From 9dc14fc68d5247537cf2d9efda64ba9107e378a3 Mon Sep 17 00:00:00 2001 From: tildejustin Date: Sun, 21 Jan 2024 14:50:02 -0500 Subject: [PATCH] fix lambda to anonymous class regression (#336) * fix lambda to anonymous class option * add regression tests for feature * get method references to decompile correctly again --- .../java/decompiler/main/ClassWriter.java | 18 ++-- .../java/decompiler/SingleClassesTest.java | 16 ++++ .../pkg/TestLambdaToAnonymousClass.dec | 24 ++++++ .../pkg/TestLambdaToAnonymousClass2.dec | 83 +++++++++++++++++++ .../java8/pkg/TestLambdaToAnonymousClass.java | 5 ++ .../pkg/TestLambdaToAnonymousClass2.java | 14 ++++ 6 files changed, 151 insertions(+), 9 deletions(-) create mode 100644 testData/results/pkg/TestLambdaToAnonymousClass.dec create mode 100644 testData/results/pkg/TestLambdaToAnonymousClass2.dec create mode 100644 testData/src/java8/pkg/TestLambdaToAnonymousClass.java create mode 100644 testData/src/java8/pkg/TestLambdaToAnonymousClass2.java diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index 02867cb390..75b89e3896 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -192,10 +192,10 @@ public void classLambdaToJava(ClassNode node, TextBuffer buffer, Exprent method_ MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(node.lambdaInformation.method_descriptor); boolean simpleLambda = false; + boolean written = false; if (!lambdaToAnonymous) { RootStatement root = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root; - boolean written = false; if (DecompilerContext.getOption(IFernflowerPreferences.MARK_CORRESPONDING_SYNTHETICS)) { buffer.append("/* ") .appendMethod(node.lambdaInformation.content_method_name, @@ -310,16 +310,16 @@ public void classLambdaToJava(ClassNode node, TextBuffer buffer, Exprent method_ } } } - - if (!simpleLambda) { - buffer.append(" {").appendLineSeparator(); - - methodLambdaToJava(node, wrapper, mt, buffer, indent + 1, !lambdaToAnonymous); - - buffer.appendIndent(indent).append("}"); - } } } + + if ((!simpleLambda && !written) || lambdaToAnonymous) { + buffer.append(" {").appendLineSeparator(); + + methodLambdaToJava(node, wrapper, mt, buffer, indent + 1, !lambdaToAnonymous); + + buffer.appendIndent(indent).append("}"); + } } } finally { diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 7a65979cb0..fd05daba59 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -140,6 +140,17 @@ public String getMethodDoc(StructClass structClass, StructMethod structMethod) { IFernflowerPreferences.VERIFY_ANONYMOUS_CLASSES, "1", IFernflowerPreferences.MARK_CORRESPONDING_SYNTHETICS, "1" ); + registerSet("Lambda to Anonymous Class", this::registerLambdaToAnonymousClass, + IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "1", + IFernflowerPreferences.DUMP_ORIGINAL_LINES, "1", + IFernflowerPreferences.DUMP_EXCEPTION_ON_ERROR, "0", + IFernflowerPreferences.IGNORE_INVALID_BYTECODE, "1", + IFernflowerPreferences.VERIFY_ANONYMOUS_CLASSES, "1", + IFernflowerPreferences.INCLUDE_ENTIRE_CLASSPATH, "0", + IFernflowerPreferences.TERNARY_CONDITIONS, "1", + IFernflowerPreferences.FORCE_JSR_INLINE, "1", + IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS, "1" + ); // TODO: user renamer class test } @@ -843,4 +854,9 @@ private void registerSyntheticsMarking() { register(JAVA_8, "TestAnonymousClassNaming"); register(JAVA_8, "TestLocalClassNaming"); } + + private void registerLambdaToAnonymousClass() { + register(JAVA_8, "TestLambdaToAnonymousClass"); + register(JAVA_8, "TestLambdaToAnonymousClass2"); + } } diff --git a/testData/results/pkg/TestLambdaToAnonymousClass.dec b/testData/results/pkg/TestLambdaToAnonymousClass.dec new file mode 100644 index 0000000000..5c59b4f9c5 --- /dev/null +++ b/testData/results/pkg/TestLambdaToAnonymousClass.dec @@ -0,0 +1,24 @@ +package pkg; + +public class TestLambdaToAnonymousClass { + Runnable f = new Runnable() { + public run() { + System.out.println();// 4 + } + }; +} + +class 'pkg/TestLambdaToAnonymousClass' { + method 'lambda$new$0 ()V' { + 0 5 + 1 5 + 2 5 + 3 5 + 4 5 + 5 5 + 6 6 + } +} + +Lines mapping: +4 <-> 6 diff --git a/testData/results/pkg/TestLambdaToAnonymousClass2.dec b/testData/results/pkg/TestLambdaToAnonymousClass2.dec new file mode 100644 index 0000000000..2093e3144b --- /dev/null +++ b/testData/results/pkg/TestLambdaToAnonymousClass2.dec @@ -0,0 +1,83 @@ +package pkg; + +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.IntFunction; + +public class TestLambdaToAnonymousClass2 { + public void test() { + BiConsumer, Integer> $ = new BiConsumer() {// 8 + public accept(List l, Integer i) { + Character[] a = (Character[])l.stream().map(new Function() {// 9 + public apply(String st) { + return st.charAt(i);// 10 + } + }).toArray(new IntFunction() { + public apply(int x$0) { + return new Character[x$0];// 11 + } + }); + }// 12 + }; + }// 13 +} + +class 'pkg/TestLambdaToAnonymousClass2' { + method 'test ()V' { + 5 9 + 6 22 + } + + method 'lambda$test$2 (Ljava/util/List;Ljava/lang/Integer;)V' { + 0 11 + 1 11 + 2 11 + 3 11 + 4 11 + 5 11 + c 11 + d 11 + e 11 + f 11 + 10 11 + 16 15 + 17 15 + 18 15 + 19 15 + 1a 15 + 1b 11 + 1c 11 + 1d 11 + 1e 11 + 1f 20 + } + + method 'lambda$null$0 (Ljava/lang/Integer;Ljava/lang/String;)Ljava/lang/Character;' { + 0 13 + 1 13 + 2 13 + 3 13 + 4 13 + 5 13 + 6 13 + 7 13 + 8 13 + 9 13 + a 13 + b 13 + } + + method 'lambda$null$1 (I)[Ljava/lang/Character;' { + 0 17 + 4 17 + } +} + +Lines mapping: +8 <-> 10 +9 <-> 12 +10 <-> 14 +11 <-> 18 +12 <-> 21 +13 <-> 23 diff --git a/testData/src/java8/pkg/TestLambdaToAnonymousClass.java b/testData/src/java8/pkg/TestLambdaToAnonymousClass.java new file mode 100644 index 0000000000..0970660568 --- /dev/null +++ b/testData/src/java8/pkg/TestLambdaToAnonymousClass.java @@ -0,0 +1,5 @@ +package pkg; + +public class TestLambdaToAnonymousClass { + Runnable f = () -> System.out.println(); +} diff --git a/testData/src/java8/pkg/TestLambdaToAnonymousClass2.java b/testData/src/java8/pkg/TestLambdaToAnonymousClass2.java new file mode 100644 index 0000000000..3635770fc9 --- /dev/null +++ b/testData/src/java8/pkg/TestLambdaToAnonymousClass2.java @@ -0,0 +1,14 @@ +package pkg; + +import java.util.List; +import java.util.function.*; + +public class TestLambdaToAnonymousClass2 { + public void test() { + BiConsumer, Integer> $ = (l, i) -> { + Character[] a = l.stream() + .map(st -> st.charAt(i)) + .toArray(Character[]::new); + }; + } +}