diff --git a/gradle.properties b/gradle.properties index 6ffb7da..b1f0323 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ group = dev.denwav.hypo -version = 2.0.1-SNAPSHOT +version = 2.1.0 org.gradle.parallel=true diff --git a/hypo-asm/hypo-asm-test-data/src/scenario-05/java/scenario05/TestClass.java b/hypo-asm/hypo-asm-test-data/src/scenario-05/java/scenario05/TestClass.java index c92ebec..eb34790 100644 --- a/hypo-asm/hypo-asm-test-data/src/scenario-05/java/scenario05/TestClass.java +++ b/hypo-asm/hypo-asm-test-data/src/scenario-05/java/scenario05/TestClass.java @@ -6,13 +6,15 @@ // Compiled with JDK 17 public class TestClass { + private long num = 0; + public void test() { final String s3 = Integer.toString(new Random().nextInt()); String s33 = Integer.toString(new Random().nextInt()); StringBuilder sb = new StringBuilder(); String str = sb.toString(); final Runnable r = () -> { - final String s4 = s3 + s3; + final String s4 = s3 + s3 + this.num; final String s44 = s33 + s33; str.length(); final Runnable r1 = () -> { @@ -25,4 +27,11 @@ public void test() { public static Object thing(String in) { return null; } + + public static void testStatic() { + final String s = Integer.toString(new Random().nextInt()); + final Runnable r = () -> { + System.out.println(s); + }; + } } diff --git a/hypo-asm/src/test/java/dev/denwav/hypo/asm/scenarios/Scenario05Test.java b/hypo-asm/src/test/java/dev/denwav/hypo/asm/scenarios/Scenario05Test.java index ce0dc4a..329898e 100644 --- a/hypo-asm/src/test/java/dev/denwav/hypo/asm/scenarios/Scenario05Test.java +++ b/hypo-asm/src/test/java/dev/denwav/hypo/asm/scenarios/Scenario05Test.java @@ -72,11 +72,11 @@ public void testLambdaCalls() throws Exception { assertNotNull(methodClosure); final MethodData call = methodClosure.getClosure(); assertNotNull(call); - assertArrayEquals(new int[] { 1, 2, 4 }, methodClosure.getParamLvtIndices()); + assertArrayEquals(new int[] { 0, 1, 2, 4 }, methodClosure.getParamLvtIndices()); assertEquals(testClass, call.parentClass()); assertTrue(call.isSynthetic()); - assertTrue(call.isStatic()); + assertFalse(call.isStatic()); final List> nestedCalls = call.get(HypoHydration.LAMBDA_CALLS); assertNotNull(nestedCalls); @@ -112,4 +112,28 @@ public void testLambdaCalls() throws Exception { .orElse(null); assertNotNull(outerNestedMethodClosure); } + + @Test + @DisplayName("Test lambda call hydrator on statics") + public void testStaticLambdaCalls() throws Exception { + final var testClass = this.context().getProvider().findClass("scenario05/TestClass"); + assertNotNull(testClass); + + final MethodData testMethod = testClass.method("testStatic", parseDescriptor("()V")); + assertNotNull(testMethod); + + final List> methodClosures = testMethod.get(HypoHydration.LAMBDA_CALLS); + assertNotNull(methodClosures); + assertEquals(1, methodClosures.size()); + + final MethodClosure methodClosure = methodClosures.get(0); + assertNotNull(methodClosure); + final MethodData call = methodClosure.getClosure(); + assertNotNull(call); + assertArrayEquals(new int[] { 0 }, methodClosure.getParamLvtIndices()); + + assertEquals(testClass, call.parentClass()); + assertTrue(call.isSynthetic()); + assertTrue(call.isStatic()); + } } diff --git a/hypo-mappings/src/main/java/dev/denwav/hypo/mappings/contributors/CopyMappingsDown.java b/hypo-mappings/src/main/java/dev/denwav/hypo/mappings/contributors/CopyMappingsDown.java index 89500d5..deeeb08 100644 --- a/hypo-mappings/src/main/java/dev/denwav/hypo/mappings/contributors/CopyMappingsDown.java +++ b/hypo-mappings/src/main/java/dev/denwav/hypo/mappings/contributors/CopyMappingsDown.java @@ -46,15 +46,31 @@ */ public class CopyMappingsDown implements ChangeContributor { - private CopyMappingsDown() {} + private final boolean stopOnChildMapping; + + private CopyMappingsDown(final boolean stopOnChildMapping) { + this.stopOnChildMapping = stopOnChildMapping; + } /** - * Create a new instance of {@link CopyMappingsDown}. + * Create a new instance of {@link CopyMappingsDown}. This instance will overwrite mappings any child method has + * with mappings provided by the parent method. * @return A new instance of {@link CopyMappingsDown}. */ @Contract(value = "-> new", pure = true) public static @NotNull CopyMappingsDown create() { - return new CopyMappingsDown(); + return new CopyMappingsDown(false); + } + + /** + * Create a new instance of {@link CopyMappingsDown}. This instance will not overwrite mappings on any child method. + * If a child method already contains mappings, that method will become the new "root" and the mappings in that + * child method will be propagated to its children instead. + * @return A new instance of {@link CopyMappingsDown}. + */ + @Contract(value = "-> new", pure = true) + public static @NotNull CopyMappingsDown createWithoutOverwrite() { + return new CopyMappingsDown(true); } @Override @@ -75,36 +91,43 @@ public void contribute( } if (!method.isConstructor()) { - walkDown(method, methodMapping, registry); + this.walkDown(method, methodMapping, registry); } else { walkConstructor(method, methodMapping, registry, null); } } } - private static void walkDown( + private void walkDown( final @NotNull MethodData method, final @NotNull MethodMapping mapping, final @NotNull ChangeRegistry registry ) { for (final MethodData childMethod : method.childMethods()) { - setChangeAndWalkDown(childMethod, mapping, registry); + this.setChangeAndWalkDown(childMethod, mapping, registry); } final MethodData syntheticTarget = method.get(HypoHydration.SYNTHETIC_TARGET); if (syntheticTarget != null) { - setChangeAndWalkDown(syntheticTarget, mapping, registry); + this.setChangeAndWalkDown(syntheticTarget, mapping, registry); } } - private static void setChangeAndWalkDown( + private void setChangeAndWalkDown( final @NotNull MethodData method, final @NotNull MethodMapping mapping, final @NotNull ChangeRegistry registry ) { + if (this.stopOnChildMapping) { + final ClassMapping classMapping = getClassMapping(mapping.getMappings(), method.parentClass().name()); + final MethodMapping methodMapping = getMethodMapping(classMapping, method.name(), method.descriptorText()); + if (methodMapping != null) { + return; + } + } registry.submitChange(CopyMethodMappingChange.of(MemberReference.of(method), mapping)); - walkDown(method, mapping, registry); + this.walkDown(method, mapping, registry); } private static void walkConstructor(