From 1df71eefd76a07d32ee3924a4fd857dd8cb292fa Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Tue, 9 May 2023 23:26:26 +0200 Subject: [PATCH 01/15] 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 56e2517c..090e8c75 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java @@ -154,7 +154,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws } if (property != null) { - visitor.visitMetadata(property, parts[1]); + visitor.visitMetadata(property, parts[1], 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 bcdf2406..2df55782 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java @@ -58,7 +58,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 { switch (key) { case Tiny1FileReader.nextIntermediaryClassProperty: case Tiny1FileReader.nextIntermediaryFieldProperty: 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..6ee418f4 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java @@ -101,7 +101,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws escapeNames = true; } - 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 aee1bdc0..cd6d9787 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java @@ -59,7 +59,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 { if (key.equals(Tiny2Util.escapedNamesProperty)) { escapeNames = true; wroteEscapedNamesProperty = true; 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 135b5b6a17cf0e8e2f04b6961bd5f228b8ff4b8c Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Sun, 17 Sep 2023 19:51:15 +0200 Subject: [PATCH 02/15] 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 851f76ef4ae0c2fa5be073179dfcfbd56e85f6f0 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Mon, 18 Sep 2023 13:16:44 +0200 Subject: [PATCH 03/15] 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 090e8c75..56e2517c 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java @@ -154,7 +154,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws } if (property != null) { - visitor.visitMetadata(property, parts[1], true); + visitor.visitMetadata(property, parts[1]); } } } 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 2df55782..bcdf2406 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java @@ -58,7 +58,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 { switch (key) { case Tiny1FileReader.nextIntermediaryClassProperty: case Tiny1FileReader.nextIntermediaryFieldProperty: 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 6ee418f4..6381d80f 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java @@ -101,7 +101,7 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws escapeNames = true; } - 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 cd6d9787..aee1bdc0 100644 --- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java @@ -59,7 +59,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 { if (key.equals(Tiny2Util.escapedNamesProperty)) { escapeNames = true; wroteEscapedNamesProperty = true; 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 7d97832ec46ffb2a3d91d8ea2867c9944fae3161 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Mon, 18 Sep 2023 13:17:34 +0200 Subject: [PATCH 04/15] 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 147e66d08ca056d5d32e2774e5ed1e979e72ccc0 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Tue, 9 May 2023 20:36:12 +0200 Subject: [PATCH 05/15] 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 d6ac8079a9cbb1652f57d21c4118c684222271fd Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Tue, 9 May 2023 23:40:16 +0200 Subject: [PATCH 06/15] 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 4ed8276a42408b6e6cf074343c43e11b19366436 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Fri, 30 Jun 2023 18:57:19 +0200 Subject: [PATCH 07/15] 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 c6a24c16bbd4d5aca1ed02cd183f04d87157426f Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Fri, 15 Sep 2023 13:57:44 +0200 Subject: [PATCH 08/15] 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 7655a62e2254f947c74fb36321ea1aed601e64e1 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Mon, 18 Sep 2023 13:31:24 +0200 Subject: [PATCH 09/15] 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 c806abf102bc35c724127735c9c9639a397d5ce5 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Wed, 20 Sep 2023 09:43:53 +0200 Subject: [PATCH 10/15] 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 bd2057cb8e782a6fe45640063cb0a408aeb522ba Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Wed, 20 Sep 2023 09:58:08 +0200 Subject: [PATCH 11/15] 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 83d5d98bad8ee367d50b78686a4b588d96fd47f7 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Wed, 20 Sep 2023 10:13:40 +0200 Subject: [PATCH 12/15] 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 ef24ec84315e82bd9db9153cccb9e8ab9d59db0d Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Wed, 20 Sep 2023 09:27:01 +0200 Subject: [PATCH 13/15] Add per-element-metadata --- .../mappingio/FlatMappingVisitor.java | 99 +++++++++++++-- .../fabricmc/mappingio/MappingVisitor.java | 15 ++- .../adapter/FlatAsRegularMappingVisitor.java | 66 +++++++++- .../adapter/ForwardingMappingVisitor.java | 5 + .../adapter/MappingDstNsReorder.java | 9 ++ .../adapter/MappingSourceNsSwitch.java | 11 ++ .../adapter/RegularAsFlatMappingVisitor.java | 107 +++++++++++++++- .../mappingio/format/MappingFormat.java | 36 ++++-- .../mappingio/format/MioTempProperties.java | 29 +++++ .../mappingio/format/StandardProperties.java | 113 ++++++++++++++--- .../mappingio/format/StandardProperty.java | 11 ++ .../format/enigma/EnigmaFileReader.java | 120 +++++++++++++----- .../format/enigma/EnigmaFileWriter.java | 3 - .../format/enigma/EnigmaWriterBase.java | 44 ++++++- .../format/proguard/ProGuardFileReader.java | 11 +- .../format/proguard/ProGuardFileWriter.java | 112 ++++++++++++---- .../mappingio/format/tsrg/TsrgFileReader.java | 6 +- .../fabricmc/mappingio/tree/MappingTree.java | 3 + .../mappingio/tree/MappingTreeView.java | 3 + .../mappingio/tree/MemoryMappingTree.java | 39 +++++- 20 files changed, 725 insertions(+), 117 deletions(-) create mode 100644 src/main/java/net/fabricmc/mappingio/format/MioTempProperties.java 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..0a681934 100644 --- a/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java +++ b/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java @@ -18,7 +18,9 @@ import java.io.IOException; import java.util.Arrays; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Set; import net.fabricmc.mappingio.FlatMappingVisitor; @@ -75,7 +77,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 +88,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 +101,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 +114,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 +126,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 +141,7 @@ public boolean visitMethodVar(int lvtRowIndex, int lvIndex, int startOpIdx, int @Override public boolean visitEnd() throws IOException { + relayPendingElementMetadata(); return next.visitEnd(); } @@ -149,6 +157,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 +190,17 @@ public boolean visitElementContent(MappedElementKind targetKind) throws IOExcept return relay; } + @Override + public void visitElementMetadata(MappedElementKind targetKind, String key, int namespace, String value) { + String[] values = elementMetadata.getOrDefault(key, new String[dstNames.length + 1]); + values[namespace] = value; + elementMetadata.put(key, values); + } + @Override public void visitComment(MappedElementKind targetKind, String comment) throws IOException { + relayPendingElementMetadata(); + switch (targetKind) { case CLASS: next.visitClassComment(srcClsName, dstClassNames, comment); @@ -206,8 +224,46 @@ public void visitComment(MappedElementKind targetKind, String comment) throws IO } } + private void relayPendingElementMetadata() throws IOException { + if (elementMetadata.isEmpty()) return; + + for (Map.Entry entry : elementMetadata.entrySet()) { + String key = entry.getKey(); + String[] values = entry.getValue(); + + 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(); + } + } + + elementMetadata.clear(); + currentElementKind = null; + } + private final FlatMappingVisitor next; + private final LinkedHashMap elementMetadata = new LinkedHashMap<>(); + 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..153b3dc1 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 = -1; i < values.length; i++) { + String value = values[i]; + if (value != null) next.visitElementMetadata(targetKind, key, i, 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/MioTempProperties.java b/src/main/java/net/fabricmc/mappingio/format/MioTempProperties.java new file mode 100644 index 00000000..24747d69 --- /dev/null +++ b/src/main/java/net/fabricmc/mappingio/format/MioTempProperties.java @@ -0,0 +1,29 @@ +/* + * 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; + +/** + * Internal properties which mapping readers attach while parsing. + * They are removed again when saving via a {@link net.fabricmc.mappingio.MappingWriter MappingWriter}. + */ +public final class MioTempProperties { + public static final String MIO_PREFIX = "mio:"; + + private static String register(String name) { + return MIO_PREFIX + name; + } +} diff --git a/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java index 221525ab..8f89c6e8 100644 --- a/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java +++ b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java @@ -16,14 +16,19 @@ 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 java.util.stream.Collectors; import org.jetbrains.annotations.ApiStatus; +import net.fabricmc.mappingio.MappedElementKind; + public final class StandardProperties { private StandardProperties() { } @@ -47,6 +52,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<>(); @@ -57,68 +66,140 @@ public static StandardProperty getById(String id) { new HashMap() {{ put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER class"); put(MappingFormat.TINY_2_FILE, "next-intermediary-class"); - }}); + }}, + Collections.emptyMap()); NEXT_INTERMEDIARY_FIELD = register( "next-intermediary-field", new HashMap() {{ put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER field"); put(MappingFormat.TINY_2_FILE, "next-intermediary-field"); - }}); + }}, + Collections.emptyMap()); NEXT_INTERMEDIARY_METHOD = register( "next-intermediary-method", new HashMap() {{ put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER method"); put(MappingFormat.TINY_2_FILE, "next-intermediary-method"); - }}); + }}, + Collections.emptyMap()); NEXT_INTERMEDIARY_COMPONENT = register( "next-intermediary-component", new HashMap() {{ put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER component"); put(MappingFormat.TINY_2_FILE, "next-intermediary-component"); - }}); + }}, + Collections.emptyMap()); MISSING_LVT_INDICES = register( "missing-lvt-indices", new HashMap() {{ put(MappingFormat.TINY_2_FILE, "missing-lvt-indices"); - }}); + }}, + Collections.emptyMap()); ESCAPED_NAMES = register( "escaped-names", new HashMap() {{ put(MappingFormat.TINY_2_FILE, "escaped-names"); + }}, + Collections.emptyMap()); + MODIFIED_ACCESS = register( + "modified-access", + Collections.emptyMap(), + new HashMap, String>() {{ + put(new SimpleEntry<>(MappingFormat.ENIGMA_FILE, MappedElementKind.CLASS), "ACC:"); + put(new SimpleEntry<>(MappingFormat.ENIGMA_FILE, MappedElementKind.FIELD), "ACC:"); + put(new SimpleEntry<>(MappingFormat.ENIGMA_FILE, MappedElementKind.METHOD), "ACC:"); + put(new SimpleEntry<>(MappingFormat.ENIGMA_DIR, MappedElementKind.CLASS), "ACC:"); + put(new SimpleEntry<>(MappingFormat.ENIGMA_DIR, MappedElementKind.FIELD), "ACC:"); + put(new SimpleEntry<>(MappingFormat.ENIGMA_DIR, MappedElementKind.METHOD), "ACC:"); + }}); + IS_STATIC = register( + "is-static", + Collections.emptyMap(), + new HashMap, String>() {{ + put(new SimpleEntry<>(MappingFormat.TSRG_2_FILE, MappedElementKind.METHOD), "static"); + }}); + START_LINE_NUMBER = register( + "start-line-number", + Collections.emptyMap(), + new HashMap, String>() {{ + put(new SimpleEntry<>(MappingFormat.PROGUARD_FILE, MappedElementKind.FIELD), null); + put(new SimpleEntry<>(MappingFormat.PROGUARD_FILE, MappedElementKind.FIELD), null); + }}); + END_LINE_NUMBER = register( + "end-line-number", + Collections.emptyMap(), + new HashMap, String>() {{ + put(new SimpleEntry<>(MappingFormat.PROGUARD_FILE, MappedElementKind.FIELD), null); + put(new SimpleEntry<>(MappingFormat.PROGUARD_FILE, MappedElementKind.FIELD), null); }}); } - private static StandardProperty register(String id, Map nameByFormat) { - StandardProperty ret = new StandardPropertyImpl(id, nameByFormat); + private static StandardProperty register(String id, Map filePropNameByFormat, + Map, String> elementPropNameByFormat) { + StandardProperty ret = new StandardPropertyImpl(id, filePropNameByFormat, elementPropNameByFormat); values.add(ret); valuesById.put(id, ret); - for (String name : nameByFormat.values()) { + for (String name : filePropNameByFormat.values()) { + valuesByName.putIfAbsent(name, ret); + } + + for (String name : elementPropNameByFormat.values()) { valuesByName.putIfAbsent(name, ret); } return ret; } - private static class StandardPropertyImpl implements StandardProperty { - StandardPropertyImpl(String id, Map nameByFormat) { + static class StandardPropertyImpl implements StandardProperty { + StandardPropertyImpl(String id, Map filePropNameByFormat, + Map, String> elementPropNameByFormat) { this.id = id; - this.nameByFormat = nameByFormat; + this.filePropNameByFormat = filePropNameByFormat; + this.elementPropNameByFormat = elementPropNameByFormat; + this.propElementKindByFormat = elementPropNameByFormat.entrySet().stream() + .map(entry -> entry.getKey()) + .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); + } + + @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 @@ -127,6 +208,8 @@ public String getId() { } private final String id; - private final Map nameByFormat; + private final Map filePropNameByFormat; + private final Map, String> elementPropNameByFormat; + private final Map propElementKindByFormat; } } 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/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..c568e349 100644 --- a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileWriter.java +++ b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileWriter.java @@ -33,9 +33,6 @@ public boolean visitElementContent(MappedElementKind targetKind) throws IOExcept } else if (targetKind == MappedElementKind.FIELD || targetKind == MappedElementKind.METHOD) { writer.write(' '); writer.write(desc); - writer.write('\n'); - } else { - writer.write('\n'); } return true; 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..9490e5c9 100644 --- a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaWriterBase.java +++ b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaWriterBase.java @@ -19,12 +19,16 @@ 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.StandardProperties; abstract class EnigmaWriterBase implements MappingWriter { EnigmaWriterBase(Writer writer) throws IOException { @@ -46,12 +50,14 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) { } @Override public boolean visitClass(String srcName) throws IOException { + writePendingElementMetadata(); srcClassName = srcName; return true; } @Override public boolean visitField(String srcName, String srcDesc) throws IOException { + writePendingElementMetadata(); writeIndent(0); writer.write("FIELD "); writer.write(srcName); @@ -63,6 +69,7 @@ public boolean visitField(String srcName, String srcDesc) throws IOException { @Override public boolean visitMethod(String srcName, String srcDesc) throws IOException { + writePendingElementMetadata(); writeIndent(0); writer.write("METHOD "); writer.write(srcName); @@ -74,6 +81,7 @@ public boolean visitMethod(String srcName, String srcDesc) throws IOException { @Override public boolean visitMethodArg(int argPosition, int lvIndex, String srcName) throws IOException { + writePendingElementMetadata(); writeIndent(1); writer.write("ARG "); writer.write(Integer.toString(lvIndex)); @@ -82,12 +90,14 @@ 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 { + writePendingElementMetadata(); return false; } @Override public boolean visitEnd() throws IOException { + writePendingElementMetadata(); close(); return true; @@ -108,6 +118,11 @@ public void visitDstName(MappedElementKind targetKind, int namespace, String nam @Override public abstract boolean visitElementContent(MappedElementKind targetKind) throws IOException; + @Override + public void visitElementMetadata(MappedElementKind target, String key, int namespace, String value) { + if (namespace == 0) elementMetadata.put(key, value); + } + protected static int getNextOuterEnd(String name, int startPos) { int pos; @@ -121,6 +136,7 @@ protected static int getNextOuterEnd(String name, int startPos) { @Override public void visitComment(MappedElementKind targetKind, String comment) throws IOException { + writePendingElementMetadata(); int start = 0; int pos; @@ -203,15 +219,38 @@ protected void writeMismatchedOrMissingClasses() throws IOException { dstName = null; } + protected void writePendingElementMetadata() throws IOException { + if (!elementMetadata.isEmpty()) { + for (Map.Entry entry : elementMetadata.entrySet()) { + String key = entry.getKey(); + if (StandardProperties.getById(key) != StandardProperties.MODIFIED_ACCESS) continue; + + writer.write(key); + writer.write(" ACC:"); + writer.write(entry.getValue().toUpperCase(Locale.ROOT)); + break; + } + + elementMetadata.clear(); + } + + writer.write('\n'); + } + protected void writeIndent(int extra) throws IOException { for (int i = 0; i < indent + extra; i++) { writer.write('\t'); } } - protected static final Set flags = EnumSet.of(MappingFlag.NEEDS_UNIQUENESS, MappingFlag.NEEDS_SRC_FIELD_DESC, MappingFlag.NEEDS_SRC_METHOD_DESC); + protected static final Set flags = EnumSet.of( + MappingFlag.NEEDS_HEADER_METADATA, + 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 +259,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..b53c144b 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,22 @@ 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) { + assert target == pendingMemberType; + 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 +180,62 @@ 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 startLine = pendingMemberData[2]; + String endLine = pendingMemberData[3]; + + writeIndent(); + + if (startLine != 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 (pendingMemberData[2] != null) { + writer.write(pendingMemberData[2]); + 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 b99d749b..e26aa085 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java @@ -64,6 +64,9 @@ interface ElementMapping extends ElementMappingView { MappingTree getTree(); void setDstName(String name, int namespace); + + void addMetadata(String key, int namespace, String value); + String[] 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 3de70989..77f4895e 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java @@ -206,6 +206,9 @@ default String getName(String namespace) { } } + Collection> getMetadata(); + String[] getMetadata(String key); + String 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 8a77cc42..be3dab61 100644 --- a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java +++ b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java @@ -654,8 +654,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).addMetadata(propertyKey, namespace, propertyValue); + } + @Override public void visitComment(MappedElementKind targetKind, String comment) { + getCurrentEntry(targetKind).setComment(comment); + } + + private Entry getCurrentEntry(MappedElementKind targetKind) { Entry entry; switch (targetKind) { @@ -670,7 +679,7 @@ public void visitComment(MappedElementKind targetKind, String comment) { } if (entry == null) throw new UnsupportedOperationException("Tried to visit comment before owning target"); - entry.setComment(comment); + return entry; } abstract static class Entry> implements ElementMapping { @@ -728,6 +737,33 @@ void updateDstNames(int[] map) { dstNames = newDstNames; } + @Override + public Collection> getMetadata() { + return Collections.unmodifiableSet(metadata.entrySet()); + } + + @Override + public String[] getMetadata(String key) { + return metadata.get(key); + } + + @Override + public String getMetadata(String key, int namespace) { + return metadata.get(key)[namespace]; + } + + @Override + public void addMetadata(String key, int namespace, String value) { + String[] values = metadata.getOrDefault(key, new String[dstNames.length + 1]); + values[namespace] = value; + metadata.put(key, values); + } + + @Override + public String[] removeMetadata(String key) { + return metadata.remove(key); + } + @Override public final String getComment() { return comment; @@ -778,6 +814,7 @@ protected void copyFrom(T o, boolean replace) { // TODO: copy args+vars } + private final Map metadata = new HashMap<>(); protected String srcName; protected String[] dstNames; protected String comment; From f8d2c6d46c16d743373efe9c310450a2626c798b Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Tue, 16 May 2023 12:22:15 +0200 Subject: [PATCH 14/15] Add preliminary `.match` file reader --- .../net/fabricmc/mappingio/MappingReader.java | 6 + .../mappingio/format/MappingFormat.java | 3 +- .../format/match/MatchFileReader.java | 148 ++++++++++++++++++ 3 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 src/main/java/net/fabricmc/mappingio/format/match/MatchFileReader.java diff --git a/src/main/java/net/fabricmc/mappingio/MappingReader.java b/src/main/java/net/fabricmc/mappingio/MappingReader.java index 65dae0b4..fd6e1b1d 100644 --- a/src/main/java/net/fabricmc/mappingio/MappingReader.java +++ b/src/main/java/net/fabricmc/mappingio/MappingReader.java @@ -29,6 +29,7 @@ import net.fabricmc.mappingio.format.MappingFormat; import net.fabricmc.mappingio.format.enigma.EnigmaDirReader; import net.fabricmc.mappingio.format.enigma.EnigmaFileReader; +import net.fabricmc.mappingio.format.match.MatchFileReader; import net.fabricmc.mappingio.format.proguard.ProGuardFileReader; import net.fabricmc.mappingio.format.srg.SrgFileReader; import net.fabricmc.mappingio.format.tiny.Tiny1FileReader; @@ -75,6 +76,8 @@ public static MappingFormat detectFormat(Reader reader) throws IOException { case "MD:": case "FD:": return MappingFormat.SRG_FILE; + case "Mat": + return MappingFormat.MATCH_FILE; } String headerStr = String.valueOf(buffer, 0, pos); @@ -200,6 +203,9 @@ public static void read(Reader reader, MappingFormat format, MappingVisitor visi case PROGUARD_FILE: ProGuardFileReader.read(reader, visitor); break; + case MATCH_FILE: + MatchFileReader.read(reader, visitor); + break; default: throw new IllegalStateException(); } diff --git a/src/main/java/net/fabricmc/mappingio/format/MappingFormat.java b/src/main/java/net/fabricmc/mappingio/format/MappingFormat.java index 66d87e46..cb318c4c 100644 --- a/src/main/java/net/fabricmc/mappingio/format/MappingFormat.java +++ b/src/main/java/net/fabricmc/mappingio/format/MappingFormat.java @@ -25,7 +25,8 @@ public enum MappingFormat { 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); + PROGUARD_FILE("ProGuard file", "map", false, true, false, false, false, MetadataSupport.NONE, MetadataSupport.HARDCODED), + MATCH_FILE("Match file", "match", false, true, false, true, true, MetadataSupport.HARDCODED, MetadataSupport.HARDCODED); MappingFormat(String name, String fileExt, boolean hasNamespaces, boolean hasFieldDescriptors, diff --git a/src/main/java/net/fabricmc/mappingio/format/match/MatchFileReader.java b/src/main/java/net/fabricmc/mappingio/format/match/MatchFileReader.java new file mode 100644 index 00000000..76251fa8 --- /dev/null +++ b/src/main/java/net/fabricmc/mappingio/format/match/MatchFileReader.java @@ -0,0 +1,148 @@ +/* + * 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.match; + +import java.io.IOException; +import java.io.Reader; +import java.util.Arrays; + +import net.fabricmc.mappingio.MappedElementKind; +import net.fabricmc.mappingio.MappingFlag; +import net.fabricmc.mappingio.MappingVisitor; +import net.fabricmc.mappingio.format.ColumnFileReader; + +public class MatchFileReader { + public static void read(Reader reader, MappingVisitor visitor) throws IOException { + read(new ColumnFileReader(reader, '\t'), visitor); + } + + private static void read(ColumnFileReader reader, MappingVisitor visitor) throws IOException { + if (!reader.nextCol().startsWith("Matches saved")) { + throw new IOException("invalid/unsupported match file: incorrect header"); + } + + if (visitor.getFlags().contains(MappingFlag.NEEDS_MULTIPLE_PASSES)) { + reader.mark(); + } + + boolean escapeNames = false; + + for (;;) { + boolean visitHeader = visitor.visitHeader(); + + if (visitHeader) { + visitor.visitNamespaces("a", Arrays.asList("b")); + } + + if (visitor.visitContent()) { + while (reader.nextLine(0)) { + if (reader.nextCol("c")) { // class: c + String srcName = reader.nextCol(escapeNames); + if (srcName == null || srcName.isEmpty()) throw new IOException("missing class-name-a in line "+reader.getLineNumber()); + + if (visitor.visitClass(srcName)) { + readClass(reader, escapeNames, visitor); + } + } + } + } + + if (visitor.visitEnd()) break; + + reader.reset(); + } + } + + private static void readClass(ColumnFileReader reader, boolean escapeNames, MappingVisitor visitor) throws IOException { + visitor.visitDstName(MappedElementKind.CLASS, 0, reader.nextCol(escapeNames)); + if (!visitor.visitElementContent(MappedElementKind.CLASS)) return; + + while (reader.nextLine(1)) { + boolean field = false; + boolean method = false; + + if ((field = reader.nextCol("f")) || (method = reader.nextCol("m"))) { + // field: f + // method: m (but no spaces between name and desc) + + String[] from; + String[] to; + + if (field) { + from = reader.nextCol(escapeNames).split(";;"); + to = reader.nextCol(escapeNames).split(";;"); + } else { + from = toMethodArray(reader.nextCol(escapeNames)); + to = toMethodArray(reader.nextCol(escapeNames)); + } + + if (from.length != 2 || to.length != 2) throw new IOException("invalid member mapping in line "+reader.getLineNumber()); + + String srcName = from[0]; + String srcDesc = from[1]; + String dstName = to[0]; + String dstDesc = to[1]; + + if (field && visitor.visitField(srcName, srcDesc)) { + visitor.visitDstName(MappedElementKind.FIELD, 0, dstName); + visitor.visitDstDesc(MappedElementKind.FIELD, 0, dstDesc); + } else if (method && visitor.visitMethod(srcName, srcDesc)) { + visitor.visitDstName(MappedElementKind.METHOD, 0, dstName); + visitor.visitDstDesc(MappedElementKind.METHOD, 0, dstDesc); + readMethodContent(reader, escapeNames, visitor); + } + } else if (reader.nextCol("c")) { // comment: c + readComment(reader, MappedElementKind.CLASS, visitor); + } + } + } + + private static String[] toMethodArray(String nameWithDescriptor) { + int parenPos = nameWithDescriptor.indexOf('('); + return new String[] { + nameWithDescriptor.substring(0, parenPos), + nameWithDescriptor.substring(parenPos) + }; + } + + private static void readMethodContent(ColumnFileReader reader, boolean escapeNames, MappingVisitor visitor) throws IOException { + if (!visitor.visitElementContent(MappedElementKind.METHOD)) return; + + while (reader.nextLine(2)) { + if (reader.nextCol("ma")) { + // method arg: ma + + int srcArgPos = reader.nextIntCol(); + int dstArgPos = reader.nextIntCol(); + if (srcArgPos < 0 || dstArgPos < 0) throw new IOException("missing/invalid method arg position in line "+reader.getLineNumber()); + + if (visitor.visitMethodArg(srcArgPos, -1, null)) { + // TODO: Implement once per-element metadata is supported + } + } else if (reader.nextCol("c")) { // comment: c + readComment(reader, MappedElementKind.METHOD, visitor); + } + } + } + + private static void readComment(ColumnFileReader reader, MappedElementKind subjectKind, MappingVisitor visitor) throws IOException { + String comment = reader.nextEscapedCol(); + if (comment == null) throw new IOException("missing comment in line "+reader.getLineNumber()); + + visitor.visitComment(subjectKind, comment); + } +} From 4fa08028d79ba67e91d29505d5c655a944545c27 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Wed, 20 Sep 2023 11:41:24 +0200 Subject: [PATCH 15/15] Complete parameter support --- .../net/fabricmc/mappingio/format/StandardProperties.java | 7 +++++++ .../fabricmc/mappingio/format/match/MatchFileReader.java | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java index 8f89c6e8..1280a65e 100644 --- a/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java +++ b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java @@ -56,6 +56,7 @@ public static StandardProperty getById(String id) { public static final StandardProperty IS_STATIC; public static final StandardProperty START_LINE_NUMBER; public static final StandardProperty END_LINE_NUMBER; + public static final StandardProperty PARAM_DEST_POS; private static final Set values = new HashSet<>(); private static final Map valuesByName = new HashMap<>(); private static final Map valuesById = new HashMap<>(); @@ -132,6 +133,12 @@ public static StandardProperty getById(String id) { put(new SimpleEntry<>(MappingFormat.PROGUARD_FILE, MappedElementKind.FIELD), null); put(new SimpleEntry<>(MappingFormat.PROGUARD_FILE, MappedElementKind.FIELD), null); }}); + PARAM_DEST_POS = register( + "parameter-destination-position", + Collections.emptyMap(), + new HashMap, String>() {{ + put(new SimpleEntry<>(MappingFormat.MATCH_FILE, MappedElementKind.METHOD_ARG), null); + }}); } private static StandardProperty register(String id, Map filePropNameByFormat, diff --git a/src/main/java/net/fabricmc/mappingio/format/match/MatchFileReader.java b/src/main/java/net/fabricmc/mappingio/format/match/MatchFileReader.java index 76251fa8..726e134d 100644 --- a/src/main/java/net/fabricmc/mappingio/format/match/MatchFileReader.java +++ b/src/main/java/net/fabricmc/mappingio/format/match/MatchFileReader.java @@ -24,6 +24,7 @@ import net.fabricmc.mappingio.MappingFlag; import net.fabricmc.mappingio.MappingVisitor; import net.fabricmc.mappingio.format.ColumnFileReader; +import net.fabricmc.mappingio.format.StandardProperties; public class MatchFileReader { public static void read(Reader reader, MappingVisitor visitor) throws IOException { @@ -131,7 +132,7 @@ private static void readMethodContent(ColumnFileReader reader, boolean escapeNam if (srcArgPos < 0 || dstArgPos < 0) throw new IOException("missing/invalid method arg position in line "+reader.getLineNumber()); if (visitor.visitMethodArg(srcArgPos, -1, null)) { - // TODO: Implement once per-element metadata is supported + visitor.visitElementMetadata(MappedElementKind.METHOD_ARG, StandardProperties.PARAM_DEST_POS.getId(), 0, String.valueOf(dstArgPos)); } } else if (reader.nextCol("c")) { // comment: c readComment(reader, MappedElementKind.METHOD, visitor);