From 5a96486853f8496dd4c7cf51f37389798311cfef Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Wed, 31 Dec 2014 15:09:51 +0300 Subject: [PATCH] decompiler: do not fail on nested lambdas --- .../java/decompiler/main/AssertProcessor.java | 6 ++-- .../main/ClassReference14Processor.java | 6 ++-- .../java/decompiler/main/ClassWriter.java | 22 ++++++--------- .../decompiler/main/ClassesProcessor.java | 10 ++++++- .../main/rels/NestedClassProcessor.java | 26 +++++++++--------- .../main/rels/NestedMemberAccess.java | 10 +++---- .../decompiler/exps/AssignmentExprent.java | 2 +- .../decompiler/exps/InvocationExprent.java | 4 +-- .../modules/decompiler/exps/NewExprent.java | 8 +++--- testData/classes/pkg/TestClassLambda.class | Bin 3723 -> 4037 bytes testData/results/TestClassLambda.dec | 18 ++++++++++++ testData/src/pkg/TestClassLambda.java | 8 ++++++ 12 files changed, 74 insertions(+), 46 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/main/AssertProcessor.java b/src/org/jetbrains/java/decompiler/main/AssertProcessor.java index cd45dd1..5b204d4 100644 --- a/src/org/jetbrains/java/decompiler/main/AssertProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/AssertProcessor.java @@ -41,7 +41,7 @@ public class AssertProcessor { public static void buildAssertions(ClassNode node) { - ClassWrapper wrapper = node.wrapper; + ClassWrapper wrapper = node.getWrapper(); StructField field = findAssertionField(node); @@ -67,7 +67,7 @@ public class AssertProcessor { private static StructField findAssertionField(ClassNode node) { - ClassWrapper wrapper = node.wrapper; + ClassWrapper wrapper = node.getWrapper(); boolean noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET); @@ -105,7 +105,7 @@ public class AssertProcessor { ClassNode nd = node; while (nd != null) { - if (nd.wrapper.getClassStruct().qualifiedName.equals(cexpr.getValue())) { + if (nd.getWrapper().getClassStruct().qualifiedName.equals(cexpr.getValue())) { break; } nd = nd.parent; diff --git a/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java b/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java index 3d34aae..b97accf 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java +++ b/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java @@ -85,7 +85,7 @@ public class ClassReference14Processor { public void processClassReferences(ClassNode node) { - ClassWrapper wrapper = node.wrapper; + ClassWrapper wrapper = node.getWrapper(); // int major_version = wrapper.getClassStruct().major_version; // int minor_version = wrapper.getClassStruct().minor_version; @@ -123,7 +123,7 @@ public class ClassReference14Processor { final HashMap mapClassMeths, final HashSet setFound) { - final ClassWrapper wrapper = node.wrapper; + final ClassWrapper wrapper = node.getWrapper(); // search code for (MethodWrapper meth : wrapper.getMethods()) { @@ -176,7 +176,7 @@ public class ClassReference14Processor { private void mapClassMethods(ClassNode node, Map map) { boolean noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET); - ClassWrapper wrapper = node.wrapper; + ClassWrapper wrapper = node.getWrapper(); for (MethodWrapper method : wrapper.getMethods()) { StructMethod mt = method.methodStruct; diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index 612255f..a996eb8 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -56,7 +56,7 @@ public class ClassWriter { } private void invokeProcessors(ClassNode node) { - ClassWrapper wrapper = node.wrapper; + ClassWrapper wrapper = node.getWrapper(); StructClass cl = wrapper.getClassStruct(); InitializerProcessor.extractInitializers(wrapper); @@ -75,12 +75,8 @@ public class ClassWriter { } public void classLambdaToJava(ClassNode node, TextBuffer buffer, Exprent method_object, int indent) { - // get the class node with the content method - ClassNode classNode = node; - while (classNode != null && classNode.type == ClassNode.CLASS_LAMBDA) { - classNode = classNode.parent; - } - if (classNode == null) { + ClassWrapper wrapper = node.getWrapper(); + if (wrapper == null) { return; } @@ -92,7 +88,6 @@ public class ClassWriter { BytecodeMappingTracer tracer = new BytecodeMappingTracer(); try { - ClassWrapper wrapper = classNode.wrapper; StructClass cl = wrapper.getClassStruct(); DecompilerContext.getLogger().startWriteClass(node.simpleName); @@ -144,7 +139,7 @@ public class ClassWriter { buffer.append(" {").appendLineSeparator(); - methodLambdaToJava(node, classNode, mt, buffer, indent + 1, !lambdaToAnonymous, tracer); + methodLambdaToJava(node, wrapper, mt, buffer, indent + 1, !lambdaToAnonymous, tracer); buffer.appendIndent(indent).append("}"); } @@ -167,7 +162,7 @@ public class ClassWriter { // last minute processing invokeProcessors(node); - ClassWrapper wrapper = node.wrapper; + ClassWrapper wrapper = node.getWrapper(); StructClass cl = wrapper.getClassStruct(); DecompilerContext.getLogger().startWriteClass(cl.qualifiedName); @@ -287,7 +282,7 @@ public class ClassWriter { return; } - ClassWrapper wrapper = node.wrapper; + ClassWrapper wrapper = node.getWrapper(); StructClass cl = wrapper.getClassStruct(); int flags = node.type == ClassNode.CLASS_ROOT ? cl.getAccessFlags() : node.access; @@ -474,12 +469,11 @@ public class ClassWriter { } private static void methodLambdaToJava(ClassNode lambdaNode, - ClassNode classNode, + ClassWrapper classWrapper, StructMethod mt, TextBuffer buffer, int indent, boolean codeOnly, BytecodeMappingTracer tracer) { - ClassWrapper classWrapper = classNode.wrapper; MethodWrapper methodWrapper = classWrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()); MethodWrapper outerWrapper = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER); @@ -562,7 +556,7 @@ public class ClassWriter { } private boolean methodToJava(ClassNode node, StructMethod mt, TextBuffer buffer, int indent, BytecodeMappingTracer tracer) { - ClassWrapper wrapper = node.wrapper; + ClassWrapper wrapper = node.getWrapper(); StructClass cl = wrapper.getClassStruct(); MethodWrapper methodWrapper = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()); diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java index 80d3493..4f155e5 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java @@ -354,7 +354,7 @@ public class ClassesProcessor { public int access; public String simpleName; public StructClass classStruct; - public ClassWrapper wrapper; + private ClassWrapper wrapper; public String enclosingMethod; public InvocationExprent superInvocation; public Map mapFieldsToVars = new HashMap(); @@ -419,6 +419,14 @@ public class ClassesProcessor { return null; } + public ClassWrapper getWrapper() { + ClassNode node = this; + while (node.type == CLASS_LAMBDA) { + node = node.parent; + } + return node.wrapper; + } + public static class LambdaInformation { public String class_name; public String method_name; diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java index 1525226..490290e 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java @@ -49,8 +49,8 @@ public class NestedClassProcessor { // hide synthetic lambda content methods if (node.type == ClassNode.CLASS_LAMBDA && !node.lambdaInformation.is_method_reference) { ClassNode node_content = DecompilerContext.getClassProcessor().getMapRootClasses().get(node.classStruct.qualifiedName); - if (node_content != null && node_content.wrapper != null) { - node_content.wrapper.getHiddenMembers().add(node.lambdaInformation.content_method_key); + if (node_content != null && node_content.getWrapper() != null) { + node_content.getWrapper().getHiddenMembers().add(node.lambdaInformation.content_method_key); } } @@ -91,7 +91,7 @@ public class NestedClassProcessor { insertLocalVars(node, child); if (child.type == ClassNode.CLASS_LOCAL) { - setLocalClassDefinition(node.wrapper.getMethods().getWithKey(child.enclosingMethod), child); + setLocalClassDefinition(node.getWrapper().getMethods().getWithKey(child.enclosingMethod), child); } } } @@ -107,8 +107,8 @@ public class NestedClassProcessor { return; } - final MethodWrapper meth = parent.wrapper.getMethods().getWithKey(child.lambdaInformation.content_method_key); - final MethodWrapper encmeth = parent.wrapper.getMethods().getWithKey(child.enclosingMethod); + final MethodWrapper meth = parent.getWrapper().getMethods().getWithKey(child.lambdaInformation.content_method_key); + final MethodWrapper encmeth = parent.getWrapper().getMethods().getWithKey(child.enclosingMethod); MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(child.lambdaInformation.method_descriptor); final MethodDescriptor md_content = MethodDescriptor.parseDescriptor(child.lambdaInformation.content_method_descriptor); @@ -120,7 +120,7 @@ public class NestedClassProcessor { final boolean is_static_lambda_content = child.lambdaInformation.is_content_method_static; - final String parent_class_name = parent.wrapper.getClassStruct().qualifiedName; + final String parent_class_name = parent.getWrapper().getClassStruct().qualifiedName; final String lambda_class_name = child.simpleName; final VarType lambda_class_type = new VarType(lambda_class_name, true); @@ -272,7 +272,7 @@ public class NestedClassProcessor { cltypes |= nd.type; - HashMap> mask = getMaskLocalVars(nd.wrapper); + HashMap> mask = getMaskLocalVars(nd.getWrapper()); if (mask.isEmpty()) { String message = "Nested class " + nd.classStruct.qualifiedName + " has no constructor!"; DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN); @@ -291,7 +291,7 @@ public class NestedClassProcessor { if (cltypes != ClassNode.CLASS_MEMBER) { // iterate enclosing class - for (final MethodWrapper meth : node.wrapper.getMethods()) { + for (final MethodWrapper meth : node.getWrapper().getMethods()) { if (meth.root != null) { // neither abstract, nor native DirectGraph graph = meth.getOrBuildGraph(); @@ -423,7 +423,7 @@ public class NestedClassProcessor { for (Entry> entmt : entcl.getValue().entrySet()) { mergeListSignatures(entmt.getValue(), intrPairMask, false); - MethodWrapper meth = nestedNode.wrapper.getMethodWrapper("", entmt.getKey()); + MethodWrapper meth = nestedNode.getWrapper().getMethodWrapper("", entmt.getKey()); meth.signatureFields = new ArrayList(); for (VarFieldPair pair : entmt.getValue()) { @@ -436,10 +436,10 @@ public class NestedClassProcessor { private static void insertLocalVars(final ClassNode parent, final ClassNode child) { // enclosing method, is null iff member class - MethodWrapper encmeth = parent.wrapper.getMethods().getWithKey(child.enclosingMethod); + MethodWrapper encmeth = parent.getWrapper().getMethods().getWithKey(child.enclosingMethod); // iterate all child methods - for (final MethodWrapper meth : child.wrapper.getMethods()) { + for (final MethodWrapper meth : child.getWrapper().getMethods()) { if (meth.root != null) { // neither abstract nor native @@ -503,7 +503,7 @@ public class NestedClassProcessor { if (clnode.type != ClassNode.CLASS_MEMBER) { - MethodWrapper enclosing_method = clnode.parent.wrapper.getMethods().getWithKey(clnode.enclosingMethod); + MethodWrapper enclosing_method = clnode.parent.getWrapper().getMethods().getWithKey(clnode.enclosingMethod); varname = enclosing_method.varproc.getVarName(entr.getValue()); vartype = enclosing_method.varproc.getVarType(entr.getValue()); @@ -528,7 +528,7 @@ public class NestedClassProcessor { // hide synthetic field if (clnode == child) { // fields higher up the chain were already handled with their classes StructField fd = child.classStruct.getFields().getWithKey(entr.getKey()); - child.wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor())); + child.getWrapper().getHiddenMembers().add(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor())); } } } diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java b/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java index c5d5c18..f102644 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java +++ b/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java @@ -67,7 +67,7 @@ public class NestedMemberAccess { computeMethodTypes(nd); } - for (MethodWrapper method : node.wrapper.getMethods()) { + for (MethodWrapper method : node.getWrapper().getMethods()) { computeMethodType(node, method); } } @@ -220,7 +220,7 @@ public class NestedMemberAccess { return; } - for (MethodWrapper meth : node.wrapper.getMethods()) { + for (MethodWrapper meth : node.getWrapper().getMethods()) { if (meth.root != null) { @@ -327,8 +327,8 @@ public class NestedMemberAccess { ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(invexpr.getClassname()); MethodWrapper methsource = null; - if (node != null && node.wrapper != null) { - methsource = node.wrapper.getMethodWrapper(invexpr.getName(), invexpr.getStringDescriptor()); + if (node != null && node.getWrapper() != null) { + methsource = node.getWrapper().getMethodWrapper(invexpr.getName(), invexpr.getStringDescriptor()); } if (methsource == null || !mapMethodType.containsKey(methsource)) { @@ -440,7 +440,7 @@ public class NestedMemberAccess { } } if (hide) { - node.wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(invexpr.getName(), invexpr.getStringDescriptor())); + node.getWrapper().getHiddenMembers().add(InterpreterUtil.makeUniqueKey(invexpr.getName(), invexpr.getStringDescriptor())); } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java index 10b1378..95ebdc5 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java @@ -118,7 +118,7 @@ public class AssignmentExprent extends Exprent { if (field.isStatic() && fd.hasModifier(CodeConstants.ACC_FINAL)) { fieldInClassInit = true; } - if (node.wrapper != null && node.wrapper.getHiddenMembers().contains(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()))) { + if (node.getWrapper() != null && node.getWrapper().getHiddenMembers().contains(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()))) { hiddenField = true; } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java index c64f5a7..5ef7bf1 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -324,8 +324,8 @@ public class InvocationExprent extends Exprent { ClassNode newNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(classname); if (newNode != null) { // own class - if (newNode.wrapper != null) { - sigFields = newNode.wrapper.getMethodWrapper("", stringDescriptor).signatureFields; + if (newNode.getWrapper() != null) { + sigFields = newNode.getWrapper().getMethodWrapper("", stringDescriptor).signatureFields; } else { if (newNode.type == ClassNode.CLASS_MEMBER && (newNode.access & CodeConstants.ACC_STATIC) == 0) { // non-static member class diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java index f3d6d2a..ba23463 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java @@ -176,8 +176,8 @@ public class NewExprent extends Exprent { List sigFields = null; if (newnode != null) { // own class - if (newnode.wrapper != null) { - sigFields = newnode.wrapper.getMethodWrapper("", invsuper.getStringDescriptor()).signatureFields; + if (newnode.getWrapper() != null) { + sigFields = newnode.getWrapper().getMethodWrapper("", invsuper.getStringDescriptor()).signatureFields; } else { if (newnode.type == ClassNode.CLASS_MEMBER && (newnode.access & CodeConstants.ACC_STATIC) == 0 && @@ -282,8 +282,8 @@ public class NewExprent extends Exprent { List sigFields = null; if (newnode != null) { // own class - if (newnode.wrapper != null) { - sigFields = newnode.wrapper.getMethodWrapper("", constructor.getStringDescriptor()).signatureFields; + if (newnode.getWrapper() != null) { + sigFields = newnode.getWrapper().getMethodWrapper("", constructor.getStringDescriptor()).signatureFields; } else { if (newnode.type == ClassNode.CLASS_MEMBER && (newnode.access & CodeConstants.ACC_STATIC) == 0 && diff --git a/testData/classes/pkg/TestClassLambda.class b/testData/classes/pkg/TestClassLambda.class index b506ea80c80578af10664df2edb80b36cbb0bd52..c6e62aa1a4d3dedfcb82e31eec752f6c5f59822d 100644 GIT binary patch delta 1652 zcmZ8hYg<%R6n@X#&dgyGr$I>>5#iwuI)H#mgoNcK?xN7ekinS%9R`KL$S!DCOD%18 zwTqgmR8&GnMx|ET#mdrdANtVq^vyrf)4OMexO_Nkuf5*2-t+Fg);ar9E~O4#{&(UW zfD-&^AP@B}|#g$MDFj)x7Tpx%i`)Hp}s{Th;j5ies# zIHOF1EoWVBi-!0~d>|OiD3z-%JLFNz9C^*s>RgN^0{JMAMb@ODeb}$#fWWhOPRBuk zLwH_;S>4+k?hp6*w$}y1UA_MP1P7#v7ZP;5XyPS-m+^{@R|O8^H4{sSzAo?v-lTKH z#7Ztl1&-k@f#q1iT^66?l;-Q$;um-uCrq47u;Y}8xM6{J@UB2PZkAWA^Qzy&h>7=^ z|AC1Q1x{mBU<@DWIHM9zQrlMFPMY3mP0JrbFB2W*3|^LvjtXs$Jm47Q?g#1A4;c#oQJJ6QuzqE&BNzyEhPyOa zdwhc$oZX>ti!V43&~ZiJXZ$K~2WkY?p;}@BTV78suSg^U@TXdsD$Jdg3B7}{?5(iEx& z9Pr>4EI>6Dq5-Xwgp7MzuL2kyYg9@bR9!a=-8lDefq;1{JD;x8qV>VfG}G zx>JjFWEN8mGpeE*h~#mn6dKM7&jjC(x~W@^;PXOT7g==rA0P%}KKX71E2W|M{^9zizG z(3xdg)E5wYK^ax5X-u+HV0KsK7#5^>+Vjr9(msxy*>{)9TUdm-NMltkt1PI)HLeEP ze!*|J%D-s~_xCZ<%A7lK7w%SG3)--mj|#TI7xOx>1s#!C2TLZs&X~6q+YpSPJJ5&z MSnUJ{9k^lez delta 1430 zcmZ9M`&U#|6vsbzUU%lsSuhQX!9=D7gAO`^h(dw_m66(u#HbKPnE)FH8wNwOrk7>W zL%Y4Lh}7(1C1gZc+KV34YOPkk^e?nptNw#l`wUZrO8mF3HUN zJ#`kS<|m7CT6~1L&Say7lT8+zx!&RiZVU>g&CgbD4PtP65QjESIxXRM1#!_C#7(D{ z9a^S4h=*Q{^_lFnD4<0r-xb89Uwga#+)c`4pwXg;v_50d#~$u68L}v$#mip3?$hR8 zZT4H-$NgS1y0QoK=0TH(OdcMaIcV6wI)e5wM~B;0-m;|4{>3rRE^xMIB2*}ru+-q9 zov}T!Xd;&EiMAxu@t$}}@dyV@9#uTXL6gT7PcUo{XzK4z52RDE-J9d--u~`^d=F0s zcq-rI=>X3t4sqDzS%uAW0V)K2Uhx7iit|!{dRbmpyuuMh4Vl%l4axVafh)FsN4MfN zUJo#m@8*pFqlz~U(utEa+taRb=NUe;_qmJBFrOO~mfMxi1@^c*;|z1wuJ$bUhB>F(`-Q#DQzyYM z?IWJG#(w)Z&yeiCvRlo=`68W&CwtPp2F_ivA^T7B=cu)lQxaiE7oe$z&hLITV>4Hb-v$SKN^(UhkOg{2CFI*mKj3^(a_x$FCd;YTkJA> z*a{UbmzX6p3WYM77fU>vL(f?;W4XP^Uu3SxMH>C3TQpw}F_g*_m!afp1#*T#&`U6oTl<3GQWsGuu^zcPpZ^*?l_pw)s_=g`a56(w3Z zPo^DKi(MlX)(T@)j?t~^{HlQ&sr|Di$| ztv!oupiXCSr7+~(h5fIRem{rv#b$<)pQebIs!#J0egu0fV#?duF*<2@Q-+Q6_r!HeYizI7 { + Runnable var1x = () -> { + System.out.println("hello2" + var1); + }; + System.out.println("hello1" + var1); + };// 80 + } } class 'pkg/TestClassLambda' { @@ -150,6 +160,12 @@ class 'pkg/TestClassLambda' { 0 70 1 70 } + + method 'nestedLambdas ()V' { + 0 74 + 1 74 + 8 80 + } } Lines mapping: @@ -171,3 +187,5 @@ Lines mapping: 67 <-> 63 71 <-> 67 75 <-> 71 +79 <-> 75 +80 <-> 81 diff --git a/testData/src/pkg/TestClassLambda.java b/testData/src/pkg/TestClassLambda.java index 589766e..1c29cd5 100644 --- a/testData/src/pkg/TestClassLambda.java +++ b/testData/src/pkg/TestClassLambda.java @@ -74,4 +74,12 @@ public class TestClassLambda { public static int localMax(int first, int second) { return 0; } + + public void nestedLambdas() { + int a =5; + Runnable r1 = () -> { + Runnable r2 = () -> { System.out.println("hello2" + a); }; + System.out.println("hello1" + a); + }; + } }