diff --git a/enigma-server/src/main/java/org/quiltmc/enigma/network/DedicatedEnigmaServer.java b/enigma-server/src/main/java/org/quiltmc/enigma/network/DedicatedEnigmaServer.java index a2e28e23e..57d1b65d2 100644 --- a/enigma-server/src/main/java/org/quiltmc/enigma/network/DedicatedEnigmaServer.java +++ b/enigma-server/src/main/java/org/quiltmc/enigma/network/DedicatedEnigmaServer.java @@ -124,10 +124,10 @@ public static void main(String[] args) { EntryRemapper mappings; if (!Files.exists(mappingsFile)) { - mappings = EntryRemapper.mapped(enigma, project.getCombinedIndex(), project.getMappingsIndex(), project.getRemapper().getJarProposedMappings(), new HashEntryTree<>(), enigma.getNameProposalServices()); + mappings = EntryRemapper.mapped(project, project.getRemapper().getJarProposedMappings(), new HashEntryTree<>()); } else { Logger.info("Reading mappings..."); - mappings = EntryRemapper.mapped(enigma, project.getCombinedIndex(), project.getMappingsIndex(), project.getRemapper().getJarProposedMappings(), readWriteService.get().read(mappingsFile), enigma.getNameProposalServices()); + mappings = EntryRemapper.mapped(project, project.getRemapper().getJarProposedMappings(), readWriteService.get().read(mappingsFile)); } PrintWriter log = new PrintWriter(Files.newBufferedWriter(logFile)); diff --git a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/GuiController.java b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/GuiController.java index ddc724c42..86fb6fd08 100644 --- a/enigma-swing/src/main/java/org/quiltmc/enigma/gui/GuiController.java +++ b/enigma-swing/src/main/java/org/quiltmc/enigma/gui/GuiController.java @@ -686,7 +686,7 @@ public void createClient(String username, String ip, int port, char[] password) } public void createServer(String username, int port, char[] password) throws IOException { - this.server = new IntegratedEnigmaServer(this.project.getJarChecksum(), password, EntryRemapper.mapped(this.project.getEnigma(), this.project.getCombinedIndex(), this.project.getMappingsIndex(), new HashEntryTree<>(this.project.getRemapper().getJarProposedMappings()), new HashEntryTree<>(this.project.getRemapper().getDeobfMappings()), this.project.getEnigma().getNameProposalServices()), port); + this.server = new IntegratedEnigmaServer(this.project.getJarChecksum(), password, EntryRemapper.mapped(this.project, new HashEntryTree<>(this.project.getRemapper().getJarProposedMappings()), new HashEntryTree<>(this.project.getRemapper().getDeobfMappings())), port); this.server.start(); this.client = new IntegratedEnigmaClient(this, "127.0.0.1", port); this.client.connect(); diff --git a/enigma/src/main/java/org/quiltmc/enigma/api/EnigmaProject.java b/enigma/src/main/java/org/quiltmc/enigma/api/EnigmaProject.java index 41473e185..596f54f91 100644 --- a/enigma/src/main/java/org/quiltmc/enigma/api/EnigmaProject.java +++ b/enigma/src/main/java/org/quiltmc/enigma/api/EnigmaProject.java @@ -78,7 +78,7 @@ public EnigmaProject(Enigma enigma, Path jarPath, ClassProvider classProvider, J this.jarChecksum = jarChecksum; this.mappingsIndex = mappingsIndex; - this.remapper = EntryRemapper.mapped(this.enigma, this.combinedIndex, this.mappingsIndex, proposedNames, new HashEntryTree<>(), this.enigma.getNameProposalServices()); + this.remapper = EntryRemapper.mapped(this, proposedNames, new HashEntryTree<>()); } /** @@ -97,12 +97,12 @@ public void setMappings(@Nullable EntryTree mappings, ProgressList EntryTree mergedTree = EntryTreeUtil.merge(jarProposedMappings, mappings); this.mappingsIndex.indexMappings(mergedTree, progress); - this.remapper = EntryRemapper.mapped(this.enigma, this.combinedIndex, this.mappingsIndex, jarProposedMappings, mappings, this.enigma.getNameProposalServices()); + this.remapper = EntryRemapper.mapped(this, jarProposedMappings, mappings); } else if (!jarProposedMappings.isEmpty()) { this.mappingsIndex.indexMappings(jarProposedMappings, progress); - this.remapper = EntryRemapper.mapped(this.enigma, this.combinedIndex, this.mappingsIndex, jarProposedMappings, new HashEntryTree<>(), this.enigma.getNameProposalServices()); + this.remapper = EntryRemapper.mapped(this, jarProposedMappings, new HashEntryTree<>()); } else { - this.remapper = EntryRemapper.empty(this.enigma, this.combinedIndex, this.enigma.getNameProposalServices()); + this.remapper = EntryRemapper.empty(this); } // update dynamically proposed names diff --git a/enigma/src/main/java/org/quiltmc/enigma/api/translation/mapping/EntryRemapper.java b/enigma/src/main/java/org/quiltmc/enigma/api/translation/mapping/EntryRemapper.java index a8522baca..ae9e2cef3 100644 --- a/enigma/src/main/java/org/quiltmc/enigma/api/translation/mapping/EntryRemapper.java +++ b/enigma/src/main/java/org/quiltmc/enigma/api/translation/mapping/EntryRemapper.java @@ -3,6 +3,7 @@ import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.quiltmc.enigma.api.Enigma; +import org.quiltmc.enigma.api.EnigmaProject; import org.quiltmc.enigma.api.analysis.index.jar.InheritanceIndex; import org.quiltmc.enigma.api.analysis.index.jar.JarIndex; import org.quiltmc.enigma.api.analysis.index.mapping.MappingsIndex; @@ -30,7 +31,7 @@ import java.util.Set; import java.util.stream.Stream; -public class EntryRemapper { +public final class EntryRemapper { private final EntryTree deobfMappings; private final EntryTree jarProposedMappings; private final EntryTree proposedMappings; @@ -45,7 +46,12 @@ public class EntryRemapper { private final MappingValidator validator; private final List proposalServices; - private EntryRemapper(Enigma enigma, JarIndex jarIndex, MappingsIndex mappingsIndex, EntryTree jarProposedMappings, EntryTree deobfMappings, List proposalServices) { + private EntryRemapper( + Enigma enigma, JarIndex jarIndex, JarIndex combinedIndex, + MappingsIndex mappingsIndex, + EntryTree jarProposedMappings, EntryTree deobfMappings, + List proposalServices + ) { this.deobfMappings = deobfMappings; this.jarProposedMappings = jarProposedMappings; this.proposedMappings = new HashEntryTree<>(jarProposedMappings); @@ -58,16 +64,67 @@ private EntryRemapper(Enigma enigma, JarIndex jarIndex, MappingsIndex mappingsIn this.jarIndex = jarIndex; this.mappingsIndex = mappingsIndex; - this.validator = new MappingValidator(this.obfResolver, this.deobfuscator, jarIndex, mappingsIndex); + // use combined index for validator so it can find conflicts with lib method names + final EntryResolver combinedResolver = combinedIndex.getEntryResolver(); + this.validator = new MappingValidator(combinedResolver, new MappingTranslator(this.mappings, combinedResolver), combinedIndex, mappingsIndex); this.proposalServices = proposalServices; } - public static EntryRemapper mapped(Enigma enigma, JarIndex jarIndex, MappingsIndex mappingsIndex, EntryTree proposedMappings, EntryTree deobfMappings, List proposalServices) { - return new EntryRemapper(enigma, jarIndex, mappingsIndex, proposedMappings, deobfMappings, proposalServices); + public static EntryRemapper mapped( + Enigma project, JarIndex jarIndex, JarIndex combinedIndex, + MappingsIndex mappingsIndex, + EntryTree proposedMappings, EntryTree deobfMappings, + List proposalServices + ) { + return new EntryRemapper( + project, jarIndex, combinedIndex, + mappingsIndex, + proposedMappings, deobfMappings, + proposalServices + ); } - public static EntryRemapper empty(Enigma enigma, JarIndex index, List proposalServices) { - return new EntryRemapper(enigma, index, MappingsIndex.empty(), new HashEntryTree<>(), new HashEntryTree<>(), proposalServices); + /** + * Creates a remapper with the passed {@code project}'s {@linkplain EnigmaProject#getEnigma() enigma} instance, + * {@linkplain EnigmaProject#getJarIndex() jar index}, {@linkplain EnigmaProject#getCombinedIndex() combined index}, + * {@linkplain EnigmaProject#getMappingsIndex() mappings index}, + * and its enigma instance's {@linkplain Enigma#getNameProposalServices() name proposal services}. + */ + public static EntryRemapper mapped( + EnigmaProject project, EntryTree proposedMappings, EntryTree deobfMappings + ) { + return mapped( + project.getEnigma(), project.getJarIndex(), project.getCombinedIndex(), + project.getMappingsIndex(), + proposedMappings, deobfMappings, + project.getEnigma().getNameProposalServices() + ); + } + + public static EntryRemapper empty( + Enigma enigma, + JarIndex jarIndex, JarIndex combinedIndex, + List proposalServices + ) { + return new EntryRemapper( + enigma, jarIndex, combinedIndex, + MappingsIndex.empty(), new HashEntryTree<>(), new HashEntryTree<>(), + proposalServices + ); + } + + /** + * Creates an empty remapper with the passed {@code project}'s + * {@linkplain EnigmaProject#getEnigma() enigma} instance, + * {@linkplain EnigmaProject#getJarIndex() jar index}, {@linkplain EnigmaProject#getCombinedIndex() combined index}, + * and its enigma instance's {@linkplain Enigma#getNameProposalServices() name proposal services}. + */ + public static EntryRemapper empty(EnigmaProject project) { + return empty( + project.getEnigma(), + project.getJarIndex(), project.getCombinedIndex(), + project.getEnigma().getNameProposalServices() + ); } public void validatePutMapping(ValidationContext vc, Entry obfuscatedEntry, @NonNull EntryMapping deobfMapping) { @@ -82,7 +139,9 @@ private void doPutMapping(ValidationContext vc, Entry obfuscatedEntry, @NonNu EntryMapping oldMapping = this.getMapping(obfuscatedEntry); boolean renaming = !Objects.equals(oldMapping.targetName(), deobfMapping.targetName()); - Collection> resolvedEntries = renaming ? this.resolveAllRoots(obfuscatedEntry) : this.obfResolver.resolveEntry(obfuscatedEntry, ResolutionStrategy.RESOLVE_CLOSEST); + Collection> resolvedEntries = renaming + ? this.resolveAllRoots(obfuscatedEntry) + : this.obfResolver.resolveEntry(obfuscatedEntry, ResolutionStrategy.RESOLVE_CLOSEST); if (renaming && deobfMapping.targetName() != null) { for (Entry resolvedEntry : resolvedEntries) { diff --git a/enigma/src/test/java/org/quiltmc/enigma/TestMainJarMapped.java b/enigma/src/test/java/org/quiltmc/enigma/TestMainJarMapped.java new file mode 100644 index 000000000..48aab5fa0 --- /dev/null +++ b/enigma/src/test/java/org/quiltmc/enigma/TestMainJarMapped.java @@ -0,0 +1,70 @@ +package org.quiltmc.enigma; + +import org.junit.jupiter.api.Test; +import org.quiltmc.enigma.api.Enigma; +import org.quiltmc.enigma.api.EnigmaProject; +import org.quiltmc.enigma.api.ProgressListener; +import org.quiltmc.enigma.api.class_provider.ClasspathClassProvider; +import org.quiltmc.enigma.api.translation.mapping.EntryMapping; +import org.quiltmc.enigma.api.translation.mapping.serde.MappingFileNameFormat; +import org.quiltmc.enigma.api.translation.mapping.serde.MappingSaveParameters; +import org.quiltmc.enigma.api.translation.representation.entry.LocalVariableEntry; +import org.quiltmc.enigma.util.validation.ValidationContext; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TestMainJarMapped { + private static final Path JAR = TestUtil.obfJar("main_jar_mapped"); + + public static final String TEST_CLASS_NAME = "a"; + + private static EnigmaProject openProject() { + try { + return Enigma.create().openJar(JAR, new ClasspathClassProvider(), ProgressListener.createEmpty()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Tests that when a parameter of a main jar method that's inherited from a lib class is mapped, + * the main jar's parameter is mapped; no lib mapping should be created. + */ + @Test + void test() throws IOException { + final EnigmaProject project = openProject(); + + final LocalVariableEntry equalsParam = TestEntryFactory.newParameter( + TestEntryFactory.newMethod(TEST_CLASS_NAME, "equals", "(Ljava/lang/Object;)Z"), + 1 + ); + + project.getRemapper().putMapping(new ValidationContext(null), equalsParam, new EntryMapping("object")); + + final Path mappingsDir = Files.createTempDirectory("main_jar_mapped"); + project.getEnigma() + .getReadWriteService(mappingsDir) + .orElseThrow() + .write( + project.getRemapper().getMappings(), + mappingsDir, + new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF, false, null, null) + ); + + final List savedFiles = new LinkedList<>(); + try (Stream paths = Files.walk(mappingsDir)) { + paths.filter(Files::isRegularFile).forEach(savedFiles::add); + } + + assertEquals(1, savedFiles.size()); + + assertEquals(mappingsDir.resolve(TEST_CLASS_NAME + ".mapping"), savedFiles.get(0)); + } +} diff --git a/enigma/src/test/java/org/quiltmc/enigma/input/main_jar_mapped/MainJarMapped.java b/enigma/src/test/java/org/quiltmc/enigma/input/main_jar_mapped/MainJarMapped.java new file mode 100644 index 000000000..4357b8a91 --- /dev/null +++ b/enigma/src/test/java/org/quiltmc/enigma/input/main_jar_mapped/MainJarMapped.java @@ -0,0 +1,8 @@ +package org.quiltmc.enigma.input.main_jar_mapped; + +public class MainJarMapped { + @Override + public boolean equals(Object o) { + return false; + } +}