From 4c72e697a012beb1b331620a19b7f6aadc9b9105 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Tue, 9 May 2023 20:36:12 +0200 Subject: [PATCH 01/22] Move Tiny properties to separate class --- .../format/tiny/Tiny1FileReader.java | 12 +++---- .../format/tiny/Tiny1FileWriter.java | 20 +++++------ .../mappingio/format/tiny/TinyProperties.java | 36 +++++++++++++++++++ 3 files changed, 49 insertions(+), 19 deletions(-) create mode 100644 src/main/java/net/fabricmc/mappingio/format/tiny/TinyProperties.java diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java index 56e2517c..8a515d86 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java @@ -134,7 +134,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws } } else { String line = reader.nextCol(); - final String prefix = "# INTERMEDIARY-COUNTER "; + final String prefix = TinyProperties.intermediaryCounter + " "; String[] parts; if (line.startsWith(prefix) @@ -143,13 +143,13 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws switch (parts[0]) { case "class": - property = nextIntermediaryClassProperty; + property = TinyProperties.NEXT_INTERMEDIARY_CLASS; break; case "field": - property = nextIntermediaryFieldProperty; + property = TinyProperties.NEXT_INTERMEDIARY_FIELD; break; case "method": - property = nextIntermediaryMethodProperty; + property = TinyProperties.NEXT_INTERMEDIARY_METHOD; break; } @@ -179,8 +179,4 @@ private static void readDstNames(ColumnFileReader reader, MappedElementKind subj if (!name.isEmpty()) visitor.visitDstName(subjectKind, dstNs, name); } } - - static final String nextIntermediaryClassProperty = "next-intermediary-class"; - static final String nextIntermediaryFieldProperty = "next-intermediary-field"; - static final String nextIntermediaryMethodProperty = "next-intermediary-method"; } diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java index bcdf2406..b28f6d7e 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java @@ -60,20 +60,18 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr @Override public void visitMetadata(String key, String value) throws IOException { switch (key) { - case Tiny1FileReader.nextIntermediaryClassProperty: - case Tiny1FileReader.nextIntermediaryFieldProperty: - case Tiny1FileReader.nextIntermediaryMethodProperty: - write("# INTERMEDIARY-COUNTER "); - + case TinyProperties.NEXT_INTERMEDIARY_CLASS: + case TinyProperties.NEXT_INTERMEDIARY_FIELD: + case TinyProperties.NEXT_INTERMEDIARY_METHOD: switch (key) { - case Tiny1FileReader.nextIntermediaryClassProperty: - write("class"); + case TinyProperties.NEXT_INTERMEDIARY_CLASS: + write(TinyProperties.NEXT_INTERMEDIARY_CLASS); break; - case Tiny1FileReader.nextIntermediaryFieldProperty: - write("field"); + case TinyProperties.NEXT_INTERMEDIARY_FIELD: + write(TinyProperties.NEXT_INTERMEDIARY_FIELD); break; - case Tiny1FileReader.nextIntermediaryMethodProperty: - write("method"); + case TinyProperties.NEXT_INTERMEDIARY_METHOD: + write(TinyProperties.NEXT_INTERMEDIARY_METHOD); break; default: throw new IllegalStateException(); diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/TinyProperties.java b/src/main/java/net/fabricmc/mappingio/format/tiny/TinyProperties.java new file mode 100644 index 00000000..38051d34 --- /dev/null +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/TinyProperties.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingio.format.tiny; + +/** + * All standard properties of the Tiny format. + * Internally, trees use the lowest common denominator. + */ +public final class TinyProperties { + // Tiny v1 + static final String intermediaryCounter = "# INTERMEDIARY COUNTER"; + public static final String NEXT_INTERMEDIARY_CLASS = intermediaryCounter + " class"; + public static final String NEXT_INTERMEDIARY_FIELD = intermediaryCounter + " field"; + public static final String NEXT_INTERMEDIARY_METHOD = intermediaryCounter + " method"; + + // Tiny v2 + public static final String NEXT_INTERMEDIARY_CLASS_TINY_2 = "next-intermediary-class"; + public static final String NEXT_INTERMEDIARY_FIELD_TINY_2 = "next-intermediary-field"; + public static final String NEXT_INTERMEDIARY_METHOD_TINY_2 = "next-intermediary-method"; + public static final String MISSING_LVT_INDICES = "missing-lvt-indices"; + public static final String ESCAPED_NAMES = "escaped-names"; +} From c00c98b15ff633e9a97755d35a2b6270caad7d93 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Tue, 9 May 2023 23:40:16 +0200 Subject: [PATCH 02/22] Remove duplicate `escaped-names` property --- .../net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java | 4 ++-- .../net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java | 4 ++-- .../java/net/fabricmc/mappingio/format/tiny/Tiny2Util.java | 2 -- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java index 6381d80f..0fa25b3e 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java @@ -89,7 +89,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws if (visitHeader || firstIteration) { while (reader.nextLine(1)) { if (!visitHeader) { - if (!escapeNames && reader.nextCol(Tiny2Util.escapedNamesProperty)) { + if (!escapeNames && reader.nextCol(TinyProperties.ESCAPED_NAMES)) { escapeNames = true; } } else { @@ -97,7 +97,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws if (key == null) throw new IOException("missing property key in line "+reader.getLineNumber()); String value = reader.nextEscapedCol(); // may be missing -> null - if (key.equals(Tiny2Util.escapedNamesProperty)) { + if (key.equals(TinyProperties.ESCAPED_NAMES)) { escapeNames = true; } diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java index aee1bdc0..5a786c86 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java @@ -60,7 +60,7 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr @Override public void visitMetadata(String key, String value) throws IOException { - if (key.equals(Tiny2Util.escapedNamesProperty)) { + if (key.equals(TinyProperties.ESCAPED_NAMES)) { escapeNames = true; wroteEscapedNamesProperty = true; } @@ -80,7 +80,7 @@ public void visitMetadata(String key, String value) throws IOException { public boolean visitContent() throws IOException { if (escapeNames && !wroteEscapedNamesProperty) { write("\t"); - write(Tiny2Util.escapedNamesProperty); + write(TinyProperties.ESCAPED_NAMES); writeLn(); } diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2Util.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2Util.java index 68bee840..341d297d 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2Util.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2Util.java @@ -84,6 +84,4 @@ public static String unescape(String str) { private static final String toEscape = "\\\n\r\0\t"; private static final String escaped = "\\nr0t"; - - static final String escapedNamesProperty = "escaped-names"; } From 07238f948bdebeb70c939dcea40a6f0d93527b7d Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Fri, 30 Jun 2023 18:57:19 +0200 Subject: [PATCH 03/22] Prevent instantiation of `TinyProperties` class --- .../net/fabricmc/mappingio/format/tiny/TinyProperties.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/TinyProperties.java b/src/main/java/net/fabricmc/mappingio/format/tiny/TinyProperties.java index 38051d34..659ea2ae 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/TinyProperties.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/TinyProperties.java @@ -21,6 +21,9 @@ * Internally, trees use the lowest common denominator. */ public final class TinyProperties { + private TinyProperties() { + } + // Tiny v1 static final String intermediaryCounter = "# INTERMEDIARY COUNTER"; public static final String NEXT_INTERMEDIARY_CLASS = intermediaryCounter + " class"; From 7e1f237b2903286ef1fe9eb6711e0b2c505768c8 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Fri, 15 Sep 2023 13:57:44 +0200 Subject: [PATCH 04/22] Create cross-format `StandardProperties` class - Now supports `component` intermediary counter - Removes some hardcoded values - Tiny v1 now supports reading arbitrary metadata (prefixed with `#`) --- .../mappingio/format/StandardProperties.java | 116 ++++++++++++++++++ .../mappingio/format/StandardProperty.java | 18 +++ .../format/tiny/Tiny1FileReader.java | 39 +++--- .../format/tiny/Tiny1FileWriter.java | 34 +++-- .../format/tiny/Tiny2FileReader.java | 16 ++- .../format/tiny/Tiny2FileWriter.java | 19 ++- .../mappingio/format/tiny/TinyProperties.java | 39 ------ 7 files changed, 197 insertions(+), 84 deletions(-) create mode 100644 src/main/java/net/fabricmc/mappingio/format/StandardProperties.java create mode 100644 src/main/java/net/fabricmc/mappingio/format/StandardProperty.java delete mode 100644 src/main/java/net/fabricmc/mappingio/format/tiny/TinyProperties.java diff --git a/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java new file mode 100644 index 00000000..6bf8fb41 --- /dev/null +++ b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java @@ -0,0 +1,116 @@ +package net.fabricmc.mappingio.format; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.jetbrains.annotations.ApiStatus; + +public final class StandardProperties { + private StandardProperties() { + } + + public static Set values() { + return Collections.unmodifiableSet(values); + } + + public static StandardProperty getByName(String name) { + return valuesByName.get(name); + } + + @ApiStatus.Internal + public static StandardProperty getById(String id) { + return valuesById.get(id); + } + + public static final StandardProperty NEXT_INTERMEDIARY_CLASS; + public static final StandardProperty NEXT_INTERMEDIARY_FIELD; + public static final StandardProperty NEXT_INTERMEDIARY_METHOD; + public static final StandardProperty NEXT_INTERMEDIARY_COMPONENT; + public static final StandardProperty MISSING_LVT_INDICES; + public static final StandardProperty ESCAPED_NAMES; + private static final Set values = new HashSet<>(); + private static final Map valuesByName = new HashMap<>(); + private static final Map valuesById = new HashMap<>(); + + static { + NEXT_INTERMEDIARY_CLASS = register( + "next-intermediary-class", + new HashMap() {{ + put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER class"); + put(MappingFormat.TINY_2_FILE, "next-intermediary-class"); + }}); + NEXT_INTERMEDIARY_FIELD = register( + "next-intermediary-field", + new HashMap() {{ + put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER field"); + put(MappingFormat.TINY_2_FILE, "next-intermediary-field"); + }}); + NEXT_INTERMEDIARY_METHOD = register( + "next-intermediary-method", + new HashMap() {{ + put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER method"); + put(MappingFormat.TINY_2_FILE, "next-intermediary-method"); + }}); + NEXT_INTERMEDIARY_COMPONENT = register( + "next-intermediary-component", + new HashMap() {{ + put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER component"); + put(MappingFormat.TINY_2_FILE, "next-intermediary-component"); + }}); + MISSING_LVT_INDICES = register( + "missing-lvt-indices", + new HashMap() {{ + put(MappingFormat.TINY_2_FILE, "missing-lvt-indices"); + }}); + ESCAPED_NAMES = register( + "escaped-names", + new HashMap() {{ + put(MappingFormat.TINY_2_FILE, "escaped-names"); + }}); + } + + private static StandardProperty register(String id, Map nameByFormat) { + StandardProperty ret = new StandardPropertyImpl(id, nameByFormat); + values.add(ret); + valuesById.put(id, ret); + + for (String name : nameByFormat.values()) { + valuesByName.putIfAbsent(name, ret); + } + + return ret; + } + + private static class StandardPropertyImpl implements StandardProperty { + StandardPropertyImpl(String id, Map nameByFormat) { + this.id = id; + this.nameByFormat = nameByFormat; + } + + @Override + public Set getApplicableFormats() { + return nameByFormat.keySet(); + } + + @Override + public boolean isApplicableTo(MappingFormat format) { + return nameByFormat.containsKey(format); + } + + @Override + public String getNameFor(MappingFormat format) { + return nameByFormat.get(format); + } + + @Override + public String getId() { + return id; + } + + private final String id; + private final Map nameByFormat; + } +} diff --git a/src/main/java/net/fabricmc/mappingio/format/StandardProperty.java b/src/main/java/net/fabricmc/mappingio/format/StandardProperty.java new file mode 100644 index 00000000..a1c5caae --- /dev/null +++ b/src/main/java/net/fabricmc/mappingio/format/StandardProperty.java @@ -0,0 +1,18 @@ +package net.fabricmc.mappingio.format; + +import java.util.Set; + +import org.jetbrains.annotations.ApiStatus; + +public interface StandardProperty { + Set getApplicableFormats(); + boolean isApplicableTo(MappingFormat format); + String getNameFor(MappingFormat format); + + /** + * Used internally by MappingTrees, consistency between JVM sessions + * or library versions isn't guaranteed! + */ + @ApiStatus.Internal + String getId(); +} diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java index 8a515d86..ae38982e 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java @@ -26,6 +26,9 @@ import net.fabricmc.mappingio.MappingFlag; import net.fabricmc.mappingio.MappingVisitor; import net.fabricmc.mappingio.format.ColumnFileReader; +import net.fabricmc.mappingio.format.MappingFormat; +import net.fabricmc.mappingio.format.StandardProperties; +import net.fabricmc.mappingio.format.StandardProperty; import net.fabricmc.mappingio.tree.MappingTree; import net.fabricmc.mappingio.tree.MemoryMappingTree; @@ -134,28 +137,26 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws } } else { String line = reader.nextCol(); - final String prefix = TinyProperties.intermediaryCounter + " "; - String[] parts; - - if (line.startsWith(prefix) - && (parts = line.substring(prefix.length()).split(" ")).length == 2) { - String property = null; - - switch (parts[0]) { - case "class": - property = TinyProperties.NEXT_INTERMEDIARY_CLASS; - break; - case "field": - property = TinyProperties.NEXT_INTERMEDIARY_FIELD; - break; - case "method": - property = TinyProperties.NEXT_INTERMEDIARY_METHOD; - break; + + if (line.startsWith("#") && line.length() >= 4) { // Metadata + line = line.substring(2); + String[] parts = line.split(" "); + String value = parts[parts.length - 1]; + String key = line.substring(0, line.lastIndexOf(value)); + + if (key.isEmpty()) { + String oldValue = value; + value = key; + key = oldValue; } + StandardProperty property = StandardProperties.getByName(key); + if (property != null) { - visitor.visitMetadata(property, parts[1]); + key = property.getId(); } + + visitor.visitMetadata(key, value); } } } @@ -179,4 +180,6 @@ private static void readDstNames(ColumnFileReader reader, MappedElementKind subj if (!name.isEmpty()) visitor.visitDstName(subjectKind, dstNs, name); } } + + private static final MappingFormat format = MappingFormat.TINY_FILE; } diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java index b28f6d7e..c249d4e8 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java @@ -26,6 +26,9 @@ import net.fabricmc.mappingio.MappedElementKind; import net.fabricmc.mappingio.MappingFlag; import net.fabricmc.mappingio.MappingWriter; +import net.fabricmc.mappingio.format.MappingFormat; +import net.fabricmc.mappingio.format.StandardProperties; +import net.fabricmc.mappingio.format.StandardProperty; public final class Tiny1FileWriter implements MappingWriter { public Tiny1FileWriter(Writer writer) { @@ -59,28 +62,18 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr @Override public void visitMetadata(String key, String value) throws IOException { - switch (key) { - case TinyProperties.NEXT_INTERMEDIARY_CLASS: - case TinyProperties.NEXT_INTERMEDIARY_FIELD: - case TinyProperties.NEXT_INTERMEDIARY_METHOD: - switch (key) { - case TinyProperties.NEXT_INTERMEDIARY_CLASS: - write(TinyProperties.NEXT_INTERMEDIARY_CLASS); - break; - case TinyProperties.NEXT_INTERMEDIARY_FIELD: - write(TinyProperties.NEXT_INTERMEDIARY_FIELD); - break; - case TinyProperties.NEXT_INTERMEDIARY_METHOD: - write(TinyProperties.NEXT_INTERMEDIARY_METHOD); - break; - default: - throw new IllegalStateException(); - } + StandardProperty property = StandardProperties.getById(key); - write(" "); - write(value); - writeLn(); + if (property != null) { + if (!property.isApplicableTo(format)) return; + key = property.getNameFor(format); } + + write("# "); + write(key); + write(" "); + write(value); + writeLn(); } @Override @@ -189,6 +182,7 @@ private void writeTab() throws IOException { } private static final Set flags = EnumSet.of(MappingFlag.NEEDS_SRC_FIELD_DESC, MappingFlag.NEEDS_SRC_METHOD_DESC); + private static final MappingFormat format = MappingFormat.TINY_FILE; private final Writer writer; private String classSrcName; diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java index 0fa25b3e..b4a7b184 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java @@ -25,6 +25,9 @@ import net.fabricmc.mappingio.MappingFlag; import net.fabricmc.mappingio.MappingVisitor; import net.fabricmc.mappingio.format.ColumnFileReader; +import net.fabricmc.mappingio.format.MappingFormat; +import net.fabricmc.mappingio.format.StandardProperties; +import net.fabricmc.mappingio.format.StandardProperty; public final class Tiny2FileReader { private Tiny2FileReader() { @@ -89,16 +92,21 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws if (visitHeader || firstIteration) { while (reader.nextLine(1)) { if (!visitHeader) { - if (!escapeNames && reader.nextCol(TinyProperties.ESCAPED_NAMES)) { + if (!escapeNames && reader.nextCol(StandardProperties.ESCAPED_NAMES.getNameFor(format))) { escapeNames = true; } } else { String key = reader.nextCol(); if (key == null) throw new IOException("missing property key in line "+reader.getLineNumber()); String value = reader.nextEscapedCol(); // may be missing -> null + StandardProperty property = StandardProperties.getByName(key); - if (key.equals(TinyProperties.ESCAPED_NAMES)) { - escapeNames = true; + if (property != null) { + key = property.getId(); + + if (property == StandardProperties.ESCAPED_NAMES) { + escapeNames = true; + } } visitor.visitMetadata(key, value); @@ -215,4 +223,6 @@ private static void readDstNames(ColumnFileReader reader, MappedElementKind subj if (!name.isEmpty()) visitor.visitDstName(subjectKind, dstNs, name); } } + + private static final MappingFormat format = MappingFormat.TINY_2_FILE; } diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java index 5a786c86..2a37e263 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java @@ -26,6 +26,9 @@ import net.fabricmc.mappingio.MappedElementKind; import net.fabricmc.mappingio.MappingFlag; import net.fabricmc.mappingio.MappingWriter; +import net.fabricmc.mappingio.format.MappingFormat; +import net.fabricmc.mappingio.format.StandardProperties; +import net.fabricmc.mappingio.format.StandardProperty; public final class Tiny2FileWriter implements MappingWriter { public Tiny2FileWriter(Writer writer, boolean escapeNames) { @@ -60,9 +63,16 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr @Override public void visitMetadata(String key, String value) throws IOException { - if (key.equals(TinyProperties.ESCAPED_NAMES)) { - escapeNames = true; - wroteEscapedNamesProperty = true; + StandardProperty property = StandardProperties.getById(key); + + if (property != null) { + if (!property.isApplicableTo(format)) return; + key = property.getNameFor(format); + + if (property == StandardProperties.ESCAPED_NAMES) { + escapeNames = true; + wroteEscapedNamesProperty = true; + } } writeTab(); @@ -80,7 +90,7 @@ public void visitMetadata(String key, String value) throws IOException { public boolean visitContent() throws IOException { if (escapeNames && !wroteEscapedNamesProperty) { write("\t"); - write(TinyProperties.ESCAPED_NAMES); + write(StandardProperties.ESCAPED_NAMES.getNameFor(format)); writeLn(); } @@ -201,6 +211,7 @@ private void writeTabs(int count) throws IOException { } private static final Set flags = EnumSet.of(MappingFlag.NEEDS_HEADER_METADATA, MappingFlag.NEEDS_UNIQUENESS, MappingFlag.NEEDS_SRC_FIELD_DESC, MappingFlag.NEEDS_SRC_METHOD_DESC); + private static final MappingFormat format = MappingFormat.TINY_2_FILE; private final Writer writer; private boolean escapeNames; diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/TinyProperties.java b/src/main/java/net/fabricmc/mappingio/format/tiny/TinyProperties.java deleted file mode 100644 index 659ea2ae..00000000 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/TinyProperties.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2021 FabricMC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.fabricmc.mappingio.format.tiny; - -/** - * All standard properties of the Tiny format. - * Internally, trees use the lowest common denominator. - */ -public final class TinyProperties { - private TinyProperties() { - } - - // Tiny v1 - static final String intermediaryCounter = "# INTERMEDIARY COUNTER"; - public static final String NEXT_INTERMEDIARY_CLASS = intermediaryCounter + " class"; - public static final String NEXT_INTERMEDIARY_FIELD = intermediaryCounter + " field"; - public static final String NEXT_INTERMEDIARY_METHOD = intermediaryCounter + " method"; - - // Tiny v2 - public static final String NEXT_INTERMEDIARY_CLASS_TINY_2 = "next-intermediary-class"; - public static final String NEXT_INTERMEDIARY_FIELD_TINY_2 = "next-intermediary-field"; - public static final String NEXT_INTERMEDIARY_METHOD_TINY_2 = "next-intermediary-method"; - public static final String MISSING_LVT_INDICES = "missing-lvt-indices"; - public static final String ESCAPED_NAMES = "escaped-names"; -} From 770926115d52c7e66c1f80c66fba3fe5d50411a3 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Mon, 18 Sep 2023 13:31:24 +0200 Subject: [PATCH 05/22] Fix checkstyle --- .../mappingio/format/StandardProperties.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java index 6bf8fb41..cf5497da 100644 --- a/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java +++ b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java @@ -37,37 +37,37 @@ public static StandardProperty getById(String id) { static { NEXT_INTERMEDIARY_CLASS = register( - "next-intermediary-class", - new HashMap() {{ + "next-intermediary-class", + new HashMap() {{ put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER class"); put(MappingFormat.TINY_2_FILE, "next-intermediary-class"); }}); NEXT_INTERMEDIARY_FIELD = register( - "next-intermediary-field", - new HashMap() {{ + "next-intermediary-field", + new HashMap() {{ put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER field"); put(MappingFormat.TINY_2_FILE, "next-intermediary-field"); }}); NEXT_INTERMEDIARY_METHOD = register( - "next-intermediary-method", - new HashMap() {{ + "next-intermediary-method", + new HashMap() {{ put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER method"); put(MappingFormat.TINY_2_FILE, "next-intermediary-method"); }}); NEXT_INTERMEDIARY_COMPONENT = register( - "next-intermediary-component", - new HashMap() {{ + "next-intermediary-component", + new HashMap() {{ put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER component"); put(MappingFormat.TINY_2_FILE, "next-intermediary-component"); }}); MISSING_LVT_INDICES = register( - "missing-lvt-indices", - new HashMap() {{ + "missing-lvt-indices", + new HashMap() {{ put(MappingFormat.TINY_2_FILE, "missing-lvt-indices"); }}); ESCAPED_NAMES = register( - "escaped-names", - new HashMap() {{ + "escaped-names", + new HashMap() {{ put(MappingFormat.TINY_2_FILE, "escaped-names"); }}); } From 98f04f79dc5f309902865c00d71d8fb22b6e24a2 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Wed, 20 Sep 2023 09:43:53 +0200 Subject: [PATCH 06/22] Add missing license headers --- .../mappingio/format/StandardProperties.java | 16 ++++++++++++++++ .../mappingio/format/StandardProperty.java | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java index cf5497da..221525ab 100644 --- a/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java +++ b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2023 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package net.fabricmc.mappingio.format; import java.util.Collections; diff --git a/src/main/java/net/fabricmc/mappingio/format/StandardProperty.java b/src/main/java/net/fabricmc/mappingio/format/StandardProperty.java index a1c5caae..671ea7ba 100644 --- a/src/main/java/net/fabricmc/mappingio/format/StandardProperty.java +++ b/src/main/java/net/fabricmc/mappingio/format/StandardProperty.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2023 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package net.fabricmc.mappingio.format; import java.util.Set; From 14d047d0456c20d3c84e534712d3280a06570167 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Wed, 20 Sep 2023 09:58:08 +0200 Subject: [PATCH 07/22] Fix Tiny v1 metadata detection --- .../net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java index ae38982e..77986efc 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java @@ -138,7 +138,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws } else { String line = reader.nextCol(); - if (line.startsWith("#") && line.length() >= 4) { // Metadata + if (line.startsWith("# ") && line.length() >= 3 && line.charAt(3) != ' ') { // Metadata line = line.substring(2); String[] parts = line.split(" "); String value = parts[parts.length - 1]; From 76c2a89ede2ffebf73405c313e108add8dea229e Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Wed, 20 Sep 2023 10:13:40 +0200 Subject: [PATCH 08/22] Don't read properties from non-applicable formats --- .../java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java | 1 + .../java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java index 77986efc..9d807b6d 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java @@ -153,6 +153,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws StandardProperty property = StandardProperties.getByName(key); if (property != null) { + if (!property.isApplicableTo(format)) continue; // How did it get there? key = property.getId(); } diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java index b4a7b184..7c174ea1 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java @@ -102,6 +102,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws StandardProperty property = StandardProperties.getByName(key); if (property != null) { + if (!property.isApplicableTo(format)) continue; // How did it get there? key = property.getId(); if (property == StandardProperties.ESCAPED_NAMES) { From 3348d45dd990ed998b696a1a72e5d71b97495f74 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Wed, 20 Sep 2023 21:06:19 +0200 Subject: [PATCH 09/22] Use builder for standard properties --- .../mappingio/format/StandardProperties.java | 88 ++++++++++--------- 1 file changed, 47 insertions(+), 41 deletions(-) diff --git a/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java index 221525ab..b31e65f6 100644 --- a/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java +++ b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java @@ -52,52 +52,58 @@ public static StandardProperty getById(String id) { private static final Map valuesById = new HashMap<>(); static { - NEXT_INTERMEDIARY_CLASS = register( - "next-intermediary-class", - new HashMap() {{ - put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER class"); - put(MappingFormat.TINY_2_FILE, "next-intermediary-class"); - }}); - NEXT_INTERMEDIARY_FIELD = register( - "next-intermediary-field", - new HashMap() {{ - put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER field"); - put(MappingFormat.TINY_2_FILE, "next-intermediary-field"); - }}); - NEXT_INTERMEDIARY_METHOD = register( - "next-intermediary-method", - new HashMap() {{ - put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER method"); - put(MappingFormat.TINY_2_FILE, "next-intermediary-method"); - }}); - NEXT_INTERMEDIARY_COMPONENT = register( - "next-intermediary-component", - new HashMap() {{ - put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER component"); - put(MappingFormat.TINY_2_FILE, "next-intermediary-component"); - }}); - MISSING_LVT_INDICES = register( - "missing-lvt-indices", - new HashMap() {{ - put(MappingFormat.TINY_2_FILE, "missing-lvt-indices"); - }}); - ESCAPED_NAMES = register( - "escaped-names", - new HashMap() {{ - put(MappingFormat.TINY_2_FILE, "escaped-names"); - }}); + NEXT_INTERMEDIARY_CLASS = builder("next-intermediary-class") + .add(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER class") + .add(MappingFormat.TINY_2_FILE, "next-intermediary-class") + .build(); + NEXT_INTERMEDIARY_FIELD = builder("next-intermediary-field") + .add(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER field") + .add(MappingFormat.TINY_2_FILE, "next-intermediary-field") + .build(); + NEXT_INTERMEDIARY_METHOD = builder("next-intermediary-method") + .add(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER method") + .add(MappingFormat.TINY_2_FILE, "next-intermediary-method") + .build(); + NEXT_INTERMEDIARY_COMPONENT = builder("next-intermediary-component") + .add(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER component") + .add(MappingFormat.TINY_2_FILE, "next-intermediary-component") + .build(); + MISSING_LVT_INDICES = builder("missing-lvt-indices") + .add(MappingFormat.TINY_2_FILE, "missing-lvt-indices") + .build(); + ESCAPED_NAMES = builder("escaped-names") + .add(MappingFormat.TINY_2_FILE, "escaped-names") + .build(); } - private static StandardProperty register(String id, Map nameByFormat) { - StandardProperty ret = new StandardPropertyImpl(id, nameByFormat); - values.add(ret); - valuesById.put(id, ret); + private static PropertyBuilder builder(String id) { + return new PropertyBuilder(id); + } - for (String name : nameByFormat.values()) { - valuesByName.putIfAbsent(name, ret); + private static class PropertyBuilder { + PropertyBuilder(String id) { + this.id = id; } - return ret; + PropertyBuilder add(MappingFormat format, String name) { + nameByFormat.put(format, name); + return this; + } + + StandardProperty build() { + StandardProperty ret = new StandardPropertyImpl(id, new HashMap<>(nameByFormat)); + values.add(ret); + valuesById.put(id, ret); + + for (String name : nameByFormat.values()) { + valuesByName.putIfAbsent(name, ret); + } + + return ret; + } + + private final String id; + private final Map nameByFormat = new HashMap<>(4); } private static class StandardPropertyImpl implements StandardProperty { From 2b4ead189787cc2d80146d7f28b0cc1f9f33be4f Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Sun, 24 Sep 2023 14:27:30 +0200 Subject: [PATCH 10/22] Consolidate builder functionality into `StandardPropertyImpl` --- .../mappingio/format/StandardProperties.java | 75 +++++++------------ 1 file changed, 25 insertions(+), 50 deletions(-) diff --git a/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java index b31e65f6..d5e9491c 100644 --- a/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java +++ b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java @@ -52,66 +52,41 @@ public static StandardProperty getById(String id) { private static final Map valuesById = new HashMap<>(); static { - NEXT_INTERMEDIARY_CLASS = builder("next-intermediary-class") - .add(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER class") - .add(MappingFormat.TINY_2_FILE, "next-intermediary-class") - .build(); - NEXT_INTERMEDIARY_FIELD = builder("next-intermediary-field") - .add(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER field") - .add(MappingFormat.TINY_2_FILE, "next-intermediary-field") - .build(); - NEXT_INTERMEDIARY_METHOD = builder("next-intermediary-method") - .add(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER method") - .add(MappingFormat.TINY_2_FILE, "next-intermediary-method") - .build(); - NEXT_INTERMEDIARY_COMPONENT = builder("next-intermediary-component") - .add(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER component") - .add(MappingFormat.TINY_2_FILE, "next-intermediary-component") - .build(); - MISSING_LVT_INDICES = builder("missing-lvt-indices") - .add(MappingFormat.TINY_2_FILE, "missing-lvt-indices") - .build(); - ESCAPED_NAMES = builder("escaped-names") - .add(MappingFormat.TINY_2_FILE, "escaped-names") - .build(); + NEXT_INTERMEDIARY_CLASS = register("next-intermediary-class") + .addMapping(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER class") + .addMapping(MappingFormat.TINY_2_FILE, "next-intermediary-class"); + NEXT_INTERMEDIARY_FIELD = register("next-intermediary-field") + .addMapping(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER field") + .addMapping(MappingFormat.TINY_2_FILE, "next-intermediary-field"); + NEXT_INTERMEDIARY_METHOD = register("next-intermediary-method") + .addMapping(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER method") + .addMapping(MappingFormat.TINY_2_FILE, "next-intermediary-method"); + NEXT_INTERMEDIARY_COMPONENT = register("next-intermediary-component") + .addMapping(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER component") + .addMapping(MappingFormat.TINY_2_FILE, "next-intermediary-component"); + MISSING_LVT_INDICES = register("missing-lvt-indices") + .addMapping(MappingFormat.TINY_2_FILE, "missing-lvt-indices"); + ESCAPED_NAMES = register("escaped-names") + .addMapping(MappingFormat.TINY_2_FILE, "escaped-names"); } - private static PropertyBuilder builder(String id) { - return new PropertyBuilder(id); + private static StandardPropertyImpl register(String id) { + return new StandardPropertyImpl(id); } - private static class PropertyBuilder { - PropertyBuilder(String id) { + private static class StandardPropertyImpl implements StandardProperty { + StandardPropertyImpl(String id) { this.id = id; + values.add(this); + valuesById.put(id, this); } - PropertyBuilder add(MappingFormat format, String name) { + private StandardPropertyImpl addMapping(MappingFormat format, String name) { nameByFormat.put(format, name); + valuesByName.put(name, this); return this; } - StandardProperty build() { - StandardProperty ret = new StandardPropertyImpl(id, new HashMap<>(nameByFormat)); - values.add(ret); - valuesById.put(id, ret); - - for (String name : nameByFormat.values()) { - valuesByName.putIfAbsent(name, ret); - } - - return ret; - } - - private final String id; - private final Map nameByFormat = new HashMap<>(4); - } - - private static class StandardPropertyImpl implements StandardProperty { - StandardPropertyImpl(String id, Map nameByFormat) { - this.id = id; - this.nameByFormat = nameByFormat; - } - @Override public Set getApplicableFormats() { return nameByFormat.keySet(); @@ -133,6 +108,6 @@ public String getId() { } private final String id; - private final Map nameByFormat; + private final Map nameByFormat = new HashMap<>(4); } } From 426bfb02b0e0a34271f8df320fa76a4d9db8f468 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Tue, 9 May 2023 23:26:26 +0200 Subject: [PATCH 11/22] Properly handle multiple metadata entries with same key --- .../mappingio/FlatMappingVisitor.java | 2 +- .../fabricmc/mappingio/MappingVisitor.java | 2 +- .../adapter/FlatAsRegularMappingVisitor.java | 4 +- .../adapter/ForwardingMappingVisitor.java | 4 +- .../mappingio/adapter/MappingNsCompleter.java | 4 +- .../adapter/MappingSourceNsSwitch.java | 4 +- .../adapter/RegularAsFlatMappingVisitor.java | 4 +- .../format/tiny/Tiny1FileReader.java | 2 +- .../format/tiny/Tiny1FileWriter.java | 2 +- .../format/tiny/Tiny2FileReader.java | 2 +- .../format/tiny/Tiny2FileWriter.java | 2 +- .../fabricmc/mappingio/tree/MappingTree.java | 4 +- .../mappingio/tree/MappingTreeView.java | 2 +- .../mappingio/tree/MemoryMappingTree.java | 95 ++++++++++++------- 14 files changed, 81 insertions(+), 52 deletions(-) diff --git a/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java index 056020ed..017c1f18 100644 --- a/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java @@ -45,7 +45,7 @@ default boolean visitHeader() throws IOException { void visitNamespaces(String srcNamespace, List dstNamespaces) throws IOException; - default void visitMetadata(String key, String value) throws IOException { } + default void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { } /** * Determine whether the mapping content (classes and anything below, metadata if not part of the header) should be visited. diff --git a/src/main/java/net/fabricmc/mappingio/MappingVisitor.java b/src/main/java/net/fabricmc/mappingio/MappingVisitor.java index 5c2455ce..d21747a5 100644 --- a/src/main/java/net/fabricmc/mappingio/MappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/MappingVisitor.java @@ -69,7 +69,7 @@ default boolean visitHeader() throws IOException { void visitNamespaces(String srcNamespace, List dstNamespaces) throws IOException; - default void visitMetadata(String key, String value) throws IOException { } + default void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { } /** * Determine whether the mapping content (classes and anything below, metadata if not part of the header) should be visited. diff --git a/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java index 34da310f..adbd91c6 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java @@ -65,8 +65,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value) throws IOException { - next.visitMetadata(key, value); + public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { + next.visitMetadata(key, value, overrideExisting); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java index 71d9574f..90ba14da 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java @@ -53,8 +53,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value) throws IOException { - next.visitMetadata(key, value); + public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { + next.visitMetadata(key, value, overrideExisting); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/adapter/MappingNsCompleter.java b/src/main/java/net/fabricmc/mappingio/adapter/MappingNsCompleter.java index fb3fb326..a3162c1a 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/MappingNsCompleter.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/MappingNsCompleter.java @@ -87,8 +87,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value) throws IOException { - if (relayHeaderOrMetadata) next.visitMetadata(key, value); + public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { + if (relayHeaderOrMetadata) next.visitMetadata(key, value, overrideExisting); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java b/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java index de52a900..8b560738 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java @@ -127,8 +127,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value) throws IOException { - if (classMapReady && relayHeaderOrMetadata) next.visitMetadata(key, value); + public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { + if (classMapReady && relayHeaderOrMetadata) next.visitMetadata(key, value, overrideExisting); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java index 2c6408e8..3af70827 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java @@ -59,8 +59,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value) throws IOException { - next.visitMetadata(key, value); + public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { + next.visitMetadata(key, value, overrideExisting); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java index 9d807b6d..7bff7401 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java @@ -157,7 +157,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws key = property.getId(); } - visitor.visitMetadata(key, value); + visitor.visitMetadata(key, value, true); } } } diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java index c249d4e8..55d690ea 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java @@ -61,7 +61,7 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value) throws IOException { + public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { StandardProperty property = StandardProperties.getById(key); if (property != null) { diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java index 7c174ea1..8b6a5d1e 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java @@ -110,7 +110,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws } } - visitor.visitMetadata(key, value); + visitor.visitMetadata(key, value, true); } } } diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java index 2a37e263..19a22f3a 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java @@ -62,7 +62,7 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value) throws IOException { + public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { StandardProperty property = StandardProperties.getById(key); if (property != null) { diff --git a/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java b/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java index b99d749b..f1d8bfda 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java @@ -23,8 +23,8 @@ public interface MappingTree extends MappingTreeView { String setSrcNamespace(String namespace); List setDstNamespaces(List namespaces); - void addMetadata(String key, String value); - String removeMetadata(String key); + void addMetadata(String key, String value, boolean overrideExisting); + boolean removeMetadata(String key); @Override Collection getClasses(); diff --git a/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java b/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java index 3de70989..365bfaf6 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java @@ -58,7 +58,7 @@ default String getNamespaceName(int id) { } Collection> getMetadata(); - String getMetadata(String key); + Collection getMetadata(String key); Collection getClasses(); ClassMappingView getClass(String srcName); diff --git a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java index 9956cce0..9cb86f31 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java @@ -30,6 +30,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; import net.fabricmc.mappingio.MappedElementKind; import net.fabricmc.mappingio.MappingFlag; @@ -44,21 +45,12 @@ public MemoryMappingTree(boolean indexByDstNames) { this.indexByDstNames = indexByDstNames; } - public MemoryMappingTree(MappingTree src) { + public MemoryMappingTree(MappingTree src) throws IOException { if (src instanceof MemoryMappingTree) { indexByDstNames = ((MemoryMappingTree) src).indexByDstNames; } - setSrcNamespace(src.getSrcNamespace()); - setDstNamespaces(src.getDstNamespaces()); - - for (Map.Entry entry : src.getMetadata()) { - addMetadata(entry.getKey(), entry.getValue()); - } - - for (ClassMapping cls : src.getClasses()) { - addClass(cls); - } + src.accept(this); } public void setIndexByDstNames(boolean indexByDstNames) { @@ -205,37 +197,45 @@ private void updateDstNames(int[] nameMap) { } @Override - public Collection> getMetadata() { - return metadata; + public List> getMetadata() { + return Collections.unmodifiableList(metadata.stream() + .map(entry -> new AbstractMap.SimpleEntry<>(entry.key, entry.value)) + .collect(Collectors.toList())); } @Override - public String getMetadata(String key) { - for (Map.Entry entry : metadata) { - if (entry.getKey().equals(key)) return entry.getValue(); - } - - return null; + public List getMetadata(String key) { + return Collections.unmodifiableList(metadata.stream() + .filter(entry -> entry.key.equals(key)) + .map(entry -> entry.value) + .collect(Collectors.toList())); } @Override - public void addMetadata(String key, String value) { - metadata.add(new AbstractMap.SimpleEntry<>(key, value)); + public void addMetadata(String key, String value, boolean overrideExisting) { + MetadataEntry entry = new MetadataEntry(key, value, overrideExisting); + + if (overrideExisting) { + removeMetadata(key); + } + + metadata.add(entry); } @Override - public String removeMetadata(String key) { - for (Iterator> it = metadata.iterator(); it.hasNext(); ) { - Map.Entry entry = it.next(); + public boolean removeMetadata(String key) { + boolean removedAny = false; - if (entry.getKey().equals(key)) { - it.remove(); + for (Iterator it = metadata.iterator(); it.hasNext(); ) { + MetadataEntry entry = it.next(); - return entry.getValue(); + if (entry.key.equals(key)) { + it.remove(); + removedAny = true; } } - return null; + return removedAny; } @Override @@ -304,8 +304,8 @@ public void accept(MappingVisitor visitor, VisitOrder order) throws IOException if (visitor.visitHeader()) { visitor.visitNamespaces(srcNamespace, dstNamespaces); - for (Map.Entry entry : metadata) { - visitor.visitMetadata(entry.getKey(), entry.getValue()); + for (MetadataEntry entry : metadata) { + visitor.visitMetadata(entry.key, entry.value, entry.overrideExisting); } } @@ -390,8 +390,14 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) { } @Override - public void visitMetadata(String key, String value) { - this.metadata.add(new AbstractMap.SimpleEntry<>(key, value)); + public void visitMetadata(String key, String value, boolean overrideExisting) { + MetadataEntry entry = new MetadataEntry(key, value, overrideExisting); + + if (overrideExisting) { + removeMetadata(key); + } + + metadata.add(entry); } @Override @@ -1699,6 +1705,29 @@ public String toString() { private final int hash; } + static final class MetadataEntry { + MetadataEntry(String key, String value, boolean enforceUniqueness) { + this.key = key; + this.value = value; + this.overrideExisting = enforceUniqueness; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof MetadataEntry)) { + return false; + } + + MetadataEntry entry = (MetadataEntry) other; + + return this.key.equals(entry.key) && this.value.equals(entry.value); + } + + final String key; + final String value; + final boolean overrideExisting; + } + static final class GlobalMemberKey { GlobalMemberKey(ClassEntry owner, String name, String desc, boolean isField) { this.owner = owner; @@ -1739,7 +1768,7 @@ public String toString() { private boolean indexByDstNames; private String srcNamespace; private List dstNamespaces = Collections.emptyList(); - private final List> metadata = new ArrayList<>(); + private final List metadata = new ArrayList<>(); private final Map classesBySrcName = new LinkedHashMap<>(); private Map[] classesByDstNames; From 1bc07fb5d959ed3296d9cacd6b772e7bac5905c4 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Sun, 17 Sep 2023 19:51:15 +0200 Subject: [PATCH 12/22] Fix `MetadataEntry`'s `equals` and `hashCode` methods --- .../net/fabricmc/mappingio/tree/MemoryMappingTree.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java index 9cb86f31..35c69ccd 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java @@ -1714,6 +1714,8 @@ static final class MetadataEntry { @Override public boolean equals(Object other) { + if (other == this) return true; + if (!(other instanceof MetadataEntry)) { return false; } @@ -1723,6 +1725,11 @@ public boolean equals(Object other) { return this.key.equals(entry.key) && this.value.equals(entry.value); } + @Override + public int hashCode() { + return key.hashCode() | value.hashCode(); + } + final String key; final String value; final boolean overrideExisting; From d6f7a4dc6d313beb2d28e529f053ac7cbc181a13 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Mon, 18 Sep 2023 13:16:44 +0200 Subject: [PATCH 13/22] Always override existing metadata entries, use Map under the hood --- .../mappingio/FlatMappingVisitor.java | 2 +- .../fabricmc/mappingio/MappingVisitor.java | 2 +- .../adapter/FlatAsRegularMappingVisitor.java | 4 +- .../adapter/ForwardingMappingVisitor.java | 4 +- .../mappingio/adapter/MappingNsCompleter.java | 4 +- .../adapter/MappingSourceNsSwitch.java | 4 +- .../adapter/RegularAsFlatMappingVisitor.java | 4 +- .../format/tiny/Tiny1FileReader.java | 2 +- .../format/tiny/Tiny1FileWriter.java | 2 +- .../format/tiny/Tiny2FileReader.java | 2 +- .../format/tiny/Tiny2FileWriter.java | 2 +- .../fabricmc/mappingio/tree/MappingTree.java | 4 +- .../mappingio/tree/MappingTreeView.java | 2 +- .../mappingio/tree/MemoryMappingTree.java | 97 +++++-------------- 14 files changed, 43 insertions(+), 92 deletions(-) diff --git a/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java index 017c1f18..056020ed 100644 --- a/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java @@ -45,7 +45,7 @@ default boolean visitHeader() throws IOException { void visitNamespaces(String srcNamespace, List dstNamespaces) throws IOException; - default void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { } + default void visitMetadata(String key, String value) throws IOException { } /** * Determine whether the mapping content (classes and anything below, metadata if not part of the header) should be visited. diff --git a/src/main/java/net/fabricmc/mappingio/MappingVisitor.java b/src/main/java/net/fabricmc/mappingio/MappingVisitor.java index d21747a5..5c2455ce 100644 --- a/src/main/java/net/fabricmc/mappingio/MappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/MappingVisitor.java @@ -69,7 +69,7 @@ default boolean visitHeader() throws IOException { void visitNamespaces(String srcNamespace, List dstNamespaces) throws IOException; - default void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { } + default void visitMetadata(String key, String value) throws IOException { } /** * Determine whether the mapping content (classes and anything below, metadata if not part of the header) should be visited. diff --git a/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java index adbd91c6..34da310f 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java @@ -65,8 +65,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { - next.visitMetadata(key, value, overrideExisting); + public void visitMetadata(String key, String value) throws IOException { + next.visitMetadata(key, value); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java index 90ba14da..71d9574f 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java @@ -53,8 +53,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { - next.visitMetadata(key, value, overrideExisting); + public void visitMetadata(String key, String value) throws IOException { + next.visitMetadata(key, value); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/adapter/MappingNsCompleter.java b/src/main/java/net/fabricmc/mappingio/adapter/MappingNsCompleter.java index a3162c1a..fb3fb326 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/MappingNsCompleter.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/MappingNsCompleter.java @@ -87,8 +87,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { - if (relayHeaderOrMetadata) next.visitMetadata(key, value, overrideExisting); + public void visitMetadata(String key, String value) throws IOException { + if (relayHeaderOrMetadata) next.visitMetadata(key, value); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java b/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java index 8b560738..de52a900 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java @@ -127,8 +127,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { - if (classMapReady && relayHeaderOrMetadata) next.visitMetadata(key, value, overrideExisting); + public void visitMetadata(String key, String value) throws IOException { + if (classMapReady && relayHeaderOrMetadata) next.visitMetadata(key, value); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java index 3af70827..2c6408e8 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java @@ -59,8 +59,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { - next.visitMetadata(key, value, overrideExisting); + public void visitMetadata(String key, String value) throws IOException { + next.visitMetadata(key, value); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java index 7bff7401..9d807b6d 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java @@ -157,7 +157,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws key = property.getId(); } - visitor.visitMetadata(key, value, true); + visitor.visitMetadata(key, value); } } } diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java index 55d690ea..c249d4e8 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java @@ -61,7 +61,7 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { + public void visitMetadata(String key, String value) throws IOException { StandardProperty property = StandardProperties.getById(key); if (property != null) { diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java index 8b6a5d1e..7c174ea1 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java @@ -110,7 +110,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws } } - visitor.visitMetadata(key, value, true); + visitor.visitMetadata(key, value); } } } diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java index 19a22f3a..2a37e263 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java @@ -62,7 +62,7 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { + public void visitMetadata(String key, String value) throws IOException { StandardProperty property = StandardProperties.getById(key); if (property != null) { diff --git a/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java b/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java index f1d8bfda..b99d749b 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java @@ -23,8 +23,8 @@ public interface MappingTree extends MappingTreeView { String setSrcNamespace(String namespace); List setDstNamespaces(List namespaces); - void addMetadata(String key, String value, boolean overrideExisting); - boolean removeMetadata(String key); + void addMetadata(String key, String value); + String removeMetadata(String key); @Override Collection getClasses(); diff --git a/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java b/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java index 365bfaf6..3de70989 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java @@ -58,7 +58,7 @@ default String getNamespaceName(int id) { } Collection> getMetadata(); - Collection getMetadata(String key); + String getMetadata(String key); Collection getClasses(); ClassMappingView getClass(String srcName); diff --git a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java index 35c69ccd..b471ecc1 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java @@ -45,12 +45,21 @@ public MemoryMappingTree(boolean indexByDstNames) { this.indexByDstNames = indexByDstNames; } - public MemoryMappingTree(MappingTree src) throws IOException { + public MemoryMappingTree(MappingTree src) { if (src instanceof MemoryMappingTree) { indexByDstNames = ((MemoryMappingTree) src).indexByDstNames; } - src.accept(this); + setSrcNamespace(src.getSrcNamespace()); + setDstNamespaces(src.getDstNamespaces()); + + for (Map.Entry entry : src.getMetadata()) { + addMetadata(entry.getKey(), entry.getValue()); + } + + for (ClassMapping cls : src.getClasses()) { + addClass(cls); + } } public void setIndexByDstNames(boolean indexByDstNames) { @@ -197,45 +206,23 @@ private void updateDstNames(int[] nameMap) { } @Override - public List> getMetadata() { - return Collections.unmodifiableList(metadata.stream() - .map(entry -> new AbstractMap.SimpleEntry<>(entry.key, entry.value)) - .collect(Collectors.toList())); + public Collection> getMetadata() { + return Collections.unmodifiableSet(metadata.entrySet()); } @Override - public List getMetadata(String key) { - return Collections.unmodifiableList(metadata.stream() - .filter(entry -> entry.key.equals(key)) - .map(entry -> entry.value) - .collect(Collectors.toList())); + public String getMetadata(String key) { + return metadata.get(key); } @Override - public void addMetadata(String key, String value, boolean overrideExisting) { - MetadataEntry entry = new MetadataEntry(key, value, overrideExisting); - - if (overrideExisting) { - removeMetadata(key); - } - - metadata.add(entry); + public void addMetadata(String key, String value) { + metadata.put(key, value); } @Override - public boolean removeMetadata(String key) { - boolean removedAny = false; - - for (Iterator it = metadata.iterator(); it.hasNext(); ) { - MetadataEntry entry = it.next(); - - if (entry.key.equals(key)) { - it.remove(); - removedAny = true; - } - } - - return removedAny; + public String removeMetadata(String key) { + return metadata.remove(key); } @Override @@ -304,8 +291,8 @@ public void accept(MappingVisitor visitor, VisitOrder order) throws IOException if (visitor.visitHeader()) { visitor.visitNamespaces(srcNamespace, dstNamespaces); - for (MetadataEntry entry : metadata) { - visitor.visitMetadata(entry.key, entry.value, entry.overrideExisting); + for (Map.Entry entry : metadata.entrySet()) { + visitor.visitMetadata(entry.getKey(), entry.getValue()); } } @@ -390,14 +377,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) { } @Override - public void visitMetadata(String key, String value, boolean overrideExisting) { - MetadataEntry entry = new MetadataEntry(key, value, overrideExisting); - - if (overrideExisting) { - removeMetadata(key); - } - - metadata.add(entry); + public void visitMetadata(String key, String value) { + addMetadata(key, value); } @Override @@ -1705,36 +1686,6 @@ public String toString() { private final int hash; } - static final class MetadataEntry { - MetadataEntry(String key, String value, boolean enforceUniqueness) { - this.key = key; - this.value = value; - this.overrideExisting = enforceUniqueness; - } - - @Override - public boolean equals(Object other) { - if (other == this) return true; - - if (!(other instanceof MetadataEntry)) { - return false; - } - - MetadataEntry entry = (MetadataEntry) other; - - return this.key.equals(entry.key) && this.value.equals(entry.value); - } - - @Override - public int hashCode() { - return key.hashCode() | value.hashCode(); - } - - final String key; - final String value; - final boolean overrideExisting; - } - static final class GlobalMemberKey { GlobalMemberKey(ClassEntry owner, String name, String desc, boolean isField) { this.owner = owner; @@ -1775,7 +1726,7 @@ public String toString() { private boolean indexByDstNames; private String srcNamespace; private List dstNamespaces = Collections.emptyList(); - private final List metadata = new ArrayList<>(); + private final Map metadata = new HashMap<>(); private final Map classesBySrcName = new LinkedHashMap<>(); private Map[] classesByDstNames; From a22d759ccf06388d31b4f2713cda67e1336aa7f9 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Mon, 18 Sep 2023 13:17:34 +0200 Subject: [PATCH 14/22] Remove unused imports --- .../java/net/fabricmc/mappingio/tree/MemoryMappingTree.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java index b471ecc1..8a77cc42 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java @@ -17,20 +17,17 @@ package net.fabricmc.mappingio.tree; import java.io.IOException; -import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.IdentityHashMap; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.stream.Collectors; import net.fabricmc.mappingio.MappedElementKind; import net.fabricmc.mappingio.MappingFlag; From 39e6781c8f23d8ffc783c735e64fba4e3454de90 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Fri, 29 Sep 2023 10:36:23 +0200 Subject: [PATCH 15/22] Revert to previous design This reverts commit 2a82c6e63285a92151a8bc07d77ea1f1d3803c52. --- .../mappingio/FlatMappingVisitor.java | 2 +- .../fabricmc/mappingio/MappingVisitor.java | 2 +- .../adapter/FlatAsRegularMappingVisitor.java | 4 +- .../adapter/ForwardingMappingVisitor.java | 4 +- .../mappingio/adapter/MappingNsCompleter.java | 4 +- .../adapter/MappingSourceNsSwitch.java | 4 +- .../adapter/RegularAsFlatMappingVisitor.java | 4 +- .../format/tiny/Tiny1FileReader.java | 2 +- .../format/tiny/Tiny1FileWriter.java | 2 +- .../format/tiny/Tiny2FileReader.java | 2 +- .../format/tiny/Tiny2FileWriter.java | 2 +- .../fabricmc/mappingio/tree/MappingTree.java | 4 +- .../mappingio/tree/MappingTreeView.java | 4 +- .../mappingio/tree/MemoryMappingTree.java | 83 +++++++++++++++---- 14 files changed, 89 insertions(+), 34 deletions(-) diff --git a/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java index 056020ed..017c1f18 100644 --- a/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java @@ -45,7 +45,7 @@ default boolean visitHeader() throws IOException { void visitNamespaces(String srcNamespace, List dstNamespaces) throws IOException; - default void visitMetadata(String key, String value) throws IOException { } + default void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { } /** * Determine whether the mapping content (classes and anything below, metadata if not part of the header) should be visited. diff --git a/src/main/java/net/fabricmc/mappingio/MappingVisitor.java b/src/main/java/net/fabricmc/mappingio/MappingVisitor.java index 5c2455ce..d21747a5 100644 --- a/src/main/java/net/fabricmc/mappingio/MappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/MappingVisitor.java @@ -69,7 +69,7 @@ default boolean visitHeader() throws IOException { void visitNamespaces(String srcNamespace, List dstNamespaces) throws IOException; - default void visitMetadata(String key, String value) throws IOException { } + default void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { } /** * Determine whether the mapping content (classes and anything below, metadata if not part of the header) should be visited. diff --git a/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java index 34da310f..adbd91c6 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java @@ -65,8 +65,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value) throws IOException { - next.visitMetadata(key, value); + public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { + next.visitMetadata(key, value, overrideExisting); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java index 71d9574f..90ba14da 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java @@ -53,8 +53,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value) throws IOException { - next.visitMetadata(key, value); + public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { + next.visitMetadata(key, value, overrideExisting); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/adapter/MappingNsCompleter.java b/src/main/java/net/fabricmc/mappingio/adapter/MappingNsCompleter.java index fb3fb326..a3162c1a 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/MappingNsCompleter.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/MappingNsCompleter.java @@ -87,8 +87,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value) throws IOException { - if (relayHeaderOrMetadata) next.visitMetadata(key, value); + public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { + if (relayHeaderOrMetadata) next.visitMetadata(key, value, overrideExisting); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java b/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java index de52a900..8b560738 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java @@ -127,8 +127,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value) throws IOException { - if (classMapReady && relayHeaderOrMetadata) next.visitMetadata(key, value); + public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { + if (classMapReady && relayHeaderOrMetadata) next.visitMetadata(key, value, overrideExisting); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java index 2c6408e8..3af70827 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java @@ -59,8 +59,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value) throws IOException { - next.visitMetadata(key, value); + public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { + next.visitMetadata(key, value, overrideExisting); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java index 9d807b6d..7bff7401 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java @@ -157,7 +157,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws key = property.getId(); } - visitor.visitMetadata(key, value); + visitor.visitMetadata(key, value, true); } } } diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java index c249d4e8..55d690ea 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java @@ -61,7 +61,7 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value) throws IOException { + public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { StandardProperty property = StandardProperties.getById(key); if (property != null) { diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java index 7c174ea1..8b6a5d1e 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java @@ -110,7 +110,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws } } - visitor.visitMetadata(key, value); + visitor.visitMetadata(key, value, true); } } } diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java index 2a37e263..19a22f3a 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java @@ -62,7 +62,7 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value) throws IOException { + public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { StandardProperty property = StandardProperties.getById(key); if (property != null) { diff --git a/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java b/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java index b99d749b..f1d8bfda 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java @@ -23,8 +23,8 @@ public interface MappingTree extends MappingTreeView { String setSrcNamespace(String namespace); List setDstNamespaces(List namespaces); - void addMetadata(String key, String value); - String removeMetadata(String key); + void addMetadata(String key, String value, boolean overrideExisting); + boolean removeMetadata(String key); @Override Collection getClasses(); diff --git a/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java b/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java index 3de70989..957aaee7 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java @@ -57,8 +57,8 @@ default String getNamespaceName(int id) { return getDstNamespaces().get(id); } - Collection> getMetadata(); - String getMetadata(String key); + List> getMetadata(); + List getMetadata(String key); Collection getClasses(); ClassMappingView getClass(String srcName); diff --git a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java index 8a77cc42..eb3efcac 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java @@ -17,17 +17,20 @@ package net.fabricmc.mappingio.tree; import java.io.IOException; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.IdentityHashMap; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; import net.fabricmc.mappingio.MappedElementKind; import net.fabricmc.mappingio.MappingFlag; @@ -51,7 +54,7 @@ public MemoryMappingTree(MappingTree src) { setDstNamespaces(src.getDstNamespaces()); for (Map.Entry entry : src.getMetadata()) { - addMetadata(entry.getKey(), entry.getValue()); + addMetadata(entry.getKey(), entry.getValue(), false); } for (ClassMapping cls : src.getClasses()) { @@ -203,23 +206,45 @@ private void updateDstNames(int[] nameMap) { } @Override - public Collection> getMetadata() { - return Collections.unmodifiableSet(metadata.entrySet()); + public List> getMetadata() { + return Collections.unmodifiableList(metadata.stream() + .map(entry -> new AbstractMap.SimpleEntry<>(entry.key, entry.value)) + .collect(Collectors.toList())); } @Override - public String getMetadata(String key) { - return metadata.get(key); + public List getMetadata(String key) { + return Collections.unmodifiableList(metadata.stream() + .filter(entry -> entry.key.equals(key)) + .map(entry -> entry.value) + .collect(Collectors.toList())); } @Override - public void addMetadata(String key, String value) { - metadata.put(key, value); + public void addMetadata(String key, String value, boolean overrideExisting) { + MetadataEntry entry = new MetadataEntry(key, value, overrideExisting); + + if (overrideExisting) { + removeMetadata(key); + } + + metadata.add(entry); } @Override - public String removeMetadata(String key) { - return metadata.remove(key); + public boolean removeMetadata(String key) { + boolean removedAny = false; + + for (Iterator it = metadata.iterator(); it.hasNext(); ) { + MetadataEntry entry = it.next(); + + if (entry.key.equals(key)) { + it.remove(); + removedAny = true; + } + } + + return removedAny; } @Override @@ -288,8 +313,8 @@ public void accept(MappingVisitor visitor, VisitOrder order) throws IOException if (visitor.visitHeader()) { visitor.visitNamespaces(srcNamespace, dstNamespaces); - for (Map.Entry entry : metadata.entrySet()) { - visitor.visitMetadata(entry.getKey(), entry.getValue()); + for (MetadataEntry entry : metadata) { + visitor.visitMetadata(entry.key, entry.value, entry.overrideExisting); } } @@ -374,8 +399,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) { } @Override - public void visitMetadata(String key, String value) { - addMetadata(key, value); + public void visitMetadata(String key, String value, boolean overrideExisting) { + addMetadata(key, value, overrideExisting); } @Override @@ -1683,6 +1708,36 @@ public String toString() { private final int hash; } + static final class MetadataEntry { + MetadataEntry(String key, String value, boolean enforceUniqueness) { + this.key = key; + this.value = value; + this.overrideExisting = enforceUniqueness; + } + + @Override + public boolean equals(Object other) { + if (other == this) return true; + + if (!(other instanceof MetadataEntry)) { + return false; + } + + MetadataEntry entry = (MetadataEntry) other; + + return this.key.equals(entry.key) && this.value.equals(entry.value); + } + + @Override + public int hashCode() { + return key.hashCode() | value.hashCode(); + } + + final String key; + final String value; + final boolean overrideExisting; + } + static final class GlobalMemberKey { GlobalMemberKey(ClassEntry owner, String name, String desc, boolean isField) { this.owner = owner; @@ -1723,7 +1778,7 @@ public String toString() { private boolean indexByDstNames; private String srcNamespace; private List dstNamespaces = Collections.emptyList(); - private final Map metadata = new HashMap<>(); + private final List metadata = new ArrayList<>(); private final Map classesBySrcName = new LinkedHashMap<>(); private Map[] classesByDstNames; From bea6a69c236015d865741bfc8fa82a16b3520a68 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Fri, 29 Sep 2023 16:24:09 +0200 Subject: [PATCH 16/22] Expose `MetadataEntry`s instead of `Map.Entry` --- .../fabricmc/mappingio/tree/MappingTree.java | 22 +++++- .../mappingio/tree/MappingTreeView.java | 16 ++++- .../mappingio/tree/MemoryMappingTree.java | 68 +++++++++---------- 3 files changed, 67 insertions(+), 39 deletions(-) diff --git a/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java b/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java index f1d8bfda..839ad030 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java @@ -23,7 +23,27 @@ public interface MappingTree extends MappingTreeView { String setSrcNamespace(String namespace); List setDstNamespaces(List namespaces); - void addMetadata(String key, String value, boolean overrideExisting); + /** + * @return A modifiable list of all metadata entries currently present in the tree. + * The list's order is equal to the order in which the entries have been originally added. + */ + @Override + List getMetadata(); + + /** + * @return An unmodifiable list of all metadata entries currently present + * in the tree whose key is equal to the passed one. + * The list's order is equal to the order in which the entries have been originally added. + */ + @Override + List getMetadata(String key); + + void addMetadata(MetadataEntryView entry); + + /** + * Removes all metadata entries whose key is equal to the passed one. + * @return Whether or not any entries have been removed. + */ boolean removeMetadata(String key); @Override diff --git a/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java b/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java index 957aaee7..2fd6cffa 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.util.Collection; import java.util.List; -import java.util.Map.Entry; import net.fabricmc.mappingio.MappingVisitor; @@ -57,8 +56,8 @@ default String getNamespaceName(int id) { return getDstNamespaces().get(id); } - List> getMetadata(); - List getMetadata(String key); + List getMetadata(); + List getMetadata(String key); Collection getClasses(); ClassMappingView getClass(String srcName); @@ -182,6 +181,17 @@ default String mapDesc(CharSequence desc, int start, int end, int srcNamespace, return ret.toString(); } + interface MetadataEntryView { + String getKey(); + String getValue(); + + /** + * @return Whether or not existing entries with the same key + * should get deleted once this entry gets added. + */ + boolean overridesExisting(); + } + interface ElementMappingView { MappingTreeView getTree(); diff --git a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java index eb3efcac..23358bbf 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java @@ -17,14 +17,12 @@ package net.fabricmc.mappingio.tree; import java.io.IOException; -import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.IdentityHashMap; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -53,8 +51,8 @@ public MemoryMappingTree(MappingTree src) { setSrcNamespace(src.getSrcNamespace()); setDstNamespaces(src.getDstNamespaces()); - for (Map.Entry entry : src.getMetadata()) { - addMetadata(entry.getKey(), entry.getValue(), false); + for (MetadataEntryView entry : src.getMetadata()) { + addMetadata(entry); } for (ClassMapping cls : src.getClasses()) { @@ -206,26 +204,21 @@ private void updateDstNames(int[] nameMap) { } @Override - public List> getMetadata() { - return Collections.unmodifiableList(metadata.stream() - .map(entry -> new AbstractMap.SimpleEntry<>(entry.key, entry.value)) - .collect(Collectors.toList())); + public List getMetadata() { + return metadata; } @Override - public List getMetadata(String key) { + public List getMetadata(String key) { return Collections.unmodifiableList(metadata.stream() - .filter(entry -> entry.key.equals(key)) - .map(entry -> entry.value) + .filter(entry -> entry.getKey().equals(key)) .collect(Collectors.toList())); } @Override - public void addMetadata(String key, String value, boolean overrideExisting) { - MetadataEntry entry = new MetadataEntry(key, value, overrideExisting); - - if (overrideExisting) { - removeMetadata(key); + public void addMetadata(MetadataEntryView entry) { + if (entry.overridesExisting()) { + removeMetadata(entry.getKey()); } metadata.add(entry); @@ -233,18 +226,7 @@ public void addMetadata(String key, String value, boolean overrideExisting) { @Override public boolean removeMetadata(String key) { - boolean removedAny = false; - - for (Iterator it = metadata.iterator(); it.hasNext(); ) { - MetadataEntry entry = it.next(); - - if (entry.key.equals(key)) { - it.remove(); - removedAny = true; - } - } - - return removedAny; + return metadata.removeIf(entry -> entry.getKey().equals(key)); } @Override @@ -313,8 +295,8 @@ public void accept(MappingVisitor visitor, VisitOrder order) throws IOException if (visitor.visitHeader()) { visitor.visitNamespaces(srcNamespace, dstNamespaces); - for (MetadataEntry entry : metadata) { - visitor.visitMetadata(entry.key, entry.value, entry.overrideExisting); + for (MetadataEntryView entry : metadata) { + visitor.visitMetadata(entry.getKey(), entry.getValue(), entry.overridesExisting()); } } @@ -400,7 +382,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) { @Override public void visitMetadata(String key, String value, boolean overrideExisting) { - addMetadata(key, value, overrideExisting); + MetadataEntry entry = new MetadataEntry(key, value, overrideExisting); + addMetadata(entry); } @Override @@ -1708,11 +1691,26 @@ public String toString() { private final int hash; } - static final class MetadataEntry { - MetadataEntry(String key, String value, boolean enforceUniqueness) { + static final class MetadataEntry implements MetadataEntryView { + MetadataEntry(String key, String value, boolean overrideExisting) { this.key = key; this.value = value; - this.overrideExisting = enforceUniqueness; + this.overrideExisting = overrideExisting; + } + + @Override + public String getKey() { + return key; + } + + @Override + public String getValue() { + return value; + } + + @Override + public boolean overridesExisting() { + return overrideExisting; } @Override @@ -1778,7 +1776,7 @@ public String toString() { private boolean indexByDstNames; private String srcNamespace; private List dstNamespaces = Collections.emptyList(); - private final List metadata = new ArrayList<>(); + private final List metadata = new ArrayList<>(); private final Map classesBySrcName = new LinkedHashMap<>(); private Map[] classesByDstNames; From 803986fbffed607c4983ceb5c78dcf9c7c315aa0 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Sat, 30 Sep 2023 09:09:26 +0200 Subject: [PATCH 17/22] Use `NEEDS_UNIQUENESS` flag instead of `overrideExisting` --- .../mappingio/FlatMappingVisitor.java | 2 +- .../fabricmc/mappingio/MappingVisitor.java | 2 +- .../adapter/FlatAsRegularMappingVisitor.java | 4 +- .../adapter/ForwardingMappingVisitor.java | 4 +- .../mappingio/adapter/MappingNsCompleter.java | 4 +- .../adapter/MappingSourceNsSwitch.java | 4 +- .../adapter/RegularAsFlatMappingVisitor.java | 4 +- .../format/tiny/Tiny1FileReader.java | 2 +- .../format/tiny/Tiny1FileWriter.java | 4 +- .../format/tiny/Tiny2FileReader.java | 2 +- .../format/tiny/Tiny2FileWriter.java | 2 +- .../mappingio/tree/MappingTreeView.java | 6 --- .../mappingio/tree/MemoryMappingTree.java | 41 +++++++++++-------- 13 files changed, 42 insertions(+), 39 deletions(-) diff --git a/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java index 017c1f18..056020ed 100644 --- a/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java @@ -45,7 +45,7 @@ default boolean visitHeader() throws IOException { void visitNamespaces(String srcNamespace, List dstNamespaces) throws IOException; - default void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { } + default void visitMetadata(String key, String value) throws IOException { } /** * Determine whether the mapping content (classes and anything below, metadata if not part of the header) should be visited. diff --git a/src/main/java/net/fabricmc/mappingio/MappingVisitor.java b/src/main/java/net/fabricmc/mappingio/MappingVisitor.java index d21747a5..5c2455ce 100644 --- a/src/main/java/net/fabricmc/mappingio/MappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/MappingVisitor.java @@ -69,7 +69,7 @@ default boolean visitHeader() throws IOException { void visitNamespaces(String srcNamespace, List dstNamespaces) throws IOException; - default void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { } + default void visitMetadata(String key, String value) throws IOException { } /** * Determine whether the mapping content (classes and anything below, metadata if not part of the header) should be visited. diff --git a/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java index adbd91c6..34da310f 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java @@ -65,8 +65,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { - next.visitMetadata(key, value, overrideExisting); + public void visitMetadata(String key, String value) throws IOException { + next.visitMetadata(key, value); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java index 90ba14da..71d9574f 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java @@ -53,8 +53,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { - next.visitMetadata(key, value, overrideExisting); + public void visitMetadata(String key, String value) throws IOException { + next.visitMetadata(key, value); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/adapter/MappingNsCompleter.java b/src/main/java/net/fabricmc/mappingio/adapter/MappingNsCompleter.java index a3162c1a..fb3fb326 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/MappingNsCompleter.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/MappingNsCompleter.java @@ -87,8 +87,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { - if (relayHeaderOrMetadata) next.visitMetadata(key, value, overrideExisting); + public void visitMetadata(String key, String value) throws IOException { + if (relayHeaderOrMetadata) next.visitMetadata(key, value); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java b/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java index 8b560738..de52a900 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java @@ -127,8 +127,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { - if (classMapReady && relayHeaderOrMetadata) next.visitMetadata(key, value, overrideExisting); + public void visitMetadata(String key, String value) throws IOException { + if (classMapReady && relayHeaderOrMetadata) next.visitMetadata(key, value); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java index 3af70827..2c6408e8 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java @@ -59,8 +59,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { - next.visitMetadata(key, value, overrideExisting); + public void visitMetadata(String key, String value) throws IOException { + next.visitMetadata(key, value); } @Override diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java index 7bff7401..9d807b6d 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java @@ -157,7 +157,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws key = property.getId(); } - visitor.visitMetadata(key, value, true); + visitor.visitMetadata(key, value); } } } diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java index 55d690ea..2685c033 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java @@ -61,7 +61,7 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { + public void visitMetadata(String key, String value) throws IOException { StandardProperty property = StandardProperties.getById(key); if (property != null) { @@ -181,7 +181,7 @@ private void writeTab() throws IOException { writer.write('\t'); } - private static final Set flags = EnumSet.of(MappingFlag.NEEDS_SRC_FIELD_DESC, MappingFlag.NEEDS_SRC_METHOD_DESC); + private static final Set flags = EnumSet.of(MappingFlag.NEEDS_UNIQUENESS, MappingFlag.NEEDS_SRC_FIELD_DESC, MappingFlag.NEEDS_SRC_METHOD_DESC); private static final MappingFormat format = MappingFormat.TINY_FILE; private final Writer writer; diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java index 8b6a5d1e..7c174ea1 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java @@ -110,7 +110,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws } } - visitor.visitMetadata(key, value, true); + visitor.visitMetadata(key, value); } } } diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java index 19a22f3a..2a37e263 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java @@ -62,7 +62,7 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr } @Override - public void visitMetadata(String key, String value, boolean overrideExisting) throws IOException { + public void visitMetadata(String key, String value) throws IOException { StandardProperty property = StandardProperties.getById(key); if (property != null) { diff --git a/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java b/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java index 2fd6cffa..154cf4d0 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java @@ -184,12 +184,6 @@ default String mapDesc(CharSequence desc, int start, int end, int srcNamespace, interface MetadataEntryView { String getKey(); String getValue(); - - /** - * @return Whether or not existing entries with the same key - * should get deleted once this entry gets added. - */ - boolean overridesExisting(); } interface ElementMappingView { diff --git a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java index 23358bbf..8c2fdb96 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java @@ -22,8 +22,10 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.IdentityHashMap; import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; @@ -217,10 +219,6 @@ public List getMetadata(String key) { @Override public void addMetadata(MetadataEntryView entry) { - if (entry.overridesExisting()) { - removeMetadata(entry.getKey()); - } - metadata.add(entry); } @@ -292,11 +290,29 @@ public ClassMapping removeClass(String srcName) { @Override public void accept(MappingVisitor visitor, VisitOrder order) throws IOException { do { + boolean needsUniqueness = visitor.getFlags().contains(MappingFlag.NEEDS_UNIQUENESS); + if (visitor.visitHeader()) { visitor.visitNamespaces(srcNamespace, dstNamespaces); + List metadataToVisit = metadata; + + if (needsUniqueness) { + metadataToVisit = new LinkedList<>(); + Set addedKeys = new HashSet<>(); + + // Iterate last-to-first to construct a list of each key's latest occurrence. + for (int i = metadata.size() - 1; i >= 0; i--) { + MetadataEntryView entry = metadata.get(i); + + if (!addedKeys.contains(entry.getKey())) { + addedKeys.add(entry.getKey()); + metadataToVisit.add(0, entry); + } + } + } - for (MetadataEntryView entry : metadata) { - visitor.visitMetadata(entry.getKey(), entry.getValue(), entry.overridesExisting()); + for (MetadataEntryView entry : metadataToVisit) { + visitor.visitMetadata(entry.getKey(), entry.getValue()); } } @@ -381,8 +397,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) { } @Override - public void visitMetadata(String key, String value, boolean overrideExisting) { - MetadataEntry entry = new MetadataEntry(key, value, overrideExisting); + public void visitMetadata(String key, String value) { + MetadataEntry entry = new MetadataEntry(key, value); addMetadata(entry); } @@ -1692,10 +1708,9 @@ public String toString() { } static final class MetadataEntry implements MetadataEntryView { - MetadataEntry(String key, String value, boolean overrideExisting) { + MetadataEntry(String key, String value) { this.key = key; this.value = value; - this.overrideExisting = overrideExisting; } @Override @@ -1708,11 +1723,6 @@ public String getValue() { return value; } - @Override - public boolean overridesExisting() { - return overrideExisting; - } - @Override public boolean equals(Object other) { if (other == this) return true; @@ -1733,7 +1743,6 @@ public int hashCode() { final String key; final String value; - final boolean overrideExisting; } static final class GlobalMemberKey { From 2b2b6a25370d2f57698c94bdabd663faaeb0f211 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Sat, 30 Sep 2023 09:31:59 +0200 Subject: [PATCH 18/22] Add new placeholder `MetadataEntry` interface --- .../fabricmc/mappingio/tree/MappingTree.java | 9 ++++--- .../mappingio/tree/MemoryMappingTree.java | 26 +++++++++---------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java b/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java index 839ad030..d096bae6 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java @@ -28,7 +28,7 @@ public interface MappingTree extends MappingTreeView { * The list's order is equal to the order in which the entries have been originally added. */ @Override - List getMetadata(); + List getMetadata(); /** * @return An unmodifiable list of all metadata entries currently present @@ -36,9 +36,9 @@ public interface MappingTree extends MappingTreeView { * The list's order is equal to the order in which the entries have been originally added. */ @Override - List getMetadata(String key); + List getMetadata(String key); - void addMetadata(MetadataEntryView entry); + void addMetadata(MetadataEntry entry); /** * Removes all metadata entries whose key is equal to the passed one. @@ -79,6 +79,9 @@ default MethodMapping getMethod(String ownerName, String name, String desc, int return (MethodMapping) MappingTreeView.super.getMethod(ownerName, name, desc, namespace); } + interface MetadataEntry extends MetadataEntryView { + } + interface ElementMapping extends ElementMappingView { @Override MappingTree getTree(); diff --git a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java index 8c2fdb96..c1529a66 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java @@ -53,7 +53,7 @@ public MemoryMappingTree(MappingTree src) { setSrcNamespace(src.getSrcNamespace()); setDstNamespaces(src.getDstNamespaces()); - for (MetadataEntryView entry : src.getMetadata()) { + for (MetadataEntry entry : src.getMetadata()) { addMetadata(entry); } @@ -206,19 +206,19 @@ private void updateDstNames(int[] nameMap) { } @Override - public List getMetadata() { + public List getMetadata() { return metadata; } @Override - public List getMetadata(String key) { + public List getMetadata(String key) { return Collections.unmodifiableList(metadata.stream() .filter(entry -> entry.getKey().equals(key)) .collect(Collectors.toList())); } @Override - public void addMetadata(MetadataEntryView entry) { + public void addMetadata(MetadataEntry entry) { metadata.add(entry); } @@ -294,7 +294,7 @@ public void accept(MappingVisitor visitor, VisitOrder order) throws IOException if (visitor.visitHeader()) { visitor.visitNamespaces(srcNamespace, dstNamespaces); - List metadataToVisit = metadata; + List metadataToVisit = metadata; if (needsUniqueness) { metadataToVisit = new LinkedList<>(); @@ -302,7 +302,7 @@ public void accept(MappingVisitor visitor, VisitOrder order) throws IOException // Iterate last-to-first to construct a list of each key's latest occurrence. for (int i = metadata.size() - 1; i >= 0; i--) { - MetadataEntryView entry = metadata.get(i); + MetadataEntry entry = metadata.get(i); if (!addedKeys.contains(entry.getKey())) { addedKeys.add(entry.getKey()); @@ -311,7 +311,7 @@ public void accept(MappingVisitor visitor, VisitOrder order) throws IOException } } - for (MetadataEntryView entry : metadataToVisit) { + for (MetadataEntry entry : metadataToVisit) { visitor.visitMetadata(entry.getKey(), entry.getValue()); } } @@ -398,7 +398,7 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) { @Override public void visitMetadata(String key, String value) { - MetadataEntry entry = new MetadataEntry(key, value); + MetadataEntryImpl entry = new MetadataEntryImpl(key, value); addMetadata(entry); } @@ -1707,8 +1707,8 @@ public String toString() { private final int hash; } - static final class MetadataEntry implements MetadataEntryView { - MetadataEntry(String key, String value) { + static final class MetadataEntryImpl implements MetadataEntry { + MetadataEntryImpl(String key, String value) { this.key = key; this.value = value; } @@ -1727,11 +1727,11 @@ public String getValue() { public boolean equals(Object other) { if (other == this) return true; - if (!(other instanceof MetadataEntry)) { + if (!(other instanceof MetadataEntryImpl)) { return false; } - MetadataEntry entry = (MetadataEntry) other; + MetadataEntryImpl entry = (MetadataEntryImpl) other; return this.key.equals(entry.key) && this.value.equals(entry.value); } @@ -1785,7 +1785,7 @@ public String toString() { private boolean indexByDstNames; private String srcNamespace; private List dstNamespaces = Collections.emptyList(); - private final List metadata = new ArrayList<>(); + private final List metadata = new ArrayList<>(); private final Map classesBySrcName = new LinkedHashMap<>(); private Map[] classesByDstNames; From a7d1bf7e3c96912fb086187c90763e9feb64d207 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Sat, 30 Sep 2023 15:40:15 +0200 Subject: [PATCH 19/22] Add tests --- .../net/fabricmc/mappingio/MetadataTest.java | 85 +++++++++++++++++++ .../fabricmc/mappingio/NopMappingVisitor.java | 80 +++++++++++++++++ .../net/fabricmc/mappingio/TestHelper.java | 33 +++++++ .../net/fabricmc/mappingio/WriteTest.java | 29 +------ 4 files changed, 199 insertions(+), 28 deletions(-) create mode 100644 src/test/java/net/fabricmc/mappingio/MetadataTest.java create mode 100644 src/test/java/net/fabricmc/mappingio/NopMappingVisitor.java diff --git a/src/test/java/net/fabricmc/mappingio/MetadataTest.java b/src/test/java/net/fabricmc/mappingio/MetadataTest.java new file mode 100644 index 00000000..aa9e7008 --- /dev/null +++ b/src/test/java/net/fabricmc/mappingio/MetadataTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingio; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import net.fabricmc.mappingio.tree.VisitableMappingTree; + +public class MetadataTest { + private static final Random random = new Random(); + private static final List keys = new ArrayList<>(); + private static final List values = new ArrayList<>(); + private static VisitableMappingTree tree; + + @BeforeAll + public static void setup() throws Exception { + tree = TestHelper.createTestTree(); + + for (int i = 0; i < 40; i++) { + String key = "key" + random.nextInt(3); + String value = "position" + i; + + keys.add(key); + values.add(value); + tree.visitMetadata(key, value); + } + } + + @Test + public void testOrder() throws Exception { + tree.accept(new NopMappingVisitor(true) { + @Override + public void visitMetadata(String key, String value) { + assertEquals(key, keys.get(visitCount)); + assertEquals(value, values.get(visitCount)); + visitCount++; + } + + int visitCount; + }); + } + + @Test + public void testUniqueness() throws Exception { + tree.accept(new NopMappingVisitor(true) { + @Override + public Set getFlags() { + return EnumSet.of(MappingFlag.NEEDS_UNIQUENESS); + } + + @Override + public void visitMetadata(String key, String value) { + assertFalse(visitedKeys.contains(key)); + visitedKeys.add(key); + } + + Set visitedKeys = new HashSet<>(); + }); + } +} diff --git a/src/test/java/net/fabricmc/mappingio/NopMappingVisitor.java b/src/test/java/net/fabricmc/mappingio/NopMappingVisitor.java new file mode 100644 index 00000000..81d37607 --- /dev/null +++ b/src/test/java/net/fabricmc/mappingio/NopMappingVisitor.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2023 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingio; + +import java.io.IOException; +import java.util.List; + +public class NopMappingVisitor implements MappingVisitor { + NopMappingVisitor(boolean visitSubVisitors) { + this.visitSubVisitors = visitSubVisitors; + } + + @Override + public boolean visitHeader() throws IOException { + return visitSubVisitors; + } + + @Override + public void visitNamespaces(String srcNamespace, List dstNamespaces) throws IOException { + } + + @Override + public boolean visitContent() throws IOException { + return visitSubVisitors; + } + + @Override + public boolean visitClass(String srcName) throws IOException { + return visitSubVisitors; + } + + @Override + public boolean visitField(String srcName, String srcDesc) throws IOException { + return visitSubVisitors; + } + + @Override + public boolean visitMethod(String srcName, String srcDesc) throws IOException { + return visitSubVisitors; + } + + @Override + public boolean visitMethodArg(int argPosition, int lvIndex, String srcName) throws IOException { + return visitSubVisitors; + } + + @Override + public boolean visitMethodVar(int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcName) throws IOException { + return visitSubVisitors; + } + + @Override + public void visitDstName(MappedElementKind targetKind, int namespace, String name) throws IOException { + } + + @Override + public boolean visitElementContent(MappedElementKind targetKind) throws IOException { + return visitSubVisitors; + } + + @Override + public void visitComment(MappedElementKind targetKind, String comment) throws IOException { + } + + protected final boolean visitSubVisitors; +} diff --git a/src/test/java/net/fabricmc/mappingio/TestHelper.java b/src/test/java/net/fabricmc/mappingio/TestHelper.java index 0cf4ea4d..195a02e9 100644 --- a/src/test/java/net/fabricmc/mappingio/TestHelper.java +++ b/src/test/java/net/fabricmc/mappingio/TestHelper.java @@ -20,9 +20,11 @@ import java.net.URISyntaxException; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; import net.fabricmc.mappingio.format.MappingFormat; import net.fabricmc.mappingio.tree.MappingTree; +import net.fabricmc.mappingio.tree.MemoryMappingTree; public final class TestHelper { public static Path getResource(String slashPrefixedResourcePath) { @@ -33,6 +35,37 @@ public static Path getResource(String slashPrefixedResourcePath) { } } + public static MemoryMappingTree createTestTree() { + MemoryMappingTree tree = new MemoryMappingTree(); + tree.visitNamespaces(MappingUtil.NS_SOURCE_FALLBACK, Arrays.asList(MappingUtil.NS_TARGET_FALLBACK)); + + tree.visitClass("class_1"); + tree.visitDstName(MappedElementKind.CLASS, 0, "RenamedClass1"); + + tree.visitField("field_1", "I"); + tree.visitDstName(MappedElementKind.FIELD, 0, "renamedField"); + + tree.visitMethod("method_1", "(F)I"); + tree.visitDstName(MappedElementKind.METHOD, 0, "renamedMethod"); + + tree.visitMethodArg(0, 0, "param_1"); + tree.visitDstName(MappedElementKind.METHOD_ARG, 0, "renamedParameter"); + + tree.visitMethodVar(0, 0, 0, 0, "param_1"); + tree.visitDstName(MappedElementKind.METHOD_VAR, 0, "renamedVariable"); + + tree.visitClass("class_1$class_2"); + tree.visitDstName(MappedElementKind.CLASS, 0, "RenamedClass1$RenamedInnerClass"); + + tree.visitField("field_1", "I"); + tree.visitDstName(MappedElementKind.FIELD, 0, "renamedField2"); + + tree.visitClass("class_3"); + tree.visitDstName(MappedElementKind.CLASS, 0, "RenamedClass2"); + + return tree; + } + public static void writeToDir(MappingTree tree, MappingFormat format, Path dir) throws IOException { MappingWriter writer = MappingWriter.create(dir.resolve(format.name() + "." + format.fileExt), format); tree.accept(writer); diff --git a/src/test/java/net/fabricmc/mappingio/WriteTest.java b/src/test/java/net/fabricmc/mappingio/WriteTest.java index 19bacaca..9de0a4b0 100644 --- a/src/test/java/net/fabricmc/mappingio/WriteTest.java +++ b/src/test/java/net/fabricmc/mappingio/WriteTest.java @@ -17,14 +17,12 @@ package net.fabricmc.mappingio; import java.nio.file.Path; -import java.util.Arrays; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import net.fabricmc.mappingio.format.MappingFormat; -import net.fabricmc.mappingio.tree.MemoryMappingTree; import net.fabricmc.mappingio.tree.VisitableMappingTree; public class WriteTest { @@ -34,32 +32,7 @@ public class WriteTest { @BeforeAll public static void setup() throws Exception { - tree = new MemoryMappingTree(); - tree.visitNamespaces(MappingUtil.NS_SOURCE_FALLBACK, Arrays.asList(MappingUtil.NS_TARGET_FALLBACK)); - - tree.visitClass("class_1"); - tree.visitDstName(MappedElementKind.CLASS, 0, "RenamedClass1"); - - tree.visitField("field_1", "I"); - tree.visitDstName(MappedElementKind.FIELD, 0, "renamedField"); - - tree.visitMethod("method_1", "(F)I"); - tree.visitDstName(MappedElementKind.METHOD, 0, "renamedMethod"); - - tree.visitMethodArg(0, 0, "param_1"); - tree.visitDstName(MappedElementKind.METHOD_ARG, 0, "renamedParameter"); - - tree.visitMethodVar(0, 0, 0, 0, "param_1"); - tree.visitDstName(MappedElementKind.METHOD_VAR, 0, "renamedVariable"); - - tree.visitClass("class_1$class_2"); - tree.visitDstName(MappedElementKind.CLASS, 0, "RenamedClass1$RenamedInnerClass2"); - - tree.visitField("field_1", "I"); - tree.visitDstName(MappedElementKind.FIELD, 0, "renamedField2"); - - tree.visitClass("class_3"); - tree.visitDstName(MappedElementKind.CLASS, 0, "RenamedClass3"); + tree = TestHelper.createTestTree(); } @Test From cbc1a0c299662192be11cfa2c98d6dfdba1fe60e Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Wed, 20 Sep 2023 09:27:01 +0200 Subject: [PATCH 20/22] Add per-element-metadata --- .../mappingio/FlatMappingVisitor.java | 99 ++++++++-- .../fabricmc/mappingio/MappingVisitor.java | 15 +- .../adapter/FlatAsRegularMappingVisitor.java | 97 +++++++++- .../adapter/ForwardingMappingVisitor.java | 5 + .../adapter/MappingDstNsReorder.java | 9 + .../adapter/MappingSourceNsSwitch.java | 11 ++ .../adapter/RegularAsFlatMappingVisitor.java | 107 ++++++++++- .../mappingio/format/MappingFormat.java | 36 +++- .../mappingio/format/StandardProperties.java | 65 ++++++- .../mappingio/format/StandardProperty.java | 11 ++ .../format/enigma/EnigmaDirWriter.java | 15 +- .../format/enigma/EnigmaFileReader.java | 120 ++++++++---- .../format/enigma/EnigmaFileWriter.java | 16 +- .../format/enigma/EnigmaWriterBase.java | 69 ++++++- .../format/proguard/ProGuardFileReader.java | 11 +- .../format/proguard/ProGuardFileWriter.java | 112 +++++++++--- .../mappingio/format/tsrg/TsrgFileReader.java | 6 +- .../fabricmc/mappingio/tree/MappingTree.java | 35 ++++ .../mappingio/tree/MappingTreeView.java | 13 ++ .../mappingio/tree/MemoryMappingTree.java | 171 +++++++++++++++++- .../net/fabricmc/mappingio/TestHelper.java | 8 +- .../net/fabricmc/mappingio/WriteTest.java | 6 + 22 files changed, 908 insertions(+), 129 deletions(-) diff --git a/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java index 056020ed..da650649 100644 --- a/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java @@ -57,16 +57,23 @@ default boolean visitContent() throws IOException { } boolean visitClass(String srcName, String[] dstNames) throws IOException; + void visitClassMetadata(String srcName, String[] dstNames, String propertyKey, String[] propertyValues) throws IOException; void visitClassComment(String srcName, String[] dstNames, String comment) throws IOException; boolean visitField(String srcClsName, String srcName, String srcDesc, String[] dstClsNames, String[] dstNames, String[] dstDescs) throws IOException; + void visitFieldMetadata(String srcClsName, String srcName, String srcDesc, + String[] dstClsNames, String[] dstNames, String[] dstDescs, + String propertyKey, String[] propertyValues) throws IOException; void visitFieldComment(String srcClsName, String srcName, String srcDesc, String[] dstClsNames, String[] dstNames, String[] dstDescs, String comment) throws IOException; boolean visitMethod(String srcClsName, String srcName, String srcDesc, String[] dstClsNames, String[] dstNames, String[] dstDescs) throws IOException; + void visitMethodMetadata(String srcClsName, String srcName, String srcDesc, + String[] dstClsNames, String[] dstNames, String[] dstDescs, + String propertyKey, String[] propertyValues) throws IOException; void visitMethodComment(String srcClsName, String srcName, String srcDesc, String[] dstClsNames, String[] dstNames, String[] dstDescs, String comment) throws IOException; @@ -74,6 +81,10 @@ void visitMethodComment(String srcClsName, String srcName, String srcDesc, boolean visitMethodArg(String srcClsName, String srcMethodName, String srcMethodDesc, int argPosition, int lvIndex, String srcArgName, String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstArgNames) throws IOException; + void visitMethodArgMetadata(String srcClsName, String srcMethodName, String srcMethodDesc, + int argPosition, int lvIndex, String srcArgName, + String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstArgNames, + String propertyKey, String[] propertyValues) throws IOException; void visitMethodArgComment(String srcClsName, String srcMethodName, String srcMethodDesc, int argPosition, int lvIndex, String srcArgName, String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstArgNames, @@ -82,6 +93,10 @@ void visitMethodArgComment(String srcClsName, String srcMethodName, String srcMe boolean visitMethodVar(String srcClsName, String srcMethodName, String srcMethodDesc, int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName, String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstVarNames) throws IOException; + void visitMethodVarMetadata(String srcClsName, String srcMethodName, String srcMethodDesc, + int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName, + String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstVarNames, + String propertyKey, String[] propertyValues) throws IOException; void visitMethodVarComment(String srcClsName, String srcMethodName, String srcMethodDesc, int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName, String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstVarNames, @@ -135,37 +150,53 @@ default boolean visitMethodVar(String srcClsName, String srcMethodName, String s // convenience / potentially higher efficiency visit methods for only one dst name + // Class default boolean visitClass(String srcName, String dstName) throws IOException { return visitClass(srcName, toArray(dstName)); } - + default void visitClassMetadata(String srcName, String propertyKey, String[] propertyValues) throws IOException { + visitClassMetadata(srcName, (String) null, propertyKey, propertyValues); + } + default void visitClassMetadata(String srcName, String dstName, String propertyKey, String[] propertyValues) throws IOException { + visitClassMetadata(srcName, toArray(dstName), propertyKey, propertyValues); + } default void visitClassComment(String srcName, String comment) throws IOException { visitClassComment(srcName, (String) null, comment); } - default void visitClassComment(String srcName, String dstName, String comment) throws IOException { visitClassComment(srcName, toArray(dstName), comment); } + // Field default boolean visitField(String srcClsName, String srcName, String srcDesc, String dstName) throws IOException { return visitField(srcClsName, srcName, srcDesc, null, dstName, null); } - default boolean visitField(String srcClsName, String srcName, String srcDesc, String dstClsName, String dstName, String dstDesc) throws IOException { return visitField(srcClsName, srcName, srcDesc, toArray(dstClsName), toArray(dstName), toArray(dstDesc)); } - + default void visitFieldMetadata(String srcClsName, String srcName, String srcDesc, + String propertyKey, String[] propertyValues) throws IOException { + visitFieldMetadata(srcClsName, srcName, srcDesc, + (String) null, null, null, + propertyKey, propertyValues); + } + default void visitFieldMetadata(String srcClsName, String srcName, String srcDesc, + String dstClsName, String dstName, String dstDesc, + String propertyKey, String[] propertyValues) throws IOException { + visitFieldMetadata(srcClsName, srcName, srcDesc, + toArray(dstClsName), toArray(dstName), toArray(dstDesc), + propertyKey, propertyValues); + } default void visitFieldComment(String srcClsName, String srcName, String srcDesc, String comment) throws IOException { visitFieldComment(srcClsName, srcName, srcDesc, (String) null, null, null, comment); } - default void visitFieldComment(String srcClsName, String srcName, String srcDesc, String dstClsName, String dstName, String dstDesc, String comment) throws IOException { @@ -174,25 +205,36 @@ default void visitFieldComment(String srcClsName, String srcName, String srcDesc comment); } + // Method default boolean visitMethod(String srcClsName, String srcName, String srcDesc, String dstName) throws IOException { return visitMethod(srcClsName, srcName, srcDesc, null, dstName, null); } - default boolean visitMethod(String srcClsName, String srcName, String srcDesc, String dstClsName, String dstName, String dstDesc) throws IOException { return visitMethod(srcClsName, srcName, srcDesc, toArray(dstClsName), toArray(dstName), toArray(dstDesc)); } - + default void visitMethodMetadata(String srcClsName, String srcName, String srcDesc, + String propertyKey, String[] propertyValues) throws IOException { + visitMethodMetadata(srcClsName, srcName, srcDesc, + (String) null, null, null, + propertyKey, propertyValues); + } + default void visitMethodMetadata(String srcClsName, String srcName, String srcDesc, + String dstClsName, String dstName, String dstDesc, + String propertyKey, String[] propertyValues) throws IOException { + visitMethodMetadata(srcClsName, srcName, srcDesc, + toArray(dstClsName), toArray(dstName), toArray(dstDesc), + propertyKey, propertyValues); + } default void visitMethodComment(String srcClsName, String srcName, String srcDesc, String comment) throws IOException { visitMethodComment(srcClsName, srcName, srcDesc, (String) null, null, null, comment); } - default void visitMethodComment(String srcClsName, String srcName, String srcDesc, String dstClsName, String dstName, String dstDesc, String comment) throws IOException { @@ -201,6 +243,7 @@ default void visitMethodComment(String srcClsName, String srcName, String srcDes comment); } + // Method Arg default boolean visitMethodArg(String srcClsName, String srcMethodName, String srcMethodDesc, int argPosition, int lvIndex, String srcArgName, String dstArgName) throws IOException { @@ -208,7 +251,6 @@ default boolean visitMethodArg(String srcClsName, String srcMethodName, String s argPosition, lvIndex, srcArgName, null, null, null, dstArgName); } - default boolean visitMethodArg(String srcClsName, String srcMethodName, String srcMethodDesc, int argPosition, int lvIndex, String srcArgName, String dstClsName, String dstMethodName, String dstMethodDesc, String dstArgName) throws IOException { @@ -216,7 +258,22 @@ default boolean visitMethodArg(String srcClsName, String srcMethodName, String s argPosition, lvIndex, srcArgName, toArray(dstClsName), toArray(dstMethodName), toArray(dstMethodDesc), toArray(dstArgName)); } - + default void visitMethodArgMetadata(String srcClsName, String srcMethodName, String srcMethodDesc, + int argPosition, int lvIndex, String srcArgName, + String propertyKey, String[] propertyValues) throws IOException { + visitMethodArgMetadata(srcClsName, srcMethodName, srcMethodDesc, + argPosition, lvIndex, srcArgName, + (String) null, null, null, null, + propertyKey, propertyValues); + } + default void visitMethodArgMetadata(String srcClsName, String srcMethodName, String srcMethodDesc, + int argPosition, int lvIndex, String srcArgName, + String dstClsName, String dstMethodName, String dstMethodDesc, String dstArgName, + String propertyKey, String[] propertyValues) throws IOException { + visitMethodArgMetadata(srcClsName, srcMethodName, srcMethodDesc, argPosition, lvIndex, srcArgName, + toArray(dstClsName), toArray(dstMethodName), toArray(dstMethodDesc), toArray(dstArgName), + propertyKey, propertyValues); + } default void visitMethodArgComment(String srcClsName, String srcMethodName, String srcMethodDesc, int argPosition, int lvIndex, String srcArgName, String comment) throws IOException { @@ -225,7 +282,6 @@ default void visitMethodArgComment(String srcClsName, String srcMethodName, Stri (String) null, null, null, null, comment); } - default void visitMethodArgComment(String srcClsName, String srcMethodName, String srcMethodDesc, int argPosition, int lvIndex, String srcArgName, String dstClsName, String dstMethodName, String dstMethodDesc, String dstArgName, @@ -235,6 +291,7 @@ default void visitMethodArgComment(String srcClsName, String srcMethodName, Stri comment); } + // Method Var default boolean visitMethodVar(String srcClsName, String srcMethodName, String srcMethodDesc, int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName, String dstVarName) throws IOException { @@ -242,7 +299,6 @@ default boolean visitMethodVar(String srcClsName, String srcMethodName, String s lvtRowIndex, lvIndex, startOpIdx, endOpIdx, srcVarName, null, null, null, dstVarName); } - default boolean visitMethodVar(String srcClsName, String srcMethodName, String srcMethodDesc, int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName, String dstClsName, String dstMethodName, String dstMethodDesc, String dstVarName) throws IOException { @@ -250,7 +306,23 @@ default boolean visitMethodVar(String srcClsName, String srcMethodName, String s lvtRowIndex, lvIndex, startOpIdx, endOpIdx, srcVarName, toArray(dstClsName), toArray(dstMethodName), toArray(dstMethodDesc), toArray(dstVarName)); } - + default void visitMethodVarMetadata(String srcClsName, String srcMethodName, String srcMethodDesc, + int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName, + String propertyKey, String[] propertyValues) throws IOException { + visitMethodVarMetadata(srcClsName, srcMethodName, srcMethodDesc, + lvtRowIndex, lvIndex, startOpIdx, endOpIdx, srcVarName, + (String) null, null, null, null, + propertyKey, propertyValues); + } + default void visitMethodVarMetadata(String srcClsName, String srcMethodName, String srcMethodDesc, + int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName, + String dstClsName, String dstMethodName, String dstMethodDesc, String dstVarName, + String propertyKey, String[] propertyValues) throws IOException { + visitMethodVarMetadata(srcClsName, srcMethodName, srcMethodDesc, + lvtRowIndex, lvIndex, startOpIdx, endOpIdx, srcVarName, + toArray(dstClsName), toArray(dstMethodName), toArray(dstMethodDesc), toArray(dstVarName), + propertyKey, propertyValues); + } default void visitMethodVarComment(String srcClsName, String srcMethodName, String srcMethodDesc, int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName, String comment) throws IOException { @@ -259,7 +331,6 @@ default void visitMethodVarComment(String srcClsName, String srcMethodName, Stri (String) null, null, null, null, comment); } - default void visitMethodVarComment(String srcClsName, String srcMethodName, String srcMethodDesc, int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName, String dstClsName, String dstMethodName, String dstMethodDesc, String dstVarName, diff --git a/src/main/java/net/fabricmc/mappingio/MappingVisitor.java b/src/main/java/net/fabricmc/mappingio/MappingVisitor.java index 5c2455ce..f14752ee 100644 --- a/src/main/java/net/fabricmc/mappingio/MappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/MappingVisitor.java @@ -27,11 +27,11 @@ *
  • overall: header -> content -> End -> overall *
  • header: Header -> Namespaces [-> Metadata]* *
  • content: Content [-> class|Metadata]* - *
  • class: Class [-> DstName]* -> ElementContent [-> field|method|Comment]* - *
  • field: Field [-> DstName|DstDesc]* -> ElementContent [-> Comment] - *
  • method: Method [-> DstName|DstDesc]* -> ElementContent [-> arg|var|Comment]* - *
  • arg: Arg [-> DstName]* -> ElementContent [-> Comment] - *
  • var: Var [-> DstName]* -> ElementContent [-> Comment] + *
  • class: Class [-> DstName]* -> ElementContent [-> ElementMetadata|field|method|Comment]* + *
  • field: Field [-> DstName|DstDesc]* -> ElementContent [-> ElementMetadata|Comment]* + *
  • method: Method [-> DstName|DstDesc]* -> ElementContent [-> ElementMetadata|arg|var|Comment]* + *
  • arg: Arg [-> DstName]* -> ElementContent [-> ElementMetadata|Comment]* + *
  • var: Var [-> DstName]* -> ElementContent [-> ElementMetadata|Comment]* *
* *

The elements with a skip-return (Header/Content/Class/Field/Method/Arg/Var/ElementContent) abort processing the @@ -118,6 +118,11 @@ default boolean visitElementContent(MappedElementKind targetKind) throws IOExcep return true; } + /** + * Metadata for the specified element (last content-visited or any parent). + */ + default void visitElementMetadata(MappedElementKind targetKind, String key, int namespace, String value) throws IOException { } + /** * Comment for the specified element (last content-visited or any parent). * diff --git a/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java index 34da310f..b16ac554 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java @@ -17,8 +17,11 @@ package net.fabricmc.mappingio.adapter; import java.io.IOException; +import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.Set; import net.fabricmc.mappingio.FlatMappingVisitor; @@ -75,7 +78,8 @@ public boolean visitContent() throws IOException { } @Override - public boolean visitClass(String srcName) { + public boolean visitClass(String srcName) throws IOException { + relayPendingElementMetadata(); this.srcClsName = srcName; Arrays.fill(dstNames, null); @@ -85,7 +89,8 @@ public boolean visitClass(String srcName) { } @Override - public boolean visitField(String srcName, String srcDesc) { + public boolean visitField(String srcName, String srcDesc) throws IOException { + relayPendingElementMetadata(); this.srcMemberName = srcName; this.srcMemberDesc = srcDesc; @@ -97,7 +102,8 @@ public boolean visitField(String srcName, String srcDesc) { } @Override - public boolean visitMethod(String srcName, String srcDesc) { + public boolean visitMethod(String srcName, String srcDesc) throws IOException { + relayPendingElementMetadata(); this.srcMemberName = srcName; this.srcMemberDesc = srcDesc; @@ -109,7 +115,8 @@ public boolean visitMethod(String srcName, String srcDesc) { } @Override - public boolean visitMethodArg(int argPosition, int lvIndex, String srcName) { + public boolean visitMethodArg(int argPosition, int lvIndex, String srcName) throws IOException { + relayPendingElementMetadata(); this.srcMemberSubName = srcName; this.argIdx = argPosition; this.lvIndex = lvIndex; @@ -120,7 +127,8 @@ public boolean visitMethodArg(int argPosition, int lvIndex, String srcName) { } @Override - public boolean visitMethodVar(int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcName) { + public boolean visitMethodVar(int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcName) throws IOException { + relayPendingElementMetadata(); this.srcMemberSubName = srcName; this.argIdx = lvtRowIndex; this.lvIndex = lvIndex; @@ -134,6 +142,7 @@ public boolean visitMethodVar(int lvtRowIndex, int lvIndex, int startOpIdx, int @Override public boolean visitEnd() throws IOException { + relayPendingElementMetadata(); return next.visitEnd(); } @@ -149,6 +158,7 @@ public void visitDstDesc(MappedElementKind targetKind, int namespace, String des @Override public boolean visitElementContent(MappedElementKind targetKind) throws IOException { + currentElementKind = targetKind; boolean relay; switch (targetKind) { @@ -181,8 +191,36 @@ public boolean visitElementContent(MappedElementKind targetKind) throws IOExcept return relay; } + @Override + public void visitElementMetadata(MappedElementKind targetKind, String key, int namespace, String value) throws IOException { + if (!key.equals(elementMetadata.getKey())) { + relayPendingElementMetadata(); + elementMetadata = new SimpleEntry<>(key, null); + } + + List valueStack = elementMetadata.getValue(); + + if (valueStack == null) { + valueStack = new ArrayList<>(4); + valueStack.add(new String[dstNames.length + 1]); + elementMetadata.setValue(valueStack); + } + + String[] values = valueStack.get(valueStack.size() - 1); + + // Merge value into existing array, unless already set, then append to stack and add there. + if (values[namespace] != null) { + values = new String[dstNames.length + 1]; + valueStack.add(values); + } + + values[namespace] = value == null ? nullSubstitute : value; + } + @Override public void visitComment(MappedElementKind targetKind, String comment) throws IOException { + relayPendingElementMetadata(); + switch (targetKind) { case CLASS: next.visitClassComment(srcClsName, dstClassNames, comment); @@ -206,8 +244,57 @@ public void visitComment(MappedElementKind targetKind, String comment) throws IO } } + private void relayPendingElementMetadata() throws IOException { + if (elementMetadata.getValue() == null) return; + String key = elementMetadata.getKey(); + String[] lastValues = null; + + for (String[] values : elementMetadata.getValue()) { + for (int i = 0; i < values.length; i++) { + if (values[i] == nullSubstitute) { + values[i] = null; + } else if (values[i] == null && lastValues != null) { + // Fill in holes + values[i] = lastValues[i]; + } + } + + switch (currentElementKind) { + case CLASS: + next.visitClassMetadata(srcClsName, dstClassNames, key, values); + break; + case FIELD: + next.visitFieldMetadata(srcClsName, srcMemberName, srcMemberDesc, + dstClassNames, dstMemberNames, dstMemberDescs, key, values); + break; + case METHOD: + next.visitMethodMetadata(srcClsName, srcMemberName, srcMemberDesc, + dstClassNames, dstMemberNames, dstMemberDescs, key, values); + break; + case METHOD_ARG: + next.visitMethodArgMetadata(srcClsName, srcMemberName, srcMemberDesc, argIdx, lvIndex, srcMemberSubName, + dstClassNames, dstMemberNames, dstMemberDescs, dstNames, key, values); + break; + case METHOD_VAR: + next.visitMethodVarMetadata(srcClsName, srcMemberName, srcMemberDesc, argIdx, lvIndex, startOpIdx, endOpIdx, srcMemberSubName, + dstClassNames, dstMemberNames, dstMemberDescs, dstNames, key, values); + break; + default: + throw new IllegalStateException(); + } + + lastValues = values; + } + + elementMetadata.setValue(null); + currentElementKind = null; + } + + private static final String nullSubstitute = new String(); private final FlatMappingVisitor next; + private Map.Entry> elementMetadata = new SimpleEntry<>(null, null); + private MappedElementKind currentElementKind; private String srcClsName; private String srcMemberName; private String srcMemberDesc; diff --git a/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java index 71d9574f..b06b617c 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java @@ -107,6 +107,11 @@ public boolean visitElementContent(MappedElementKind targetKind) throws IOExcept return next.visitElementContent(targetKind); } + @Override + public void visitElementMetadata(MappedElementKind targetKind, String key, int namespace, String value) throws IOException { + next.visitElementMetadata(targetKind, key, namespace, value); + } + @Override public void visitComment(MappedElementKind targetKind, String comment) throws IOException { next.visitComment(targetKind, comment); diff --git a/src/main/java/net/fabricmc/mappingio/adapter/MappingDstNsReorder.java b/src/main/java/net/fabricmc/mappingio/adapter/MappingDstNsReorder.java index b0232d25..1086828a 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/MappingDstNsReorder.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/MappingDstNsReorder.java @@ -66,6 +66,15 @@ public void visitDstDesc(MappedElementKind targetKind, int namespace, String des } } + @Override + public void visitElementMetadata(MappedElementKind targetKind, String key, int namespace, String value) throws IOException { + if (namespace >= 0) namespace = nsMap[namespace]; + + if (namespace >= 0) { + super.visitElementMetadata(targetKind, key, namespace, value); + } + } + private final List newDstNs; private int[] nsMap; } diff --git a/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java b/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java index de52a900..91da8920 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java @@ -300,6 +300,17 @@ public boolean visitElementContent(MappedElementKind targetKind) throws IOExcept return relay; } + @Override + public void visitElementMetadata(MappedElementKind targetKind, String key, int namespace, String value) throws IOException { + if (namespace == newSourceNs) { + namespace = -1; + } else if (namespace == -1) { + namespace = newSourceNs; + } + + next.visitElementMetadata(targetKind, key, namespace, value); + } + private final String newSourceNsName; private final boolean dropMissingNewSrcName; diff --git a/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java index 2c6408e8..7af2850b 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java @@ -89,6 +89,18 @@ private boolean visitClass(String srcName, String[] dstNames, String dstName) th return relayLastClass; } + @Override + public void visitClassMetadata(String srcName, String[] dstNames, String propertyKey, String[] propertyValues) throws IOException { + if (!visitClass(srcName, dstNames, null)) return; + visitElementMetadata(MappedElementKind.CLASS, propertyKey, propertyValues); + } + + @Override + public void visitClassMetadata(String srcName, String dstName, String propertyKey, String[] propertyValues) throws IOException { + if (!visitClass(srcName, null, dstName)) return; + visitElementMetadata(MappedElementKind.CLASS, propertyKey, propertyValues); + } + @Override public void visitClassComment(String srcName, String[] dstNames, String comment) throws IOException { if (!visitClass(srcName, dstNames, null)) return; @@ -128,6 +140,22 @@ private boolean visitField(String srcClsName, String srcName, String srcDesc, return relayLastMember; } + @Override + public void visitFieldMetadata(String srcClsName, String srcName, String srcDesc, + String[] dstClsNames, String[] dstNames, String[] dstDescs, + String propertyKey, String[] propertyValues) throws IOException { + if (!visitField(srcClsName, srcName, srcDesc, dstClsNames, dstNames, dstDescs, null, null, null)) return; + visitElementMetadata(MappedElementKind.FIELD, propertyKey, propertyValues); + } + + @Override + public void visitFieldMetadata(String srcClsName, String srcName, String srcDesc, + String dstClsName, String dstName, String dstDesc, + String propertyKey, String[] propertyValues) throws IOException { + if (!visitField(srcClsName, srcName, srcDesc, null, null, null, dstClsName, dstName, dstDesc)) return; + visitElementMetadata(MappedElementKind.FIELD, propertyKey, propertyValues); + } + @Override public void visitFieldComment(String srcClsName, String srcName, String srcDesc, String[] dstClsNames, String[] dstNames, String[] dstDescs, @@ -171,6 +199,22 @@ private boolean visitMethod(String srcClsName, String srcName, String srcDesc, return relayLastMember; } + @Override + public void visitMethodMetadata(String srcClsName, String srcName, String srcDesc, + String[] dstClsNames, String[] dstNames, String[] dstDescs, + String propertyKey, String[] propertyValues) throws IOException { + if (!visitMethod(srcClsName, srcName, srcDesc, dstClsNames, dstNames, dstDescs, null, null, null)) return; + visitElementMetadata(MappedElementKind.METHOD, propertyKey, propertyValues); + } + + @Override + public void visitMethodMetadata(String srcClsName, String srcName, String srcDesc, + String dstClsName, String dstName, String dstDesc, + String propertyKey, String[] propertyValues) throws IOException { + if (!visitMethod(srcClsName, srcName, srcDesc, null, null, null, dstClsName, dstName, dstDesc)) return; + visitElementMetadata(MappedElementKind.METHOD, propertyKey, propertyValues); + } + @Override public void visitMethodComment(String srcClsName, String srcName, String srcDesc, String[] dstClsNames, String[] dstNames, String[] dstDescs, @@ -219,6 +263,30 @@ private boolean visitMethodArg(String srcClsName, String srcMethodName, String s return relayLastMethodSub; } + @Override + public void visitMethodArgMetadata(String srcClsName, String srcMethodName, String srcMethodDesc, int argPosition, int lvIndex, String srcArgName, + String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstArgNames, + String propertyKey, String[] propertyValues) throws IOException { + if (!visitMethodArg(srcClsName, srcMethodName, srcMethodDesc, argPosition, lvIndex, srcArgName, + dstClsNames, dstMethodNames, dstMethodDescs, dstArgNames, null, null, null, null)) { + return; + } + + visitElementMetadata(MappedElementKind.METHOD_ARG, propertyKey, propertyValues); + } + + @Override + public void visitMethodArgMetadata(String srcClsName, String srcMethodName, String srcMethodDesc, int argPosition, + int lvIndex, String srcArgName, String dstClsName, String dstMethodName, String dstMethodDesc, String dstArgName, + String propertyKey, String[] propertyValues) throws IOException { + if (!visitMethodArg(srcClsName, srcMethodName, srcMethodDesc, argPosition, lvIndex, srcArgName, + null, null, null, null, dstClsName, dstMethodName, dstMethodDesc, dstArgName)) { + return; + } + + visitElementMetadata(MappedElementKind.METHOD_ARG, propertyKey, propertyValues); + } + @Override public void visitMethodArgComment(String srcClsName, String srcMethodName, String srcMethodDesc, int argPosition, int lvIndex, String srcArgName, String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstArgNames, @@ -233,8 +301,8 @@ public void visitMethodArgComment(String srcClsName, String srcMethodName, Strin @Override public void visitMethodArgComment(String srcClsName, String srcMethodName, String srcMethodDesc, int argPosition, - int lvIndex, String srcArgName, String dstClsName, String dstMethodName, String dstMethodDesc, - String dstArgName, String comment) throws IOException { + int lvIndex, String srcArgName, String dstClsName, String dstMethodName, String dstMethodDesc, String dstArgName, + String comment) throws IOException { if (!visitMethodArg(srcClsName, srcMethodName, srcMethodDesc, argPosition, lvIndex, srcArgName, null, null, null, null, dstClsName, dstMethodName, dstMethodDesc, dstArgName)) { return; @@ -274,6 +342,32 @@ private boolean visitMethodVar(String srcClsName, String srcMethodName, String s return relayLastMethodSub; } + @Override + public void visitMethodVarMetadata(String srcClsName, String srcMethodName, String srcMethodDesc, + int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName, + String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstVarNames, + String propertyKey, String[] propertyValues) throws IOException { + if (!visitMethodVar(srcClsName, srcMethodName, srcMethodDesc, lvtRowIndex, lvIndex, startOpIdx, endOpIdx, srcVarName, + dstClsNames, dstMethodNames, dstMethodDescs, dstVarNames, null, null, null, null)) { + return; + } + + visitElementMetadata(MappedElementKind.METHOD_VAR, propertyKey, propertyValues); + } + + @Override + public void visitMethodVarMetadata(String srcClsName, String srcMethodName, String srcMethodDesc, + int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName, + String dstClsName, String dstMethodName, String dstMethodDesc, String dstVarName, + String propertyKey, String[] propertyValues) throws IOException { + if (!visitMethodVar(srcClsName, srcMethodName, srcMethodDesc, lvtRowIndex, lvIndex, startOpIdx, endOpIdx, srcVarName, + null, null, null, null, dstClsName, dstMethodName, dstMethodDesc, dstVarName)) { + return; + } + + visitElementMetadata(MappedElementKind.METHOD_VAR, propertyKey, propertyValues); + } + @Override public void visitMethodVarComment(String srcClsName, String srcMethodName, String srcMethodDesc, int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName, @@ -344,6 +438,15 @@ private boolean visitDstNamesDescs(MappedElementKind targetKind, String[] dstNam return next.visitElementContent(targetKind); } + private void visitElementMetadata(MappedElementKind targetKind, String key, String[] values) throws IOException { + if (values != null) { + for (int i = 0; i < values.length; i++) { + String value = values[i]; + if (value != null) next.visitElementMetadata(targetKind, key, i-1, value); + } + } + } + private final MappingVisitor next; private boolean relayDstFieldDescs; diff --git a/src/main/java/net/fabricmc/mappingio/format/MappingFormat.java b/src/main/java/net/fabricmc/mappingio/format/MappingFormat.java index ac7bfcf6..66d87e46 100644 --- a/src/main/java/net/fabricmc/mappingio/format/MappingFormat.java +++ b/src/main/java/net/fabricmc/mappingio/format/MappingFormat.java @@ -17,19 +17,20 @@ package net.fabricmc.mappingio.format; public enum MappingFormat { - TINY_FILE("Tiny file", "tiny", true, true, false, false, false), - TINY_2_FILE("Tiny v2 file", "tiny", true, true, true, true, true), - ENIGMA_FILE("Enigma file", "mappings", false, true, true, true, false), - ENIGMA_DIR("Enigma directory", null, false, true, true, true, false), - MCP_DIR("MCP directory", null, false, false, true, true, false), - SRG_FILE("SRG file", "srg", false, false, false, false, false), - TSRG_FILE("TSRG file", "tsrg", false, false, false, false, false), - TSRG_2_FILE("TSRG2 file", "tsrg", true, false, false, true, false), - PROGUARD_FILE("ProGuard file", "map", false, true, false, false, false); + TINY_FILE("Tiny file", "tiny", true, true, false, false, false, MetadataSupport.ARBITRARY, MetadataSupport.NONE), + TINY_2_FILE("Tiny v2 file", "tiny", true, true, true, true, true, MetadataSupport.ARBITRARY, MetadataSupport.NONE), + ENIGMA_FILE("Enigma file", "mappings", false, true, true, true, false, MetadataSupport.NONE, MetadataSupport.HARDCODED), + ENIGMA_DIR("Enigma directory", null, false, true, true, true, false, MetadataSupport.NONE, MetadataSupport.HARDCODED), + MCP_DIR("MCP directory", null, false, false, true, true, false, MetadataSupport.NONE, MetadataSupport.NONE), + SRG_FILE("SRG file", "srg", false, false, false, false, false, MetadataSupport.NONE, MetadataSupport.NONE), + TSRG_FILE("TSRG file", "tsrg", false, false, false, false, false, MetadataSupport.NONE, MetadataSupport.NONE), + TSRG_2_FILE("TSRG2 file", "tsrg", true, false, false, true, false, MetadataSupport.NONE, MetadataSupport.HARDCODED), + PROGUARD_FILE("ProGuard file", "map", false, true, false, false, false, MetadataSupport.NONE, MetadataSupport.HARDCODED); MappingFormat(String name, String fileExt, boolean hasNamespaces, boolean hasFieldDescriptors, - boolean supportsComments, boolean supportsArgs, boolean supportsLocals) { + boolean supportsComments, boolean supportsArgs, boolean supportsLocals, + MetadataSupport fileMetadataSupport, MetadataSupport elementMetadataSupport) { this.name = name; this.fileExt = fileExt; this.hasNamespaces = hasNamespaces; @@ -37,6 +38,8 @@ public enum MappingFormat { this.supportsComments = supportsComments; this.supportsArgs = supportsArgs; this.supportsLocals = supportsLocals; + this.fileMetadataSupport = fileMetadataSupport; + this.elementMetadataSupport = elementMetadataSupport; } public boolean hasSingleFile() { @@ -56,4 +59,17 @@ public String getGlobPattern() { public final boolean supportsComments; public final boolean supportsArgs; public final boolean supportsLocals; + public final MetadataSupport fileMetadataSupport; + public final MetadataSupport elementMetadataSupport; + + public enum MetadataSupport { + /** No metadata at all. */ + NONE, + + /** Only some select properties. */ + HARDCODED, + + /** Arbitrary metadata may be attached. */ + ARBITRARY + } } diff --git a/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java index d5e9491c..dc22319e 100644 --- a/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java +++ b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java @@ -16,14 +16,18 @@ package net.fabricmc.mappingio.format; +import java.util.AbstractMap.SimpleEntry; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import org.jetbrains.annotations.ApiStatus; +import net.fabricmc.mappingio.MappedElementKind; + public final class StandardProperties { private StandardProperties() { } @@ -47,6 +51,10 @@ public static StandardProperty getById(String id) { public static final StandardProperty NEXT_INTERMEDIARY_COMPONENT; public static final StandardProperty MISSING_LVT_INDICES; public static final StandardProperty ESCAPED_NAMES; + public static final StandardProperty MODIFIED_ACCESS; + public static final StandardProperty IS_STATIC; + public static final StandardProperty START_LINE_NUMBER; + public static final StandardProperty END_LINE_NUMBER; private static final Set values = new HashSet<>(); private static final Map valuesByName = new HashMap<>(); private static final Map valuesById = new HashMap<>(); @@ -68,6 +76,19 @@ public static StandardProperty getById(String id) { .addMapping(MappingFormat.TINY_2_FILE, "missing-lvt-indices"); ESCAPED_NAMES = register("escaped-names") .addMapping(MappingFormat.TINY_2_FILE, "escaped-names"); + MODIFIED_ACCESS = register("modified-access") + .addMapping(MappingFormat.ENIGMA_FILE, MappedElementKind.CLASS, "ACC:") + .addMapping(MappingFormat.ENIGMA_FILE, MappedElementKind.FIELD, "ACC:") + .addMapping(MappingFormat.ENIGMA_FILE, MappedElementKind.METHOD, "ACC:") + .addMapping(MappingFormat.ENIGMA_DIR, MappedElementKind.CLASS, "ACC:") + .addMapping(MappingFormat.ENIGMA_DIR, MappedElementKind.FIELD, "ACC:") + .addMapping(MappingFormat.ENIGMA_DIR, MappedElementKind.METHOD, "ACC:"); + IS_STATIC = register("is-static") + .addMapping(MappingFormat.TSRG_2_FILE, MappedElementKind.METHOD, "static"); + START_LINE_NUMBER = register("start-line-number") + .addMapping(MappingFormat.PROGUARD_FILE, MappedElementKind.METHOD, null); + END_LINE_NUMBER = register("end-line-number") + .addMapping(MappingFormat.PROGUARD_FILE, MappedElementKind.METHOD, null); } private static StandardPropertyImpl register(String id) { @@ -82,24 +103,56 @@ private static class StandardPropertyImpl implements StandardProperty { } private StandardPropertyImpl addMapping(MappingFormat format, String name) { - nameByFormat.put(format, name); + filePropNameByFormat.put(format, name); + valuesByName.put(name, this); + return this; + } + + private StandardPropertyImpl addMapping(MappingFormat format, MappedElementKind elementKind, String name) { + propElementKindByFormat.put(format, elementKind); + elementPropNameByFormat.put(new SimpleEntry<>(format, elementKind), name); valuesByName.put(name, this); return this; } + @Override + public boolean isFileProperty() { + return !filePropNameByFormat.isEmpty(); + } + + @Override + public boolean isElementProperty() { + return !elementPropNameByFormat.isEmpty(); + } + @Override public Set getApplicableFormats() { - return nameByFormat.keySet(); + return filePropNameByFormat.keySet(); + } + + @Override + public Map getApplicableElementKinds() { + return propElementKindByFormat; } @Override public boolean isApplicableTo(MappingFormat format) { - return nameByFormat.containsKey(format); + return filePropNameByFormat.containsKey(format); + } + + @Override + public boolean isApplicableTo(MappingFormat format, MappedElementKind elementKind) { + return elementPropNameByFormat.containsKey(new SimpleEntry<>(format, elementKind)); } @Override public String getNameFor(MappingFormat format) { - return nameByFormat.get(format); + return filePropNameByFormat.get(format); + } + + @Override + public String getNameFor(MappingFormat format, MappedElementKind elementKind) { + return elementPropNameByFormat.get(new SimpleEntry<>(format, elementKind)); } @Override @@ -108,6 +161,8 @@ public String getId() { } private final String id; - private final Map nameByFormat = new HashMap<>(4); + private final Map filePropNameByFormat = new HashMap<>(4); + private final Map, String> elementPropNameByFormat = new HashMap<>(4); + private final Map propElementKindByFormat = new HashMap<>(4); } } diff --git a/src/main/java/net/fabricmc/mappingio/format/StandardProperty.java b/src/main/java/net/fabricmc/mappingio/format/StandardProperty.java index 671ea7ba..84d5ea8e 100644 --- a/src/main/java/net/fabricmc/mappingio/format/StandardProperty.java +++ b/src/main/java/net/fabricmc/mappingio/format/StandardProperty.java @@ -16,14 +16,25 @@ package net.fabricmc.mappingio.format; +import java.util.Map; import java.util.Set; import org.jetbrains.annotations.ApiStatus; +import net.fabricmc.mappingio.MappedElementKind; + public interface StandardProperty { + boolean isFileProperty(); + boolean isElementProperty(); + Set getApplicableFormats(); + Map getApplicableElementKinds(); + boolean isApplicableTo(MappingFormat format); + boolean isApplicableTo(MappingFormat format, MappedElementKind elementKind); + String getNameFor(MappingFormat format); + String getNameFor(MappingFormat format, MappedElementKind elementKind); /** * Used internally by MappingTrees, consistency between JVM sessions diff --git a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaDirWriter.java b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaDirWriter.java index ea5332e1..4e09852c 100644 --- a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaDirWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaDirWriter.java @@ -29,6 +29,7 @@ import java.util.List; import net.fabricmc.mappingio.MappedElementKind; +import net.fabricmc.mappingio.format.MappingFormat; public final class EnigmaDirWriter extends EnigmaWriterBase { public EnigmaDirWriter(Path dir, boolean deleteExistingFiles) throws IOException { @@ -60,6 +61,11 @@ public FileVisitResult postVisitDirectory(Path file, IOException exc) throws IOE } } + @Override + protected MappingFormat getFormat() { + return MappingFormat.ENIGMA_DIR; + } + @Override public void close() throws IOException { if (writer != null) { @@ -128,16 +134,9 @@ public boolean visitElementContent(MappedElementKind targetKind) throws IOExcept writer = Files.newBufferedWriter(file, StandardOpenOption.WRITE, StandardOpenOption.APPEND, StandardOpenOption.CREATE); } - - writeMismatchedOrMissingClasses(); - } else if (targetKind == MappedElementKind.FIELD || targetKind == MappedElementKind.METHOD) { - writer.write(' '); - writer.write(desc); - writer.write('\n'); - } else { - writer.write('\n'); } + super.visitElementContent(targetKind); return true; } diff --git a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileReader.java b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileReader.java index 05ffce65..f8885567 100644 --- a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileReader.java @@ -19,13 +19,17 @@ import java.io.IOException; import java.io.Reader; import java.util.Collections; +import java.util.Locale; import java.util.Set; +import org.jetbrains.annotations.Nullable; + import net.fabricmc.mappingio.MappedElementKind; import net.fabricmc.mappingio.MappingFlag; import net.fabricmc.mappingio.MappingUtil; import net.fabricmc.mappingio.MappingVisitor; import net.fabricmc.mappingio.format.ColumnFileReader; +import net.fabricmc.mappingio.format.StandardProperties; import net.fabricmc.mappingio.tree.MappingTree; import net.fabricmc.mappingio.tree.MemoryMappingTree; @@ -61,7 +65,7 @@ public static void read(ColumnFileReader reader, String sourceNs, String targetN final MappingVisitor finalVisitor = visitor; do { - if (reader.nextCol("CLASS")) { // class: CLASS [] + if (reader.nextCol("CLASS")) { // class: CLASS [] [] readClass(reader, 0, null, null, commentSb, finalVisitor); } } while (reader.nextLine(0)); @@ -75,8 +79,11 @@ public static void read(ColumnFileReader reader, String sourceNs, String targetN } private static void readClass(ColumnFileReader reader, int indent, String outerSrcClass, String outerDstClass, StringBuilder commentSb, MappingVisitor visitor) throws IOException { - String srcInnerName = reader.nextCol(); - if (srcInnerName == null || srcInnerName.isEmpty()) throw new IOException("missing class-name-a in line "+reader.getLineNumber()); + String line = reader.nextCols(false); + String[] parts = line.split(" "); + + if (parts.length == 0 || parts[0].isEmpty()) throw new IOException("missing class-name-a in line "+reader.getLineNumber()); + String srcInnerName = parts[0]; String srcName = srcInnerName; @@ -84,7 +91,22 @@ private static void readClass(ColumnFileReader reader, int indent, String outerS srcName = String.format("%s$%s", outerSrcClass, srcInnerName); } - String dstInnerName = reader.nextCol(); + String dstInnerName = null; + String accessModifier = null; + + if (parts.length == 2) { // | + String parsedModifier = parseModifier(parts[1]); + + if (parsedModifier == null) { + dstInnerName = parts[1]; + } else { + accessModifier = parsedModifier; + } + } else { + dstInnerName = parts[1]; + accessModifier = parts[2]; + } + String dstName = dstInnerName; // merge with outer name if available @@ -96,19 +118,20 @@ private static void readClass(ColumnFileReader reader, int indent, String outerS dstName = String.format("%s$%s", outerDstClass, dstInnerName); } - readClassBody(reader, indent, srcName, dstName, commentSb, visitor); + readClassBody(reader, indent, srcName, dstName, accessModifier, commentSb, visitor); } - private static void readClassBody(ColumnFileReader reader, int indent, String srcClass, String dstClass, StringBuilder commentSb, MappingVisitor visitor) throws IOException { + private static void readClassBody(ColumnFileReader reader, int indent, String srcClass, String dstClass, + String classAccess, StringBuilder commentSb, MappingVisitor visitor) throws IOException { boolean visited = false; int state = 0; // 0=invalid 1=visit -1=skip while (reader.nextLine(indent + 1)) { boolean isMethod; - if (reader.nextCol("CLASS")) { // nested class: CLASS [] + if (reader.nextCol("CLASS")) { // nested class: CLASS [] [] if (!visited || commentSb.length() > 0) { - visitClass(srcClass, dstClass, state, commentSb, visitor); + visitClass(srcClass, dstClass, state, classAccess, commentSb, visitor); visited = true; } @@ -116,46 +139,64 @@ private static void readClassBody(ColumnFileReader reader, int indent, String sr state = 0; } else if (reader.nextCol("COMMENT")) { // comment: COMMENT readComment(reader, commentSb); - } else if ((isMethod = reader.nextCol("METHOD")) || reader.nextCol("FIELD")) { // method: METHOD [] or field: FIELD [] - state = visitClass(srcClass, dstClass, state, commentSb, visitor); + } else if ((isMethod = reader.nextCol("METHOD")) || reader.nextCol("FIELD")) { // METHOD|FIELD [] [] + state = visitClass(srcClass, dstClass, state, classAccess, commentSb, visitor); visited = true; if (state < 0) continue; - String srcName = reader.nextCol(); - if (srcName == null || srcName.isEmpty()) throw new IOException("missing field-name-a in line "+reader.getLineNumber()); + String line = reader.nextCols(false); + String[] parts = line.split(" "); + + if (parts.length == 0 || parts[0].isEmpty()) throw new IOException("missing member-name-a in line "+reader.getLineNumber()); + if (parts.length == 1 || parts[1].isEmpty()) throw new IOException("missing member-desc-a in line "+reader.getLineNumber()); + String srcName = parts[0]; + String dstName = null; + String modifier = null; + String srcDesc; + + if (parts.length == 2) { // + srcDesc = parts[1]; + } else if (parts.length == 3) { // | + String parsedModifier = parseModifier(parts[2]); + + if (parsedModifier == null) { + dstName = parts[1]; + srcDesc = parts[2]; + } else { + srcDesc = parts[1]; + modifier = parsedModifier; + } + } else { // + dstName = parts[1]; + srcDesc = parts[2]; + modifier = parts[3]; + } - String dstNameOrSrcDesc = reader.nextCol(); - if (dstNameOrSrcDesc == null || dstNameOrSrcDesc.isEmpty()) throw new IOException("missing field-desc-b in line "+reader.getLineNumber()); + MappedElementKind targetKind = isMethod && visitor.visitMethod(srcName, srcDesc) ? MappedElementKind.METHOD + : !isMethod && visitor.visitField(srcName, srcDesc) ? MappedElementKind.FIELD : null; - String srcDesc = reader.nextCol(); - String dstName; + if (targetKind != null) { + if (dstName != null && !dstName.isEmpty()) visitor.visitDstName(targetKind, 0, dstName); + if (modifier != null) visitAccessModifier(targetKind, modifier, visitor); - if (srcDesc == null) { - dstName = null; - srcDesc = dstNameOrSrcDesc; - } else { - dstName = dstNameOrSrcDesc; - } - - if (isMethod && visitor.visitMethod(srcName, srcDesc)) { - if (dstName != null && !dstName.isEmpty()) visitor.visitDstName(MappedElementKind.METHOD, 0, dstName); - readMethod(reader, indent, commentSb, visitor); - } else if (!isMethod && visitor.visitField(srcName, srcDesc)) { - if (dstName != null && !dstName.isEmpty()) visitor.visitDstName(MappedElementKind.FIELD, 0, dstName); - readElement(reader, MappedElementKind.FIELD, indent, commentSb, visitor); + if (targetKind == MappedElementKind.METHOD) { + readMethod(reader, indent, commentSb, visitor); + } else { + readElement(reader, targetKind, indent, commentSb, visitor); + } } } } if (!visited || commentSb.length() > 0) { - visitClass(srcClass, dstClass, state, commentSb, visitor); + visitClass(srcClass, dstClass, state, classAccess, commentSb, visitor); } } /** * Re-visit a class if necessary and visit its comment if available. */ - private static int visitClass(String srcClass, String dstClass, int state, StringBuilder commentSb, MappingVisitor visitor) throws IOException { + private static int visitClass(String srcClass, String dstClass, int state, String accessModifier, StringBuilder commentSb, MappingVisitor visitor) throws IOException { // state: 0=invalid 1=visit -1=skip if (state == 0) { @@ -168,6 +209,10 @@ private static int visitClass(String srcClass, String dstClass, int state, Strin state = visitContent ? 1 : -1; + if (accessModifier != null) { + visitAccessModifier(MappedElementKind.CLASS, accessModifier, visitor); + } + if (commentSb.length() > 0) { if (state > 0) visitor.visitComment(MappedElementKind.CLASS, commentSb.toString()); @@ -178,6 +223,10 @@ private static int visitClass(String srcClass, String dstClass, int state, Strin return state; } + private static void visitAccessModifier(MappedElementKind targetKind, String modifier, MappingVisitor visitor) throws IOException { + visitor.visitElementMetadata(targetKind, StandardProperties.MODIFIED_ACCESS.getId(), 0, modifier); + } + private static void readMethod(ColumnFileReader reader, int indent, StringBuilder commentSb, MappingVisitor visitor) throws IOException { if (!visitor.visitElementContent(MappedElementKind.METHOD)) return; @@ -233,4 +282,13 @@ private static void submitComment(MappedElementKind kind, StringBuilder commentS visitor.visitComment(kind, commentSb.toString()); commentSb.setLength(0); } + + @Nullable + private static String parseModifier(String token) { + if (!token.startsWith("ACC:")) { + return null; + } + + return token.substring(4).toLowerCase(Locale.ROOT); + } } diff --git a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileWriter.java b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileWriter.java index 4c285707..4ce1c70f 100644 --- a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileWriter.java @@ -19,7 +19,7 @@ import java.io.IOException; import java.io.Writer; -import net.fabricmc.mappingio.MappedElementKind; +import net.fabricmc.mappingio.format.MappingFormat; public final class EnigmaFileWriter extends EnigmaWriterBase { public EnigmaFileWriter(Writer writer) throws IOException { @@ -27,17 +27,7 @@ public EnigmaFileWriter(Writer writer) throws IOException { } @Override - public boolean visitElementContent(MappedElementKind targetKind) throws IOException { - if (targetKind == MappedElementKind.CLASS) { - writeMismatchedOrMissingClasses(); - } else if (targetKind == MappedElementKind.FIELD || targetKind == MappedElementKind.METHOD) { - writer.write(' '); - writer.write(desc); - writer.write('\n'); - } else { - writer.write('\n'); - } - - return true; + protected MappingFormat getFormat() { + return MappingFormat.ENIGMA_FILE; } } diff --git a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaWriterBase.java b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaWriterBase.java index 11277530..9ecd3bfb 100644 --- a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaWriterBase.java +++ b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaWriterBase.java @@ -19,18 +19,26 @@ import java.io.IOException; import java.io.Writer; import java.util.EnumSet; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; +import java.util.Map; import java.util.Set; import net.fabricmc.mappingio.MappedElementKind; import net.fabricmc.mappingio.MappingFlag; import net.fabricmc.mappingio.MappingWriter; +import net.fabricmc.mappingio.format.MappingFormat; +import net.fabricmc.mappingio.format.StandardProperties; +import net.fabricmc.mappingio.format.StandardProperty; abstract class EnigmaWriterBase implements MappingWriter { EnigmaWriterBase(Writer writer) throws IOException { this.writer = writer; } + protected abstract MappingFormat getFormat(); + @Override public void close() throws IOException { writer.close(); @@ -46,12 +54,14 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) { } @Override public boolean visitClass(String srcName) throws IOException { + if (writer != null && srcClassName != null) writePendingElementMetadata(true); srcClassName = srcName; return true; } @Override public boolean visitField(String srcName, String srcDesc) throws IOException { + writePendingElementMetadata(true); writeIndent(0); writer.write("FIELD "); writer.write(srcName); @@ -63,6 +73,7 @@ public boolean visitField(String srcName, String srcDesc) throws IOException { @Override public boolean visitMethod(String srcName, String srcDesc) throws IOException { + writePendingElementMetadata(true); writeIndent(0); writer.write("METHOD "); writer.write(srcName); @@ -74,6 +85,7 @@ public boolean visitMethod(String srcName, String srcDesc) throws IOException { @Override public boolean visitMethodArg(int argPosition, int lvIndex, String srcName) throws IOException { + writePendingElementMetadata(true); writeIndent(1); writer.write("ARG "); writer.write(Integer.toString(lvIndex)); @@ -82,12 +94,13 @@ public boolean visitMethodArg(int argPosition, int lvIndex, String srcName) thro } @Override - public boolean visitMethodVar(int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcName) { + public boolean visitMethodVar(int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcName) throws IOException { return false; } @Override public boolean visitEnd() throws IOException { + writePendingElementMetadata(false); close(); return true; @@ -106,7 +119,28 @@ public void visitDstName(MappedElementKind targetKind, int namespace, String nam } @Override - public abstract boolean visitElementContent(MappedElementKind targetKind) throws IOException; + public boolean visitElementContent(MappedElementKind targetKind) throws IOException { + if (targetKind == MappedElementKind.CLASS) { + writeMismatchedOrMissingClasses(); + } else if (targetKind == MappedElementKind.FIELD || targetKind == MappedElementKind.METHOD) { + writer.write(' '); + writer.write(desc); + } + + return true; + } + + @Override + public void visitElementMetadata(MappedElementKind target, String key, int namespace, String value) { + if (namespace != 0) return; + + StandardProperty property = StandardProperties.getById(key); + if (property == null) return; + if (!property.isApplicableTo(getFormat(), target)) return; // How did it get there? + + key = property.getNameFor(getFormat(), target); + elementMetadata.put(property, value); + } protected static int getNextOuterEnd(String name, int startPos) { int pos; @@ -121,6 +155,7 @@ protected static int getNextOuterEnd(String name, int startPos) { @Override public void visitComment(MappedElementKind targetKind, String comment) throws IOException { + writePendingElementMetadata(true); int start = 0; int pos; @@ -150,7 +185,9 @@ public void visitComment(MappedElementKind targetKind, String comment) throws IO if (start < end) writer.write(comment, start, end - start); } - writer.write('\n'); + if (pos >= 0) { + writer.write('\n'); + } start = end + 1; } while (pos >= 0); @@ -159,6 +196,7 @@ public void visitComment(MappedElementKind targetKind, String comment) throws IO protected void writeMismatchedOrMissingClasses() throws IOException { indent = 0; int srcStart = 0; + boolean writeNewLines = false; do { int srcEnd = getNextOuterEnd(srcClassName, srcStart); @@ -167,6 +205,11 @@ protected void writeMismatchedOrMissingClasses() throws IOException { if (!lastWrittenClass.regionMatches(srcStart, srcClassName, srcStart, srcLen) // writtenPart.startsWith(srcPart) || srcEnd < lastWrittenClass.length() && lastWrittenClass.charAt(srcEnd) != '$') { // no trailing characters in writtenPart -> startsWith = equals + if (writeNewLines) { + writer.write('\n'); + } + + writeNewLines = true; writeIndent(0); writer.write("CLASS "); writer.write(srcClassName, srcStart, srcLen); @@ -192,7 +235,7 @@ protected void writeMismatchedOrMissingClasses() throws IOException { } } - writer.write('\n'); + writePendingElementMetadata(false); } indent++; @@ -203,6 +246,22 @@ protected void writeMismatchedOrMissingClasses() throws IOException { dstName = null; } + protected void writePendingElementMetadata(boolean appendLineBreak) throws IOException { + if (!elementMetadata.isEmpty()) { + for (Map.Entry entry : elementMetadata.entrySet()) { + if (entry.getKey() != StandardProperties.MODIFIED_ACCESS) throw new IllegalStateException(); + + writer.write(" ACC:"); + writer.write(entry.getValue().toUpperCase(Locale.ROOT)); + break; + } + + elementMetadata.clear(); + } + + if (appendLineBreak) writer.write('\n'); + } + protected void writeIndent(int extra) throws IOException { for (int i = 0; i < indent + extra; i++) { writer.write('\t'); @@ -212,6 +271,7 @@ protected void writeIndent(int extra) throws IOException { protected static final Set flags = EnumSet.of(MappingFlag.NEEDS_UNIQUENESS, MappingFlag.NEEDS_SRC_FIELD_DESC, MappingFlag.NEEDS_SRC_METHOD_DESC); protected static final String toEscape = "\\\n\r\0\t"; protected static final String escaped = "\\nr0t"; + protected static final LinkedHashMap elementMetadata = new LinkedHashMap<>(); protected Writer writer; protected int indent; @@ -220,7 +280,6 @@ protected void writeIndent(int extra) throws IOException { protected String currentClass; protected String lastWrittenClass = ""; protected String dstName; - protected String[] dstNames; protected String desc; } diff --git a/src/main/java/net/fabricmc/mappingio/format/proguard/ProGuardFileReader.java b/src/main/java/net/fabricmc/mappingio/format/proguard/ProGuardFileReader.java index d1670b7d..9193e79a 100644 --- a/src/main/java/net/fabricmc/mappingio/format/proguard/ProGuardFileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/proguard/ProGuardFileReader.java @@ -27,6 +27,7 @@ import net.fabricmc.mappingio.MappingFlag; import net.fabricmc.mappingio.MappingUtil; import net.fabricmc.mappingio.MappingVisitor; +import net.fabricmc.mappingio.format.StandardProperties; public final class ProGuardFileReader { private ProGuardFileReader() { @@ -115,6 +116,8 @@ private static void read(BufferedReader reader, String sourceNs, String targetNs // lineStart, lineEndIncl, rtype String part0 = parts[0]; int pos = part0.indexOf(':'); + String lineStart = null; + String lineEnd = null; String retType; @@ -124,6 +127,8 @@ private static void read(BufferedReader reader, String sourceNs, String targetNs int pos2 = part0.indexOf(':', pos + 1); assert pos2 != -1; + lineStart = part0.substring(0, pos); + lineEnd = part0.substring(pos + 1, pos2); retType = part0.substring(pos2 + 1); } @@ -141,7 +146,11 @@ private static void read(BufferedReader reader, String sourceNs, String targetNs if (visitor.visitMethod(name, desc)) { String mappedName = parts[3]; visitor.visitDstName(MappedElementKind.METHOD, 0, mappedName); - visitor.visitElementContent(MappedElementKind.METHOD); + + if (visitor.visitElementContent(MappedElementKind.METHOD) && lineStart != null) { + visitor.visitElementMetadata(MappedElementKind.METHOD, StandardProperties.START_LINE_NUMBER.getId(), 0, lineStart); + visitor.visitElementMetadata(MappedElementKind.METHOD, StandardProperties.END_LINE_NUMBER.getId(), 0, lineEnd); + } } } } diff --git a/src/main/java/net/fabricmc/mappingio/format/proguard/ProGuardFileWriter.java b/src/main/java/net/fabricmc/mappingio/format/proguard/ProGuardFileWriter.java index f41d4450..d0f6a738 100644 --- a/src/main/java/net/fabricmc/mappingio/format/proguard/ProGuardFileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/proguard/ProGuardFileWriter.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.io.Writer; +import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -25,6 +26,8 @@ import net.fabricmc.mappingio.MappedElementKind; import net.fabricmc.mappingio.MappingWriter; +import net.fabricmc.mappingio.format.StandardProperties; +import net.fabricmc.mappingio.format.StandardProperty; /** * A mapping writer for the ProGuard mapping format. @@ -36,8 +39,11 @@ */ public final class ProGuardFileWriter implements MappingWriter { private final Writer writer; - private int dstNamespace = -1; private final String dstNamespaceString; + private int dstNamespace = -1; + private MappedElementKind pendingMemberType; + /** srcName, srcDesc, dstName, [lineStart, lineEnd]. */ + private String[] pendingMemberData = new String[5]; /** * Constructs a ProGuard mapping writer that uses @@ -103,6 +109,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr @Override public boolean visitClass(String srcName) throws IOException { + writePendingMember(); + writer.write(toJavaClassName(srcName)); writeArrow(); return true; @@ -110,34 +118,21 @@ public boolean visitClass(String srcName) throws IOException { @Override public boolean visitField(String srcName, String srcDesc) throws IOException { - writeIndent(); - writer.write(toJavaType(srcDesc)); - writer.write(' '); - writer.write(srcName); - writeArrow(); + writePendingMember(); + + pendingMemberType = MappedElementKind.FIELD; + pendingMemberData[0] = srcName; + pendingMemberData[1] = srcDesc; return true; } @Override public boolean visitMethod(String srcName, String srcDesc) throws IOException { - Type type = Type.getMethodType(srcDesc); - writeIndent(); - writer.write(toJavaType(type.getReturnType().getDescriptor())); - writer.write(' '); - writer.write(srcName); - writer.write('('); - Type[] args = type.getArgumentTypes(); - - for (int i = 0; i < args.length; i++) { - if (i > 0) { - writer.write(','); - } - - writer.write(toJavaType(args[i].getDescriptor())); - } + writePendingMember(); - writer.write(')'); - writeArrow(); + pendingMemberType = MappedElementKind.METHOD; + pendingMemberData[0] = srcName; + pendingMemberData[1] = srcDesc; return true; } @@ -162,11 +157,21 @@ public void visitDstName(MappedElementKind targetKind, int namespace, String nam if (targetKind == MappedElementKind.CLASS) { writer.write(toJavaClassName(name)); writer.write(':'); + writer.write('\n'); } else { - writer.write(name); + pendingMemberData[2] = name; } + } - writer.write('\n'); + @Override + public void visitElementMetadata(MappedElementKind target, String key, int namespace, String value) { + StandardProperty property = StandardProperties.getById(key); + + if (property == StandardProperties.START_LINE_NUMBER) { + pendingMemberData[3] = value; + } else if (property == StandardProperties.END_LINE_NUMBER) { + pendingMemberData[4] = value; + } } @Override @@ -174,6 +179,63 @@ public void visitComment(MappedElementKind targetKind, String comment) throws IO // ignored } + @Override + public boolean visitEnd() throws IOException { + writePendingMember(); + return true; + } + + private void writePendingMember() throws IOException { + if (pendingMemberType == null) return; + String srcName = pendingMemberData[0]; + String srcDesc = pendingMemberData[1]; + String dstName = pendingMemberData[2]; + String startLine = pendingMemberData[3]; + String endLine = pendingMemberData[4]; + + writeIndent(); + + if (startLine != null && endLine != null) { + writer.write(startLine); + writer.write(':'); + writer.write(endLine); + writer.write(':'); + } + + if (pendingMemberType == MappedElementKind.FIELD) { + writer.write(toJavaType(srcDesc)); + writer.write(' '); + writer.write(srcName); + writeArrow(); + } else { + Type type = Type.getMethodType(srcDesc); + writer.write(toJavaType(type.getReturnType().getDescriptor())); + writer.write(' '); + writer.write(srcName); + writer.write('('); + Type[] args = type.getArgumentTypes(); + + for (int i = 0; i < args.length; i++) { + if (i > 0) { + writer.write(','); + } + + writer.write(toJavaType(args[i].getDescriptor())); + } + + writer.write(')'); + writeArrow(); + } + + if (dstName != null) { + writer.write(dstName); + writer.write('\n'); + } + + Arrays.fill(pendingMemberData, null); + pendingMemberType = null; + } + private void writeArrow() throws IOException { writer.write(" -> "); } diff --git a/src/main/java/net/fabricmc/mappingio/format/tsrg/TsrgFileReader.java b/src/main/java/net/fabricmc/mappingio/format/tsrg/TsrgFileReader.java index 8ef79883..9eb1def0 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tsrg/TsrgFileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tsrg/TsrgFileReader.java @@ -28,6 +28,8 @@ import net.fabricmc.mappingio.MappingUtil; import net.fabricmc.mappingio.MappingVisitor; import net.fabricmc.mappingio.format.ColumnFileReader; +import net.fabricmc.mappingio.format.StandardProperties; +import net.fabricmc.mappingio.tree.MappingTree; public final class TsrgFileReader { private TsrgFileReader() { @@ -185,8 +187,8 @@ private static void readMethod(ColumnFileReader reader, int dstNsCount, MappingV while (reader.nextLine(2)) { if (reader.hasExtraIndents()) continue; - if (reader.nextCol("static")) { - // method is static + if (reader.nextCol("static")) { // method is static + visitor.visitElementMetadata(MappedElementKind.METHOD, StandardProperties.IS_STATIC.getId(), MappingTree.SRC_NAMESPACE_ID, "true"); } else { int lvIndex = reader.nextIntCol(); if (lvIndex < 0) throw new IOException("missing/invalid parameter lv-index in line "+reader.getLineNumber()); diff --git a/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java b/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java index d096bae6..26b98001 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java @@ -82,11 +82,46 @@ default MethodMapping getMethod(String ownerName, String name, String desc, int interface MetadataEntry extends MetadataEntryView { } + interface ElementMetadataEntry extends ElementMetadataEntryView { + } + interface ElementMapping extends ElementMappingView { @Override MappingTree getTree(); void setDstName(String name, int namespace); + + /** + * @return A modifiable list of all metadata entries currently associated with the element. + * The list's order is equal to the order in which the entries have been originally added. + */ + @Override + List getMetadata(); + + /** + * @return An unmodifiable list of all metadata entries currently associated with the element + * whose key is equal to the passed one. + * The list's order is equal to the order in which the entries have been originally added. + */ + @Override + List getMetadata(String key); + + /** + * @return An unmodifiable list of all metadata entries currently associated with the element + * whose key and namespace are equal to the passed ones. + * The list's order is equal to the order in which the entries have been originally added. + */ + @Override + List getMetadata(String key, int namespace); + + void addMetadata(ElementMetadataEntry entry); + + /** + * Removes all metadata entries whose key is equal to the passed one. + * @return Whether or not any entries have been removed. + */ + boolean removeMetadata(String key); + void setComment(String comment); } diff --git a/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java b/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java index 154cf4d0..fc146a69 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java @@ -186,6 +186,16 @@ interface MetadataEntryView { String getValue(); } + interface ElementMetadataEntryView { + String getKey(); + + /** + * @return Values by namespace, offset by +1 (value for namespace x is at index x+1). + */ + String[] getValues(); + String getValue(int namespace); + } + interface ElementMappingView { MappingTreeView getTree(); @@ -210,6 +220,9 @@ default String getName(String namespace) { } } + List getMetadata(); + List getMetadata(String key); + List getMetadata(String key, int namespace); String getComment(); } diff --git a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java index c1529a66..d160bfa0 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java @@ -678,8 +678,17 @@ public boolean visitElementContent(MappedElementKind targetKind) throws IOExcept return targetKind != MappedElementKind.CLASS || currentClass.getSrcName() != null; // reject classes that never received a src name } + @Override + public void visitElementMetadata(MappedElementKind targetKind, String propertyKey, int namespace, String propertyValue) { + getCurrentEntry(targetKind).visitMetadata(propertyKey, namespace, propertyValue); + } + @Override public void visitComment(MappedElementKind targetKind, String comment) { + getCurrentEntry(targetKind).setComment(comment); + } + + private Entry getCurrentEntry(MappedElementKind targetKind) { Entry entry; switch (targetKind) { @@ -693,8 +702,8 @@ public void visitComment(MappedElementKind targetKind, String comment) { entry = currentEntry; } - if (entry == null) throw new UnsupportedOperationException("Tried to visit comment before owning target"); - entry.setComment(comment); + if (entry == null) throw new UnsupportedOperationException("Tried to visit element content before owning target"); + return entry; } abstract static class Entry> implements ElementMapping { @@ -736,6 +745,18 @@ public void setDstName(String name, int namespace) { void resizeDstNames(int newSize) { dstNames = Arrays.copyOf(dstNames, newSize); + + for (ElementMetadataEntry entry : metadata) { + String[] resizedValues = Arrays.copyOf(entry.getValues(), newSize); + + if (entry instanceof ElementMetadataEntryImpl) { + ElementMetadataEntryImpl impl = (ElementMetadataEntryImpl) entry; + impl.values = resizedValues; + } else { + metadata.add(metadata.indexOf(entry), new ElementMetadataEntryImpl(entry.getKey(), resizedValues)); + metadata.remove(entry); + } + } } void updateDstNames(int[] map) { @@ -752,6 +773,72 @@ void updateDstNames(int[] map) { dstNames = newDstNames; } + @Override + public List getMetadata() { + return metadata; + } + + @Override + public List getMetadata(String key) { + return Collections.unmodifiableList(metadata.stream() + .filter(entry -> entry.getKey().equals(key)) + .collect(Collectors.toList())); + } + + @Override + public List getMetadata(String key, int namespace) { + return Collections.unmodifiableList(metadata.stream() + .filter(entry -> entry.getKey().equals(key)) + .filter(entry -> entry.getValue(namespace) != null) + .collect(Collectors.toList())); + } + + @Override + public void addMetadata(ElementMetadataEntry entry) { + ElementMetadataEntry lastEntry; + + if (metadata.isEmpty() || !(lastEntry = metadata.get(metadata.size() - 1)).getKey().equals(entry.getKey())) { + metadata.add(entry); + return; + } + + for (int i = -1; i < entry.getValues().length - 1; i++) { + lastEntry = mergeMetadata(entry.getKey(), i, entry.getValue(i), lastEntry); + } + } + + void visitMetadata(String key, int namespace, String value) { + ElementMetadataEntry lastEntry; + + if (metadata.isEmpty() || !(lastEntry = metadata.get(metadata.size() - 1)).getKey().equals(key)) { + String[] values = new String[dstNames.length + 1]; + values[namespace + 1] = value; + metadata.add(new ElementMetadataEntryImpl(key, values)); + return; + } + + mergeMetadata(key, namespace, value, lastEntry); + } + + private ElementMetadataEntry mergeMetadata(String key, int namespace, String value, ElementMetadataEntry lastEntry) { + String[] values = lastEntry.getValues(); + + if (lastEntry.getValue(namespace) != null) { + // Can't merge, create new entry + values = new String[dstNames.length + 1]; + lastEntry = new ElementMetadataEntryImpl(key, values); + metadata.add(lastEntry); + } + + values[namespace + 1] = value; + return lastEntry; + } + + @Override + public boolean removeMetadata(String key) { + return metadata.removeIf(entry -> entry.getKey().equals(key)); + } + @Override public final String getComment() { return comment; @@ -783,6 +870,44 @@ protected final boolean acceptElement(MappingVisitor visitor, String[] dstDescs) return false; } + List metadataToVisit = metadata; + + if (visitor.getFlags().contains(MappingFlag.NEEDS_UNIQUENESS)) { + metadataToVisit = new LinkedList<>(); + Set addedKeys = new HashSet<>(); + + // Iterate last-to-first to construct a list of each key's latest occurrence. + for (int i = metadata.size() - 1; i >= 0; i--) { + ElementMetadataEntry entry = metadata.get(i); + + if (!addedKeys.contains(entry.getKey())) { + addedKeys.add(entry.getKey()); + metadataToVisit.add(0, entry); + } + } + } + + String lastKey = null; + String[] lastValues = null; + + for (ElementMetadataEntry entry : metadataToVisit) { + String[] values = entry.getValues(); + + for (int ns = -1; ns < values.length - 1; ns++) { + if (entry.getKey().equals(lastKey)) { + if (values[ns+1] == null && lastValues != null) { + // Fill in holes + values[ns+1] = lastValues[ns+1]; + } + } else { + lastKey = entry.getKey(); + } + + lastValues = values; + visitor.visitElementMetadata(kind, entry.getKey(), ns, entry.getValue(ns)); + } + } + if (comment != null) visitor.visitComment(kind, comment); return true; @@ -802,6 +927,7 @@ protected void copyFrom(T o, boolean replace) { // TODO: copy args+vars } + private final List metadata = new ArrayList<>(); protected String srcName; protected String[] dstNames; protected String comment; @@ -1745,6 +1871,47 @@ public int hashCode() { final String value; } + static final class ElementMetadataEntryImpl implements ElementMetadataEntry { + ElementMetadataEntryImpl(String key, String[] values) { + this.key = key; + this.values = values; + } + + @Override + public String getKey() { + return key; + } + + @Override + public String[] getValues() { + return values; + } + + public String getValue(int namespace) { + return values[namespace + 1]; + } + + @Override + public boolean equals(Object other) { + if (other == this) return true; + + if (!(other instanceof ElementMetadataEntryImpl)) { + return false; + } + + ElementMetadataEntryImpl entry = (ElementMetadataEntryImpl) other; + return this.key.equals(entry.key) && this.values.equals(entry.values); + } + + @Override + public int hashCode() { + return key.hashCode() | values.hashCode(); + } + + final String key; + String[] values; + } + static final class GlobalMemberKey { GlobalMemberKey(ClassEntry owner, String name, String desc, boolean isField) { this.owner = owner; diff --git a/src/test/java/net/fabricmc/mappingio/TestHelper.java b/src/test/java/net/fabricmc/mappingio/TestHelper.java index 195a02e9..f7930496 100644 --- a/src/test/java/net/fabricmc/mappingio/TestHelper.java +++ b/src/test/java/net/fabricmc/mappingio/TestHelper.java @@ -23,6 +23,7 @@ import java.util.Arrays; import net.fabricmc.mappingio.format.MappingFormat; +import net.fabricmc.mappingio.format.StandardProperties; import net.fabricmc.mappingio.tree.MappingTree; import net.fabricmc.mappingio.tree.MemoryMappingTree; @@ -41,17 +42,22 @@ public static MemoryMappingTree createTestTree() { tree.visitClass("class_1"); tree.visitDstName(MappedElementKind.CLASS, 0, "RenamedClass1"); + tree.visitElementMetadata(MappedElementKind.CLASS, StandardProperties.MODIFIED_ACCESS.getId(), 0, "public"); tree.visitField("field_1", "I"); tree.visitDstName(MappedElementKind.FIELD, 0, "renamedField"); + tree.visitElementMetadata(MappedElementKind.FIELD, StandardProperties.MODIFIED_ACCESS.getId(), 0, "protected"); tree.visitMethod("method_1", "(F)I"); tree.visitDstName(MappedElementKind.METHOD, 0, "renamedMethod"); + tree.visitElementMetadata(MappedElementKind.METHOD, StandardProperties.MODIFIED_ACCESS.getId(), 0, "private"); + tree.visitElementMetadata(MappedElementKind.METHOD, StandardProperties.START_LINE_NUMBER.getId(), 0, "20"); + tree.visitElementMetadata(MappedElementKind.METHOD, StandardProperties.END_LINE_NUMBER.getId(), 0, "25"); tree.visitMethodArg(0, 0, "param_1"); tree.visitDstName(MappedElementKind.METHOD_ARG, 0, "renamedParameter"); - tree.visitMethodVar(0, 0, 0, 0, "param_1"); + tree.visitMethodVar(0, 0, 0, 0, "var_1"); tree.visitDstName(MappedElementKind.METHOD_VAR, 0, "renamedVariable"); tree.visitClass("class_1$class_2"); diff --git a/src/test/java/net/fabricmc/mappingio/WriteTest.java b/src/test/java/net/fabricmc/mappingio/WriteTest.java index 9de0a4b0..65b1d20c 100644 --- a/src/test/java/net/fabricmc/mappingio/WriteTest.java +++ b/src/test/java/net/fabricmc/mappingio/WriteTest.java @@ -17,6 +17,7 @@ package net.fabricmc.mappingio; import java.nio.file.Path; +import java.nio.file.Paths; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -55,6 +56,11 @@ public void tinyV2File() throws Exception { write(MappingFormat.TINY_2_FILE); } + @Test + public void proguardFile() throws Exception { + write(MappingFormat.PROGUARD_FILE); + } + private void write(MappingFormat format) throws Exception { TestHelper.writeToDir(tree, format, dir); } From 3662dc4418ed35a9d9df0624ac3384255758f6eb Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Sun, 1 Oct 2023 17:29:21 +0200 Subject: [PATCH 21/22] Remove misleading comment --- .../net/fabricmc/mappingio/format/enigma/EnigmaWriterBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaWriterBase.java b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaWriterBase.java index 9ecd3bfb..818d27be 100644 --- a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaWriterBase.java +++ b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaWriterBase.java @@ -136,7 +136,7 @@ public void visitElementMetadata(MappedElementKind target, String key, int names StandardProperty property = StandardProperties.getById(key); if (property == null) return; - if (!property.isApplicableTo(getFormat(), target)) return; // How did it get there? + if (!property.isApplicableTo(getFormat(), target)) return; key = property.getNameFor(getFormat(), target); elementMetadata.put(property, value); From 40494fba0a651e508a00774169525d9bdf7ab1c1 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Sun, 1 Oct 2023 18:30:57 +0200 Subject: [PATCH 22/22] Remove unused import --- src/test/java/net/fabricmc/mappingio/WriteTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/net/fabricmc/mappingio/WriteTest.java b/src/test/java/net/fabricmc/mappingio/WriteTest.java index 65b1d20c..100e6890 100644 --- a/src/test/java/net/fabricmc/mappingio/WriteTest.java +++ b/src/test/java/net/fabricmc/mappingio/WriteTest.java @@ -17,7 +17,6 @@ package net.fabricmc.mappingio; import java.nio.file.Path; -import java.nio.file.Paths; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test;