diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java index 20f4859..649520c 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java @@ -376,10 +376,8 @@ public class NestedClassProcessor { mergeListSignatures(entry.getValue(), interPairMask, false); List mask = new ArrayList<>(entry.getValue().size()); - boolean firstSignField = nestedNode.type != ClassNode.CLASS_ANONYMOUS; for (VarFieldPair pair : entry.getValue()) { - mask.add(pair == null || (!firstSignField && pair.fieldKey.isEmpty()) ? null : pair.varPair); - firstSignField = false; + mask.add(pair != null && !pair.fieldKey.isEmpty() ? pair.varPair : null); } nestedNode.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, entry.getKey()).synthParameters = mask; } @@ -620,8 +618,7 @@ public class NestedClassProcessor { StructField fd = cl.getField(left.getName(), left.getDescriptor().descriptorString); if (fd != null && cl.qualifiedName.equals(left.getClassname()) && - fd.hasModifier(CodeConstants.ACC_FINAL) && - (fd.isSynthetic() || noSynthFlag && fd.hasModifier(CodeConstants.ACC_PRIVATE))) { + (fd.isSynthetic() || noSynthFlag && possiblySyntheticField(fd))) { // local (== not inherited) field field = InterpreterUtil.makeUniqueKey(left.getName(), left.getDescriptor().descriptorString); break; @@ -634,6 +631,10 @@ public class NestedClassProcessor { return field; } + private static boolean possiblySyntheticField(StructField fd) { + return fd.getName().contains("$") && fd.hasModifier(CodeConstants.ACC_FINAL) && fd.hasModifier(CodeConstants.ACC_PRIVATE); + } + private static void mergeListSignatures(List first, List second, boolean both) { int i = 1; diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 0c24ed8..8ab660f 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -111,6 +111,7 @@ public class SingleClassesTest { //@Test public void testInUse() { doTest("pkg/TestInUse"); } //@Test public void testInterfaceSuper() { doTest("pkg/TestInterfaceSuper"); } + @Test public void testGroovyClass() { doTest("pkg/TestGroovyClass"); } @Test public void testGroovyTrait() { doTest("pkg/TestGroovyTrait"); } private void doTest(String testFile, String... companionFiles) { diff --git a/testData/classes/pkg/TestGroovyClass$Inner.class b/testData/classes/pkg/TestGroovyClass$Inner.class new file mode 100644 index 0000000..51242d8 Binary files /dev/null and b/testData/classes/pkg/TestGroovyClass$Inner.class differ diff --git a/testData/classes/pkg/TestGroovyClass$Nested.class b/testData/classes/pkg/TestGroovyClass$Nested.class new file mode 100644 index 0000000..43d2e0e Binary files /dev/null and b/testData/classes/pkg/TestGroovyClass$Nested.class differ diff --git a/testData/classes/pkg/TestGroovyClass$_closure1.class b/testData/classes/pkg/TestGroovyClass$_closure1.class new file mode 100644 index 0000000..61d5314 Binary files /dev/null and b/testData/classes/pkg/TestGroovyClass$_closure1.class differ diff --git a/testData/classes/pkg/TestGroovyClass$_closure2.class b/testData/classes/pkg/TestGroovyClass$_closure2.class new file mode 100644 index 0000000..50c203e Binary files /dev/null and b/testData/classes/pkg/TestGroovyClass$_closure2.class differ diff --git a/testData/classes/pkg/TestGroovyClass.class b/testData/classes/pkg/TestGroovyClass.class new file mode 100644 index 0000000..de9df4b Binary files /dev/null and b/testData/classes/pkg/TestGroovyClass.class differ diff --git a/testData/results/TestGroovyClass.dec b/testData/results/TestGroovyClass.dec new file mode 100644 index 0000000..02ede11 --- /dev/null +++ b/testData/results/TestGroovyClass.dec @@ -0,0 +1,230 @@ +package pkg; + +import groovy.lang.Closure; +import groovy.lang.GroovyObject; +import groovy.lang.MetaClass; +import java.util.concurrent.Callable; +import org.codehaus.groovy.runtime.GeneratedClosure; +import org.codehaus.groovy.runtime.ScriptBytecodeAdapter; +import org.codehaus.groovy.runtime.callsite.CallSite; + +public class TestGroovyClass implements GroovyObject { + private final TestGroovyClass.Nested n; + private final TestGroovyClass.Inner i; + private final Runnable r; + private final Callable c; + + public TestGroovyClass() { + CallSite[] var1 = $getCallSiteArray(); + Object var2 = var1[0].callConstructor(TestGroovyClass.Nested.class);// 9 + this.n = (TestGroovyClass.Nested)ScriptBytecodeAdapter.castToType(var2, TestGroovyClass.Nested.class); + Object var3 = var1[1].callConstructor(TestGroovyClass.Inner.class, this); + this.i = (TestGroovyClass.Inner)ScriptBytecodeAdapter.castToType(var3, TestGroovyClass.Inner.class); + TestGroovyClass._closure1 var4 = new TestGroovyClass._closure1(this, this);// 10 + this.r = var4; + TestGroovyClass._closure2 var5 = new TestGroovyClass._closure2(this, this); + this.c = var5; + MetaClass var6 = this.$getStaticMetaClass(); + this.metaClass = var6; + } + + public final TestGroovyClass.Nested getN() { + return this.n; + } + + public final TestGroovyClass.Inner getI() { + return this.i; + } + + public final Runnable getR() { + return this.r; + } + + public final Callable getC() { + return this.c; + } + + public static class Nested implements GroovyObject { + public Nested() { + CallSite[] var1 = $getCallSiteArray(); + MetaClass var2 = this.$getStaticMetaClass(); + this.metaClass = var2; + } + } + + public class Inner implements GroovyObject { + public Inner() { + CallSite[] var2 = $getCallSiteArray(); + super(); + MetaClass var4 = this.$getStaticMetaClass(); + this.metaClass = var4; + } + } + + public class _closure1 extends Closure implements GeneratedClosure { + public _closure1(Object _outerInstance, Object _thisObject) { + CallSite[] var3 = $getCallSiteArray(); + super(_outerInstance, _thisObject); + } + + public Object doCall(Object it) { + CallSite[] var2 = $getCallSiteArray(); + return var2[0].callCurrent(this, "I'm runnable");// 11 + } + + public Object doCall() { + CallSite[] var1 = $getCallSiteArray(); + return this.doCall((Object)null); + } + } + + public class _closure2 extends Closure implements GeneratedClosure { + public _closure2(Object _outerInstance, Object _thisObject) { + CallSite[] var3 = $getCallSiteArray(); + super(_outerInstance, _thisObject); + } + + public Object doCall(Object it) { + CallSite[] var2 = $getCallSiteArray(); + return "I'm callable";// 12 + } + + public Object doCall() { + CallSite[] var1 = $getCallSiteArray(); + return this.doCall((Object)null); + } + } +} + +class 'pkg/TestGroovyClass' { + method ' ()V' { + 4 17 + 7 17 + 9 18 + b 18 + c 18 + e 18 + 13 18 + 15 19 + 17 19 + 1a 19 + 1f 19 + 25 20 + 27 20 + 28 20 + 2b 20 + 30 20 + 32 21 + 34 21 + 37 21 + 3c 21 + 4a 22 + 50 23 + 5f 24 + 65 25 + 6c 26 + 6f 26 + 75 27 + 7b 28 + } + + method 'getN ()Lpkg/TestGroovyClass$Nested;' { + 1 31 + 4 31 + } + + method 'getI ()Lpkg/TestGroovyClass$Inner;' { + 1 35 + 4 35 + } + + method 'getR ()Ljava/lang/Runnable;' { + 1 39 + 4 39 + } + + method 'getC ()Ljava/util/concurrent/Callable;' { + 1 43 + 4 43 + } +} + +class 'pkg/TestGroovyClass$Nested' { + method ' ()V' { + 4 48 + 7 48 + 9 49 + c 49 + 10 50 + 15 51 + } +} + +class 'pkg/TestGroovyClass$Inner' { + method ' (Lpkg/TestGroovyClass;)V' { + 0 56 + 3 56 + f 57 + 13 58 + 16 58 + 1c 59 + 22 60 + } +} + +class 'pkg/TestGroovyClass$_closure1' { + method ' (Ljava/lang/Object;Ljava/lang/Object;)V' { + 0 65 + 3 65 + 7 66 + a 67 + } + + method 'doCall (Ljava/lang/Object;)Ljava/lang/Object;' { + 0 70 + 3 70 + 5 71 + 7 71 + 9 71 + b 71 + 10 71 + } + + method 'doCall ()Ljava/lang/Object;' { + 0 75 + 3 75 + 5 76 + 6 76 + 9 76 + } +} + +class 'pkg/TestGroovyClass$_closure2' { + method ' (Ljava/lang/Object;Ljava/lang/Object;)V' { + 0 82 + 3 82 + 7 83 + a 84 + } + + method 'doCall (Ljava/lang/Object;)Ljava/lang/Object;' { + 0 87 + 3 87 + 4 88 + 6 88 + } + + method 'doCall ()Ljava/lang/Object;' { + 0 92 + 3 92 + 5 93 + 6 93 + 9 93 + } +} + +Lines mapping: +9 <-> 19 +10 <-> 23 +11 <-> 72 +12 <-> 89 diff --git a/testData/src/pkg/TestGroovyClass.groovy b/testData/src/pkg/TestGroovyClass.groovy new file mode 100644 index 0000000..899aab2 --- /dev/null +++ b/testData/src/pkg/TestGroovyClass.groovy @@ -0,0 +1,13 @@ +package pkg + +import java.util.concurrent.Callable + +class TestGroovyClass { + static class Nested { } + class Inner { } + + final Nested n = new Nested() + final Inner i = new Inner() + final Runnable r = { println("I'm runnable") } + final Callable c = { "I'm callable" } +} \ No newline at end of file