-
-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
validate lambda parameters for uniqueness and add more tests (#205)
* start working on lambda validation * checkstyle * fix up tests * start working on tests * implement parent parameter name conflict with top level lambda and nested lambda * make lambda index more incremental * add parameter names test
- Loading branch information
Showing
10 changed files
with
250 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
enigma/src/main/java/org/quiltmc/enigma/api/analysis/index/jar/LambdaIndex.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package org.quiltmc.enigma.api.analysis.index.jar; | ||
|
||
import com.google.common.collect.ImmutableListMultimap; | ||
import org.quiltmc.enigma.api.analysis.ReferenceTargetType; | ||
import org.quiltmc.enigma.api.translation.representation.Lambda; | ||
import org.quiltmc.enigma.api.translation.representation.entry.MethodDefEntry; | ||
import org.quiltmc.enigma.api.translation.representation.entry.MethodEntry; | ||
|
||
import javax.annotation.Nullable; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
public class LambdaIndex implements JarIndexer { | ||
private final Map<MethodEntry, MethodDefEntry> callers = new HashMap<>(); | ||
private ImmutableListMultimap<MethodEntry, MethodEntry> lambdas = null; | ||
private final ImmutableListMultimap.Builder<MethodEntry, MethodEntry> lambdasBuilder = ImmutableListMultimap.builder(); | ||
|
||
@Override | ||
public void indexLambda(MethodDefEntry callerEntry, Lambda lambda, ReferenceTargetType targetType) { | ||
MethodEntry implMethod = (MethodEntry) lambda.implMethod(); | ||
this.callers.put(implMethod, callerEntry); | ||
|
||
this.lambdasBuilder.put(callerEntry, implMethod); | ||
} | ||
|
||
@Override | ||
public void processIndex(JarIndex index) { | ||
var nestedLambdas = this.lambdasBuilder.build(); | ||
|
||
ImmutableListMultimap.Builder<MethodEntry, MethodEntry> multilevelLambdasBuilder = ImmutableListMultimap.builder(); | ||
for (var callerMethod : nestedLambdas.keySet()) { | ||
// if caller method is a lambda itself, find the top level method | ||
boolean isLambda = nestedLambdas.containsValue(callerMethod); | ||
MethodEntry topLevel = callerMethod; | ||
|
||
if (!isLambda) { | ||
multilevelLambdasBuilder.put(topLevel, callerMethod); | ||
} else { | ||
// travel up the chain until we find the top level method, adding as we go | ||
while (isLambda) { | ||
topLevel = this.callers.get(topLevel); | ||
isLambda = nestedLambdas.containsValue(topLevel); | ||
|
||
multilevelLambdasBuilder.put(topLevel, callerMethod); | ||
} | ||
} | ||
} | ||
|
||
this.lambdas = multilevelLambdasBuilder.build(); | ||
} | ||
|
||
/** | ||
* {@return the top-level method that contains the given lambda} | ||
* @param lambda the lambda to get the caller for | ||
*/ | ||
public MethodDefEntry getCaller(MethodEntry lambda) { | ||
return this.callers.get(lambda); | ||
} | ||
|
||
/** | ||
* {@return all lambda methods nested inside the given method} | ||
* @param method the method to get lambdas for | ||
*/ | ||
@Nullable | ||
public List<MethodEntry> getInternalLambdas(MethodEntry method) { | ||
return this.lambdas.get(method); | ||
} | ||
|
||
@Override | ||
public String getTranslationKey() { | ||
return "progress.jar.indexing.process.lambdas"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 16 additions & 0 deletions
16
enigma/src/test/java/org/quiltmc/enigma/input/inner_classes/NestedLambdas.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package org.quiltmc.enigma.input.inner_classes; | ||
|
||
import java.util.function.Consumer; | ||
|
||
public class NestedLambdas { | ||
public static void main(String g) { | ||
gaming((s) -> gaming((w) -> { | ||
System.out.println(s); | ||
gaming(System.out::println); | ||
})); | ||
} | ||
|
||
public static void gaming(Consumer<String> runnable) { | ||
runnable.accept("Gaming!"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
.../src/test/java/org/quiltmc/enigma/translation/mapping/TestMappingValidatorParameters.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package org.quiltmc.enigma.translation.mapping; | ||
|
||
import org.junit.jupiter.api.BeforeAll; | ||
import org.junit.jupiter.api.Test; | ||
import org.quiltmc.enigma.TestEntryFactory; | ||
import org.quiltmc.enigma.TestUtil; | ||
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.EntryRemapper; | ||
import org.quiltmc.enigma.api.translation.representation.entry.LocalVariableEntry; | ||
import org.quiltmc.enigma.api.translation.representation.entry.MethodEntry; | ||
import org.quiltmc.enigma.util.validation.Message; | ||
import org.quiltmc.enigma.util.validation.ValidationContext; | ||
|
||
import java.nio.file.Path; | ||
|
||
public class TestMappingValidatorParameters { | ||
public static final Path JAR = TestUtil.obfJar("inner_classes"); | ||
private static EntryRemapper remapper; | ||
|
||
@BeforeAll | ||
public static void beforeAll() throws Exception { | ||
Enigma enigma = Enigma.create(); | ||
EnigmaProject project = enigma.openJar(JAR, new ClasspathClassProvider(), ProgressListener.createEmpty()); | ||
remapper = project.getRemapper(); | ||
} | ||
|
||
@Test | ||
public void testLambdaParameterNames() { | ||
MethodEntry parent = TestEntryFactory.newMethod("g", "a", "(Ljava/lang/String;)V"); | ||
LocalVariableEntry parentParam = TestEntryFactory.newParameter(parent, 0); | ||
MethodEntry firstLambda = TestEntryFactory.newMethod("g", "b", "(Ljava/lang/String;)V"); | ||
LocalVariableEntry firstLambdaParam = TestEntryFactory.newParameter(firstLambda, 0); | ||
MethodEntry secondLambda = TestEntryFactory.newMethod("g", "a", "(Ljava/lang/String;Ljava/lang/String;)V"); | ||
LocalVariableEntry secondLambdaParam = TestEntryFactory.newParameter(secondLambda, 1); | ||
|
||
// validate conflict with base method | ||
remapper.putMapping(TestUtil.newVC(), parentParam, new EntryMapping("LEVEL_0")); | ||
|
||
ValidationContext vc = TestUtil.newVC(); | ||
remapper.validatePutMapping(vc, firstLambdaParam, new EntryMapping("LEVEL_0")); | ||
TestMappingValidator.assertMessages(vc, Message.NON_UNIQUE_NAME_CLASS); | ||
|
||
ValidationContext vc2 = TestUtil.newVC(); | ||
remapper.validatePutMapping(vc2, secondLambdaParam, new EntryMapping("LEVEL_0")); | ||
TestMappingValidator.assertMessages(vc2, Message.NON_UNIQUE_NAME_CLASS); | ||
|
||
// validate nested lambda conflict with top level lambda | ||
remapper.putMapping(TestUtil.newVC(), firstLambdaParam, new EntryMapping("LEVEL_1")); | ||
|
||
ValidationContext vc3 = TestUtil.newVC(); | ||
remapper.validatePutMapping(vc3, secondLambdaParam, new EntryMapping("LEVEL_1")); | ||
TestMappingValidator.assertMessages(vc3, Message.NON_UNIQUE_NAME_CLASS); | ||
|
||
// validate parent parameter name conflict with top level lambda and nested lambda | ||
remapper.putMapping(TestUtil.newVC(), secondLambdaParam, new EntryMapping("LEVEL_2")); | ||
|
||
ValidationContext vc4 = TestUtil.newVC(); | ||
remapper.validatePutMapping(vc4, parentParam, new EntryMapping("LEVEL_2")); | ||
TestMappingValidator.assertMessages(vc4, Message.NON_UNIQUE_NAME_CLASS); | ||
|
||
ValidationContext vc5 = TestUtil.newVC(); | ||
remapper.validatePutMapping(vc5, parentParam, new EntryMapping("LEVEL_1")); | ||
TestMappingValidator.assertMessages(vc5, Message.NON_UNIQUE_NAME_CLASS); | ||
|
||
// validate nested lambda name conflict with nested-er lambda | ||
|
||
ValidationContext vc6 = TestUtil.newVC(); | ||
remapper.validatePutMapping(vc6, firstLambdaParam, new EntryMapping("LEVEL_2")); | ||
TestMappingValidator.assertMessages(vc6, Message.NON_UNIQUE_NAME_CLASS); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters