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 eb381ccc..67e7b498 100644 --- a/enigma/src/main/java/org/quiltmc/enigma/api/EnigmaProject.java +++ b/enigma/src/main/java/org/quiltmc/enigma/api/EnigmaProject.java @@ -170,7 +170,7 @@ public boolean isNavigable(Entry obfEntry) { return false; } - return this.jarIndex.getIndex(EntryIndex.class).hasEntry(obfEntry); + return this.jarIndex.getIndex(EntryIndex.class).hasEntry(obfEntry, this); } public boolean isRenamable(Entry obfEntry) { @@ -211,7 +211,7 @@ public boolean isRenamable(Entry obfEntry) { return false; } - return this.jarIndex.getIndex(EntryIndex.class).hasEntry(obfEntry); + return this.jarIndex.getIndex(EntryIndex.class).hasEntry(obfEntry, this); } private static boolean isEnumValueOfMethod(ClassDefEntry parent, MethodEntry method) { @@ -237,7 +237,7 @@ public boolean isObfuscated(Entry entry) { } public boolean isSynthetic(Entry entry) { - return this.jarIndex.getIndex(EntryIndex.class).hasEntry(entry) && this.jarIndex.getIndex(EntryIndex.class).getEntryAccess(entry).isSynthetic(); + return this.jarIndex.getIndex(EntryIndex.class).hasEntry(entry, this) && this.jarIndex.getIndex(EntryIndex.class).getEntryAccess(entry).isSynthetic(); } public boolean isAnonymousOrLocal(ClassEntry classEntry) { diff --git a/enigma/src/main/java/org/quiltmc/enigma/api/analysis/index/jar/EntryIndex.java b/enigma/src/main/java/org/quiltmc/enigma/api/analysis/index/jar/EntryIndex.java index 7fb4e14b..fa1d1728 100644 --- a/enigma/src/main/java/org/quiltmc/enigma/api/analysis/index/jar/EntryIndex.java +++ b/enigma/src/main/java/org/quiltmc/enigma/api/analysis/index/jar/EntryIndex.java @@ -1,5 +1,7 @@ package org.quiltmc.enigma.api.analysis.index.jar; +import org.objectweb.asm.tree.ClassNode; +import org.quiltmc.enigma.api.EnigmaProject; import org.quiltmc.enigma.api.translation.mapping.EntryMapping; import org.quiltmc.enigma.api.translation.mapping.tree.EntryTree; import org.quiltmc.enigma.api.translation.mapping.tree.HashEntryTree; @@ -17,6 +19,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; public class EntryIndex implements JarIndexer { private final EntryTree tree = new HashEntryTree<>(); @@ -68,6 +71,11 @@ public boolean hasField(FieldEntry entry) { } public boolean hasEntry(Entry entry) { + return this.hasEntry(entry, null); + } + + @SuppressWarnings("ConstantConditions") + public boolean hasEntry(Entry entry, @Nullable EnigmaProject project) { if (entry instanceof ClassEntry classEntry) { return this.hasClass(classEntry); } else if (entry instanceof MethodEntry methodEntry) { @@ -77,10 +85,25 @@ public boolean hasEntry(Entry entry) { } else if (entry instanceof LocalVariableEntry localVariableEntry) { MethodEntry parent = localVariableEntry.getParent(); if (this.hasMethod(parent)) { - // TODO: Check using max_locals from the Code attribute (JVMS§4.7.3) + AtomicInteger maxLocals = new AtomicInteger(-1); + ClassEntry parentClass = parent != null ? parent.getParent() : null; + + if (project != null) { + // find max_locals for method, representing the number of parameters it receives (JVMS§4.7.3) + // note: parent class cannot be null, warning suppressed + ClassNode classNode = project.getClassProvider().get(parentClass.getFullName()); + if (classNode != null) { + classNode.methods.stream() + .filter(node -> node.name.equals(parent.getName()) && node.desc.equals(parent.getDesc().toString())) + .findFirst().ifPresent(node -> maxLocals.set(node.maxLocals)); + } + } + AccessFlags parentAccess = this.getMethodAccess(parent); int startIndex = parentAccess != null && parentAccess.isStatic() ? 0 : 1; - return localVariableEntry.getIndex() >= startIndex; + + // if maxLocals is -1 it's not found for the method and should be ignored + return localVariableEntry.getIndex() >= startIndex && (maxLocals.get() == -1 || localVariableEntry.getIndex() <= maxLocals.get() - 1); } } diff --git a/enigma/src/main/java/org/quiltmc/enigma/impl/translation/mapping/MappingsChecker.java b/enigma/src/main/java/org/quiltmc/enigma/impl/translation/mapping/MappingsChecker.java index 70ecc396..5e8d0792 100644 --- a/enigma/src/main/java/org/quiltmc/enigma/impl/translation/mapping/MappingsChecker.java +++ b/enigma/src/main/java/org/quiltmc/enigma/impl/translation/mapping/MappingsChecker.java @@ -62,7 +62,7 @@ private void tryDropBrokenEntry(Dropped dropped, Entry entry) { } private boolean shouldDropBrokenEntry(Dropped dropped, Entry entry) { - if (!this.index.getIndex(EntryIndex.class).hasEntry(entry)) { + if (!this.index.getIndex(EntryIndex.class).hasEntry(entry, this.project)) { return true; } @@ -99,7 +99,7 @@ private boolean shouldDropEmptyMapping(Dropped dropped, Entry entry) { EntryMapping mapping = this.mappings.get(entry); System.out.println(entry + " -> " + mapping); if (mapping != null) { - boolean isEmpty = (mapping.targetName() == null && mapping.javadoc() == null) || !project.isRenamable(entry); + boolean isEmpty = (mapping.targetName() == null && mapping.javadoc() == null) || !this.project.isRenamable(entry); if (isEmpty) { return this.hasChildren(entry, dropped);