From b2f095cc2e8857834b0daf4f171bec6d6e6465ff Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Wed, 6 Dec 2023 09:59:21 +0100 Subject: [PATCH 1/5] Add Mapping-IO converters --- gradle/libs.versions.toml | 4 + io-mappingio/build.gradle | 21 ++++ .../feather/io/mappingio/MdcToMio.java | 78 ++++++++++++ .../feather/io/mappingio/MioToMdc.java | 112 ++++++++++++++++++ io-tests/build.gradle | 3 + settings.gradle | 2 + 6 files changed, 220 insertions(+) create mode 100644 io-mappingio/build.gradle create mode 100644 io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MdcToMio.java create mode 100644 io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MioToMdc.java diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ab9d448..3b6b98e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,6 +6,8 @@ guava = '32.0.1-jre' # IO subproject dependencies gson = '2.10.1' moshi = '1.12.0' # Fixed to 1.12.0 because that's the last version written in Java +mappingio = '0.5.1' +jetbrains-annotations = '24.0.1' # Test engine junit = '5.9.3' @@ -16,6 +18,8 @@ guava = { module = 'com.google.guava:guava', version.ref = 'guava' } gson = { module = 'com.google.code.gson:gson', version.ref = 'gson' } moshi = { module = 'com.squareup.moshi:moshi', version.ref = 'moshi' } +mappingio = { module = 'net.fabricmc:mapping-io', version.ref = 'mappingio' } +jetbrains-annotations = { module = 'org.jetbrains:annotations', version.ref = 'jetbrains-annotations' } junit-api = { module = 'org.junit.jupiter:junit-jupiter-api', version.ref = 'junit' } junit-engine = { module = 'org.junit.jupiter:junit-jupiter-engine', version.ref = 'junit' } diff --git a/io-mappingio/build.gradle b/io-mappingio/build.gradle new file mode 100644 index 0000000..847b8a1 --- /dev/null +++ b/io-mappingio/build.gradle @@ -0,0 +1,21 @@ +group = 'org.parchmentmc.feather' +archivesBaseName = 'io-mappingio' + +dependencies { + api project(':feather') + api libs.mappingio + + compileOnly libs.jetbrains.annotations + + testFixturesApi testFixtures(project(':feather')) +} + +publishing { + publications.create("mappingioIO", MavenPublication) { + from components.java + pom { + name = "Feather IO - Mapping-IO" + description = "Additional IO library for serializing various deobfuscation mapping formats using Mapping-IO." + } + } +} diff --git a/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MdcToMio.java b/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MdcToMio.java new file mode 100644 index 0000000..3a66d17 --- /dev/null +++ b/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MdcToMio.java @@ -0,0 +1,78 @@ +package org.parchmentmc.feather.io.mappingio; + +import net.fabricmc.mappingio.MappedElementKind; +import net.fabricmc.mappingio.MappingVisitor; +import net.fabricmc.mappingio.tree.MappingTree; +import net.fabricmc.mappingio.tree.MemoryMappingTree; +import org.parchmentmc.feather.mapping.MappingDataContainer; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +public class MdcToMio { + /** + * Constructs a new {@link MappingTree} from a given {@link MappingDataContainer}'s content. + * All data is added to the source namespace. + * + * @param mdc The {@link MappingDataContainer} to read from. + * @param srcNs The source namespace to use for the tree. + * @throws IOException If an I/O error occurs. + */ + public static MappingTree toTree(MappingDataContainer mdc, String srcNs) throws IOException { + MemoryMappingTree tree = new MemoryMappingTree(); + accept(mdc, tree, srcNs); + return tree; + } + + /** + * Reads mapping data from a given {@link MappingDataContainer} and passes it to a {@link MappingVisitor} (on the source namespace). + * + * @param mdc The {@link MappingDataContainer} to read from. + * @param srcNs The source namespace to pass to the visitor. + * @throws IOException If an I/O error occurs. + */ + public static void accept(MappingDataContainer mdc, MappingVisitor visitor, String srcNs) throws IOException { + if (visitor.visitHeader()) { + visitor.visitNamespaces(srcNs, Collections.emptyList()); + } + + if (visitor.visitContent()) { + for (MappingDataContainer.ClassData cls : mdc.getClasses()) { + if (!visitor.visitClass(cls.getName())) continue; + if (!visitor.visitElementContent(MappedElementKind.CLASS)) continue; + + if (!cls.getJavadoc().isEmpty()) { + visitor.visitComment(MappedElementKind.CLASS, joinComment(cls.getJavadoc())); + } + + for (MappingDataContainer.FieldData fld : cls.getFields()) { + if (!visitor.visitField(fld.getName(), fld.getDescriptor())) continue; + if (!visitor.visitElementContent(MappedElementKind.FIELD)) continue; + + if (!fld.getJavadoc().isEmpty()) { + visitor.visitComment(MappedElementKind.FIELD, joinComment(fld.getJavadoc())); + } + } + + for (MappingDataContainer.MethodData mth : cls.getMethods()) { + if (!visitor.visitMethod(mth.getName(), mth.getDescriptor())) continue; + if (!visitor.visitElementContent(MappedElementKind.METHOD)) continue; + + if (!mth.getJavadoc().isEmpty()) { + visitor.visitComment(MappedElementKind.FIELD, joinComment(mth.getJavadoc())); + } + + for (MappingDataContainer.ParameterData arg : mth.getParameters()) { + if (!visitor.visitMethodArg(-1, arg.getIndex(), arg.getName())) continue; + if (!visitor.visitElementContent(MappedElementKind.METHOD_ARG)) continue; + } + } + } + } + } + + private static String joinComment(List commentLines) { + return String.join("\n", commentLines); + } +} diff --git a/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MioToMdc.java b/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MioToMdc.java new file mode 100644 index 0000000..f6225e2 --- /dev/null +++ b/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MioToMdc.java @@ -0,0 +1,112 @@ +package org.parchmentmc.feather.io.mappingio; + +import net.fabricmc.mappingio.FlatMappingVisitor; +import net.fabricmc.mappingio.MappingReader; +import net.fabricmc.mappingio.adapter.FlatAsRegularMappingVisitor; +import net.fabricmc.mappingio.tree.MappingTreeView; +import org.jetbrains.annotations.Nullable; +import org.parchmentmc.feather.mapping.MappingDataBuilder; +import org.parchmentmc.feather.mapping.MappingDataContainer; + +import java.io.IOException; +import java.io.Reader; +import java.nio.file.Path; +import java.util.List; + +public class MioToMdc { + public static MappingDataContainer fromPath(Path path) throws IOException { + ConvertingVisitor converter = new ConvertingVisitor(); + MappingReader.read(path, new FlatAsRegularMappingVisitor(converter)); + return converter.getResult(); + } + + public static MappingDataContainer fromReader(Reader reader) throws IOException { + ConvertingVisitor converter = new ConvertingVisitor(); + MappingReader.read(reader, new FlatAsRegularMappingVisitor(converter)); + return converter.getResult(); + } + + public static MappingDataContainer fromTree(MappingTreeView tree) throws IOException { + ConvertingVisitor converter = new ConvertingVisitor(); + tree.accept(new FlatAsRegularMappingVisitor(converter)); + return converter.getResult(); + } + + private static class ConvertingVisitor implements FlatMappingVisitor { + MappingDataBuilder mdcBuilder = new MappingDataBuilder(); + MappingDataBuilder.MutableClassData cls; + MappingDataBuilder.MutableFieldData fld; + MappingDataBuilder.MutableMethodData mth; + MappingDataBuilder.MutableParameterData arg; + + @Override + public void visitNamespaces(String srcNamespace, List dstNamespaces) throws IOException { + } + + @Override + public boolean visitClass(String srcName, String[] dstNames) throws IOException { + cls = mdcBuilder.getOrCreateClass(srcName); + + return true; + } + + @Override + public void visitClassComment(String srcName, String[] dstNames, String comment) throws IOException { + cls.addJavadoc(splitComment(comment)); + } + + @Override + public boolean visitField(String srcClsName, String srcName, @Nullable String srcDesc, @Nullable String[] dstClsNames, @Nullable String[] dstNames, @Nullable String[] dstDescs) throws IOException { + fld = cls.getOrCreateField(srcName, srcDesc); + + return true; + } + + @Override + public void visitFieldComment(String srcClsName, String srcName, @Nullable String srcDesc, @Nullable String[] dstClsNames, @Nullable String[] dstNames, @Nullable String[] dstDescs, String comment) throws IOException { + fld.addJavadoc(splitComment(comment)); + } + + @Override + public boolean visitMethod(String srcClsName, String srcName, @Nullable String srcDesc, @Nullable String[] dstClsNames, @Nullable String[] dstNames, @Nullable String[] dstDescs) throws IOException { + mth = cls.getOrCreateMethod(srcName, srcDesc); + + return true; + } + + @Override + public void visitMethodComment(String srcClsName, String srcName, @Nullable String srcDesc, @Nullable String[] dstClsNames, @Nullable String[] dstNames, @Nullable String[] dstDescs, String comment) throws IOException { + mth.addJavadoc(splitComment(comment)); + } + + @Override + public boolean visitMethodArg(String srcClsName, String srcMethodName, @Nullable String srcMethodDesc, int argPosition, int lvIndex, @Nullable String srcName, @Nullable String[] dstClsNames, @Nullable String[] dstMethodNames, @Nullable String[] dstMethodDescs, String[] dstNames) throws IOException { + if (lvIndex > Byte.MAX_VALUE) throw new IOException("Feather doesn't support lvIndices larger than " + Byte.MAX_VALUE); + arg = mth.getOrCreateParameter((byte) lvIndex); + + return false; + } + + @Override + public void visitMethodArgComment(String srcClsName, String srcMethodName, @Nullable String srcMethodDesc, int argPosition, int lvIndex, @Nullable String srcName, @Nullable String[] dstClsNames, @Nullable String[] dstMethodNames, @Nullable String[] dstMethodDescs, @Nullable String[] dstNames, String comment) throws IOException { + arg.addJavadoc(splitComment(comment)); + } + + @Override + public boolean visitMethodVar(String srcClsName, String srcMethodName, @Nullable String srcMethodDesc, int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, @Nullable String srcName, @Nullable String[] dstClsNames, @Nullable String[] dstMethodNames, @Nullable String[] dstMethodDescs, String[] dstNames) throws IOException { + return false; + } + + @Override + public void visitMethodVarComment(String srcClsName, String srcMethodName, @Nullable String srcMethodDesc, int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, @Nullable String srcName, @Nullable String[] dstClsNames, @Nullable String[] dstMethodNames, @Nullable String[] dstMethodDescs, @Nullable String[] dstNames, String comment) throws IOException { + } + + MappingDataContainer getResult() { + return mdcBuilder; + } + } + + private static String[] splitComment(String comment) { + return comment.split("\n"); + } +} diff --git a/io-tests/build.gradle b/io-tests/build.gradle index a126b13..afd4ebd 100644 --- a/io-tests/build.gradle +++ b/io-tests/build.gradle @@ -10,4 +10,7 @@ dependencies { implementation project(':io-moshi') testImplementation testFixtures(project(':io-moshi')) + + implementation project(':io-mappingio') + testImplementation testFixtures(project(':io-mappingio')) } diff --git a/settings.gradle b/settings.gradle index 8a36db7..c5a93ea 100644 --- a/settings.gradle +++ b/settings.gradle @@ -15,6 +15,8 @@ include 'io-moshi' project(':io-moshi').name = 'io-moshi' include 'io-gson' project(':io-gson').name = 'io-gson' +include 'io-mappingio' +project(':io-mappingio').name = 'io-mappingio' include 'io-proguard' project(':io-proguard').name = 'io-proguard' include 'io-tests' From 5c5ca1a1b7401b234d113ee049c146a44d8a1bd1 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Wed, 6 Dec 2023 10:09:16 +0100 Subject: [PATCH 2/5] Don't forget parameter comments --- .../java/org/parchmentmc/feather/io/mappingio/MdcToMio.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MdcToMio.java b/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MdcToMio.java index 3a66d17..d6faa81 100644 --- a/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MdcToMio.java +++ b/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MdcToMio.java @@ -66,6 +66,10 @@ public static void accept(MappingDataContainer mdc, MappingVisitor visitor, Stri for (MappingDataContainer.ParameterData arg : mth.getParameters()) { if (!visitor.visitMethodArg(-1, arg.getIndex(), arg.getName())) continue; if (!visitor.visitElementContent(MappedElementKind.METHOD_ARG)) continue; + + if (arg.getJavadoc() != null) { + visitor.visitComment(MappedElementKind.METHOD_ARG, arg.getJavadoc()); + } } } } From 7ca1199bc059760b95a8533ab9fab45f5f415422 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Wed, 6 Dec 2023 11:11:46 +0100 Subject: [PATCH 3/5] Fix incorrect return value --- .../java/org/parchmentmc/feather/io/mappingio/MioToMdc.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MioToMdc.java b/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MioToMdc.java index f6225e2..feaa6d5 100644 --- a/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MioToMdc.java +++ b/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MioToMdc.java @@ -84,7 +84,7 @@ public boolean visitMethodArg(String srcClsName, String srcMethodName, @Nullable if (lvIndex > Byte.MAX_VALUE) throw new IOException("Feather doesn't support lvIndices larger than " + Byte.MAX_VALUE); arg = mth.getOrCreateParameter((byte) lvIndex); - return false; + return true; } @Override From 94453f1c421a17859a33abe6ddf379fbbc77a52e Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Wed, 6 Dec 2023 11:12:22 +0100 Subject: [PATCH 4/5] Add test --- io-mappingio/build.gradle | 1 + .../feather/io/mappingio/MappingIOTest.java | 42 +++ .../io/mappingio/SubsetAssertingVisitor.java | 246 ++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 io-mappingio/src/test/java/org/parchmentmc/feather/io/mappingio/MappingIOTest.java create mode 100644 io-mappingio/src/test/java/org/parchmentmc/feather/io/mappingio/SubsetAssertingVisitor.java diff --git a/io-mappingio/build.gradle b/io-mappingio/build.gradle index 847b8a1..6bfb4f8 100644 --- a/io-mappingio/build.gradle +++ b/io-mappingio/build.gradle @@ -6,6 +6,7 @@ dependencies { api libs.mappingio compileOnly libs.jetbrains.annotations + testCompileOnly libs.jetbrains.annotations testFixturesApi testFixtures(project(':feather')) } diff --git a/io-mappingio/src/test/java/org/parchmentmc/feather/io/mappingio/MappingIOTest.java b/io-mappingio/src/test/java/org/parchmentmc/feather/io/mappingio/MappingIOTest.java new file mode 100644 index 0000000..c33c09b --- /dev/null +++ b/io-mappingio/src/test/java/org/parchmentmc/feather/io/mappingio/MappingIOTest.java @@ -0,0 +1,42 @@ +package org.parchmentmc.feather.io.mappingio; + +import net.fabricmc.mappingio.MappedElementKind; +import net.fabricmc.mappingio.MappingUtil; +import net.fabricmc.mappingio.adapter.FlatAsRegularMappingVisitor; +import net.fabricmc.mappingio.tree.MappingTree; +import net.fabricmc.mappingio.tree.MemoryMappingTree; +import net.fabricmc.mappingio.tree.VisitableMappingTree; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +public class MappingIOTest { + @Test + public void testMio() throws IOException { + VisitableMappingTree tree = new MemoryMappingTree(); + String srcNs = MappingUtil.NS_SOURCE_FALLBACK; + + tree.visitNamespaces(srcNs, Collections.emptyList()); + + tree.visitClass("net/minecraft/class_1"); + tree.visitComment(MappedElementKind.CLASS, "class_1 comment"); + + tree.visitField("field_1", "I"); + tree.visitComment(MappedElementKind.FIELD, "field_1 comment"); + + tree.visitMethod("method_1", "()V"); + tree.visitComment(MappedElementKind.METHOD, "method_1 comment"); + + tree.visitMethodArg(-1, 0, "arg_1"); + tree.visitComment(MappedElementKind.METHOD_ARG, "arg_1 comment"); + + tree.visitEnd(); + + MappingTree convertedTree = MdcToMio.toTree(MioToMdc.fromTree(tree), srcNs); + + convertedTree.accept(new FlatAsRegularMappingVisitor(new SubsetAssertingVisitor(tree, null, null))); + tree.accept(new FlatAsRegularMappingVisitor(new SubsetAssertingVisitor(convertedTree, null, null))); + } +} diff --git a/io-mappingio/src/test/java/org/parchmentmc/feather/io/mappingio/SubsetAssertingVisitor.java b/io-mappingio/src/test/java/org/parchmentmc/feather/io/mappingio/SubsetAssertingVisitor.java new file mode 100644 index 0000000..7fc4633 --- /dev/null +++ b/io-mappingio/src/test/java/org/parchmentmc/feather/io/mappingio/SubsetAssertingVisitor.java @@ -0,0 +1,246 @@ +// Copied from https://github.com/FabricMC/mapping-io/blob/7e7e77ef06d155ccdf067463752e1ede702cb241/src/test/java/net/fabricmc/mappingio/SubsetAssertingVisitor.java + +package org.parchmentmc.feather.io.mappingio; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import org.jetbrains.annotations.Nullable; + +import net.fabricmc.mappingio.FlatMappingVisitor; +import net.fabricmc.mappingio.MappingUtil; +import net.fabricmc.mappingio.format.MappingFormat; +import net.fabricmc.mappingio.tree.MappingTreeView; +import net.fabricmc.mappingio.tree.MappingTreeView.ClassMappingView; +import net.fabricmc.mappingio.tree.MappingTreeView.FieldMappingView; +import net.fabricmc.mappingio.tree.MappingTreeView.MethodArgMappingView; +import net.fabricmc.mappingio.tree.MappingTreeView.MethodMappingView; +import net.fabricmc.mappingio.tree.MappingTreeView.MethodVarMappingView; + +public class SubsetAssertingVisitor implements FlatMappingVisitor { + public SubsetAssertingVisitor(MappingTreeView supTree, @Nullable MappingFormat supFormat, @Nullable MappingFormat subFormat) { + this.supTree = supTree; + this.supDstNsCount = supTree.getMaxNamespaceId(); + this.subHasNamespaces = subFormat == null ? true : subFormat.hasNamespaces; + this.supHasNamespaces = supFormat == null ? true : supFormat.hasNamespaces; + this.supHasFieldDesc = supFormat == null ? true : supFormat.hasFieldDescriptors; + this.supHasArgs = supFormat == null ? true : supFormat.supportsArgs; + this.supHasVars = supFormat == null ? true : supFormat.supportsLocals; + this.supHasComments = supFormat == null ? true : supFormat.supportsComments; + } + + @Override + public void visitNamespaces(String srcNamespace, List dstNamespaces) throws IOException { + assertTrue(srcNamespace.equals(subHasNamespaces ? supTree.getSrcNamespace() : MappingUtil.NS_SOURCE_FALLBACK)); + this.dstNamespaces = dstNamespaces; + + if (!subHasNamespaces) { + assertTrue(dstNamespaces.size() == 1); + assertTrue(dstNamespaces.get(0).equals(MappingUtil.NS_TARGET_FALLBACK)); + return; + } + + for (int i = 0; i < dstNamespaces.size(); i++) { + String dstNs = dstNamespaces.get(i); + boolean contained = supTree.getDstNamespaces().contains(dstNs); + + if (!supHasNamespaces) { + if (contained) return; + } else { + assertTrue(contained); + } + } + + if (!supHasNamespaces) throw new RuntimeException("SubTree namespace not contained in SupTree"); + } + + @Override + public boolean visitClass(String srcName, String[] dstNames) throws IOException { + ClassMappingView supCls = supTree.getClass(srcName); + Map supDstNamesByNsName = new HashMap<>(); + + if (supCls == null) { + String[] tmpDst = supHasNamespaces ? dstNames : new String[]{dstNames[0]}; + if (!Arrays.stream(tmpDst).anyMatch(Objects::nonNull)) return false; + throw new RuntimeException("SubTree class not contained in SupTree: " + srcName); + } + + for (int supNs = 0; supNs < supDstNsCount; supNs++) { + supDstNamesByNsName.put(supTree.getNamespaceName(supNs), supCls.getDstName(supNs)); + } + + for (int subNs = 0; subNs < dstNames.length; subNs++) { + String supDstName = supDstNamesByNsName.get(dstNamespaces.get(subNs)); + if (!supHasNamespaces && supDstName == null) continue; + assertTrue(dstNames[subNs] == null || dstNames[subNs].equals(supDstName) || (supDstName == null && dstNames[subNs].equals(srcName))); + } + + return true; + } + + @Override + public void visitClassComment(String srcName, String[] dstNames, String comment) throws IOException { + if (!supHasComments) return; + assertEquals(supTree.getClass(srcName).getComment(), comment); + } + + @Override + public boolean visitField(String srcClsName, String srcName, String srcDesc, + String[] dstClsNames, String[] dstNames, String[] dstDescs) throws IOException { + FieldMappingView supFld = supTree.getClass(srcClsName).getField(srcName, srcDesc); + Map supDstDataByNsName = new HashMap<>(); + + if (supFld == null) { + String[] tmpDst = supHasNamespaces ? dstNames : new String[]{dstNames[0]}; + if (!Arrays.stream(tmpDst).anyMatch(Objects::nonNull)) return false; + throw new RuntimeException("SubTree field not contained in SupTree: " + srcName); + } + + for (int supNs = 0; supNs < supDstNsCount; supNs++) { + supDstDataByNsName.put(supTree.getNamespaceName(supNs), new String[]{supFld.getDstName(supNs), supFld.getDstDesc(supNs)}); + } + + for (int subNs = 0; subNs < dstNames.length; subNs++) { + String[] supDstData = supDstDataByNsName.get(dstNamespaces.get(subNs)); + if (!supHasNamespaces && supDstData == null) continue; + + String supDstName = supDstData[0]; + assertTrue(dstNames[subNs] == null || dstNames[subNs].equals(supDstName) || (supDstName == null && dstNames[subNs].equals(srcName))); + + if (!supHasFieldDesc) continue; + String supDstDesc = supDstData[1]; + assertTrue(dstDescs == null || dstDescs[subNs] == null || dstDescs[subNs].equals(supDstDesc)); + } + + return true; + } + + @Override + public void visitFieldComment(String srcClsName, String srcName, String srcDesc, + String[] dstClsNames, String[] dstNames, String[] dstDescs, String comment) throws IOException { + if (!supHasComments) return; + assertEquals(supTree.getClass(srcClsName).getField(srcName, srcDesc).getComment(), comment); + } + + @Override + public boolean visitMethod(String srcClsName, String srcName, String srcDesc, + String[] dstClsNames, String[] dstNames, String[] dstDescs) throws IOException { + MethodMappingView supMth = supTree.getClass(srcClsName).getMethod(srcName, srcDesc); + Map supDstDataByNsName = new HashMap<>(); + + if (supMth == null) { + String[] tmpDst = supHasNamespaces ? dstNames : new String[]{dstNames[0]}; + if (!Arrays.stream(tmpDst).anyMatch(Objects::nonNull)) return false; + throw new RuntimeException("SubTree method not contained in SupTree: " + srcName); + } + + for (int supNs = 0; supNs < supDstNsCount; supNs++) { + supDstDataByNsName.put(supTree.getNamespaceName(supNs), new String[]{supMth.getDstName(supNs), supMth.getDstDesc(supNs)}); + } + + for (int subNs = 0; subNs < dstNames.length; subNs++) { + String[] supDstData = supDstDataByNsName.get(dstNamespaces.get(subNs)); + if (!supHasNamespaces && supDstData == null) continue; + + String supDstName = supDstData[0]; + assertTrue(dstNames[subNs] == null || dstNames[subNs].equals(supDstName) || (supDstName == null && dstNames[subNs].equals(srcName))); + + String supDstDesc = supDstData[1]; + assertTrue(dstDescs == null || dstDescs[subNs] == null || dstDescs[subNs].equals(supDstDesc)); + } + + return true; + } + + @Override + public void visitMethodComment(String srcClsName, String srcName, String srcDesc, + String[] dstClsNames, String[] dstNames, String[] dstDescs, String comment) throws IOException { + if (!supHasComments) return; + assertEquals(supTree.getClass(srcClsName).getMethod(srcName, srcDesc).getComment(), comment); + } + + @Override + public boolean visitMethodArg(String srcClsName, String srcMethodName, String srcMethodDesc, int argPosition, int lvIndex, String srcName, + String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstNames) throws IOException { + if (!supHasArgs) return false; + MethodArgMappingView supArg = supTree.getClass(srcClsName).getMethod(srcMethodName, srcMethodDesc).getArg(argPosition, lvIndex, srcName); + Map supDstNamesByNsName = new HashMap<>(); + + if (supArg == null) { + String[] tmpDst = supHasNamespaces ? dstNames : new String[]{dstNames[0]}; + if (!Arrays.stream(tmpDst).anyMatch(Objects::nonNull)) return false; + throw new RuntimeException("SubTree arg not contained in SupTree: " + srcName); + } + + for (int supNs = 0; supNs < supDstNsCount; supNs++) { + supDstNamesByNsName.put(supTree.getNamespaceName(supNs), supArg.getDstName(supNs)); + } + + for (int subNs = 0; subNs < dstNames.length; subNs++) { + String supDstName = supDstNamesByNsName.get(dstNamespaces.get(subNs)); + if (!supHasNamespaces && supDstName == null) continue; + assertTrue(dstNames[subNs] == null || dstNames[subNs].equals(supDstName) || (supDstName == null && dstNames[subNs].equals(srcName))); + } + + return true; + } + + @Override + public void visitMethodArgComment(String srcClsName, String srcMethodName, String srcMethodDesc, int argPosition, int lvIndex, String srcArgName, + String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstNames, String comment) throws IOException { + if (!supHasComments) return; + assertEquals(supTree.getClass(srcClsName).getMethod(srcMethodName, srcMethodDesc).getArg(argPosition, lvIndex, srcArgName).getComment(), comment); + } + + @Override + public boolean visitMethodVar(String srcClsName, String srcMethodName, String srcMethodDesc, + int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcName, + String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstNames) throws IOException { + if (!supHasVars) return false; + MethodVarMappingView supVar = supTree.getClass(srcClsName).getMethod(srcMethodName, srcMethodDesc).getVar(lvtRowIndex, lvIndex, startOpIdx, endOpIdx, srcName); + Map supDstNamesByNsName = new HashMap<>(); + + if (supVar == null) { + String[] tmpDst = supHasNamespaces ? dstNames : new String[]{dstNames[0]}; + if (!Arrays.stream(tmpDst).anyMatch(Objects::nonNull)) return false; + throw new RuntimeException("SubTree var not contained in SupTree: " + srcName); + } + + for (int supNs = 0; supNs < supDstNsCount; supNs++) { + supDstNamesByNsName.put(supTree.getNamespaceName(supNs), supVar.getDstName(supNs)); + } + + for (int subNs = 0; subNs < dstNames.length; subNs++) { + String supDstName = supDstNamesByNsName.get(dstNamespaces.get(subNs)); + if (!supHasNamespaces && supDstName == null) continue; + assertTrue(dstNames[subNs] == null || dstNames[subNs].equals(supDstName) || (supDstName == null && dstNames[subNs].equals(srcName))); + } + + return true; + } + + @Override + public 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[] dstNames, String comment) throws IOException { + if (!supHasComments) return; + assertEquals(supTree.getClass(srcClsName).getMethod(srcMethodName, srcMethodDesc).getVar(lvtRowIndex, lvIndex, startOpIdx, endOpIdx, srcVarName).getComment(), comment); + } + + private final MappingTreeView supTree; + private final int supDstNsCount; + private final boolean subHasNamespaces; + private final boolean supHasNamespaces; + private final boolean supHasFieldDesc; + private final boolean supHasArgs; + private final boolean supHasVars; + private final boolean supHasComments; + private List dstNamespaces; +} From 118fdf2e878c546a61b5236a114e483f380fee67 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Wed, 6 Dec 2023 11:30:02 +0100 Subject: [PATCH 5/5] Add missing Javadoc tags --- .../java/org/parchmentmc/feather/io/mappingio/MdcToMio.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MdcToMio.java b/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MdcToMio.java index d6faa81..04b5d43 100644 --- a/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MdcToMio.java +++ b/io-mappingio/src/main/java/org/parchmentmc/feather/io/mappingio/MdcToMio.java @@ -17,6 +17,7 @@ public class MdcToMio { * * @param mdc The {@link MappingDataContainer} to read from. * @param srcNs The source namespace to use for the tree. + * @return The constructed {@link MappingTree}. * @throws IOException If an I/O error occurs. */ public static MappingTree toTree(MappingDataContainer mdc, String srcNs) throws IOException { @@ -29,6 +30,7 @@ public static MappingTree toTree(MappingDataContainer mdc, String srcNs) throws * Reads mapping data from a given {@link MappingDataContainer} and passes it to a {@link MappingVisitor} (on the source namespace). * * @param mdc The {@link MappingDataContainer} to read from. + * @param visitor The {@link MappingVisitor} to pass the data to. * @param srcNs The source namespace to pass to the visitor. * @throws IOException If an I/O error occurs. */