From a3332a5f31edbb1ed7ff62bc0c0c13ce4b063608 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 6 Dec 2017 19:26:11 +0100 Subject: [PATCH] [java decompiler] detecting Groovy synthetic constructor parameters --- .../main/rels/NestedClassProcessor.java | 11 +- .../java/decompiler/SingleClassesTest.java | 1 + .../classes/pkg/TestGroovyClass$Inner.class | Bin 0 -> 3870 bytes .../classes/pkg/TestGroovyClass$Nested.class | Bin 0 -> 3807 bytes .../pkg/TestGroovyClass$_closure1.class | Bin 0 -> 2236 bytes .../pkg/TestGroovyClass$_closure2.class | Bin 0 -> 1969 bytes testData/classes/pkg/TestGroovyClass.class | Bin 0 -> 4911 bytes testData/results/TestGroovyClass.dec | 230 ++++++++++++++++++ testData/src/pkg/TestGroovyClass.groovy | 13 + 9 files changed, 250 insertions(+), 5 deletions(-) create mode 100644 testData/classes/pkg/TestGroovyClass$Inner.class create mode 100644 testData/classes/pkg/TestGroovyClass$Nested.class create mode 100644 testData/classes/pkg/TestGroovyClass$_closure1.class create mode 100644 testData/classes/pkg/TestGroovyClass$_closure2.class create mode 100644 testData/classes/pkg/TestGroovyClass.class create mode 100644 testData/results/TestGroovyClass.dec create mode 100644 testData/src/pkg/TestGroovyClass.groovy 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 0000000000000000000000000000000000000000..51242d8e0a41df4ad7ba654797ece7311971ebfb GIT binary patch literal 3870 zcmb7HYgZFj6y28uBI6(sML}z;HI~!SZkM`bgllVuAVb9nG9s`u~=&c?wr@&XWw%#|Ni&aKL9%Mn?OtcTq-iE z7W95Cmz$gK%P56HU?7`SH6MgP!&zlciDZ;)Dl&5BteVh$@CY=g3}bWMbS!f*+RsMtEp2N%9YM#Berd~fNye=A`JBj zh?4@fGpeo_p9MBVofQq0K9En1KAkQEIs}@cE=b9sad}YzayppKruC-?XwcQGZH)a= zs@|t$GO@I-_G+3kFVGcin{Wp-o7K}ZY9vAS1+tHn9J^(##X1R9Xp*r8^|kcd1_4j7 zZA?ZZS|oU}QD7}6iy7qE;HY=OwiR&8cm$g{>Z3Ab)N#};0$%1qV3Qjrv**NzCy*xw zRxvo%0_CPGWfd5URP__s&b74)bh>uX0vtAZeuURSxty-6jnv$EO*>X>2&m~haM z#Z*)G%J9P2At8iz8LLps@FD_1*Fs#R zz&0)!d$|!^*hh$GRDC*^97-1o>1;}1pEG4l*J!cZje|1z7A@2h7cKj6P{41}UN0!VI^NSBh1*n0?1locVj+(5z&Lyi%b6Z3u^kYciz`fGz^LZL7*<^-zjl`yN znm$S^N39hfMyOQ@rJ#@I%-90koei-iSf<~qLB?}9A>lY;6d|b=@|vn7qeQtt&;4MO zkPXnFCl294k)Upm+P+a&}f`sM-BS~YLk(?D+O)KR}2b`5YL|qOvb{8_3;X<>d zD`LYQA_5zOD-3!*iDYx9n^NJSPqU`U^*r=}GTV-~M0n`V_ATbXPb z8O(E#*97)E$y_l=Wg%vl-{2^33akn6IqNu=H#V zu&$O)W$QTKLnq(8CQQX?ZuoV3=xznN3_QH65AO>s*>0wwoV&P0q;Ws^K*9xlDC2Fs z!-wESI^4@sr2?rBAJaZ0^%CMGhq^7mPw=UP%lJ&jyExBM`huk7(i3wGf5o<63sfuS z^{3=TG$4AVsRC z_qHO|4~2)@Lz91^xqUoz9h*Xnch76e+YtV~B^o`g0@GPntYH`?(mm?O~zMql$tNcAT z(I5BTf;a97#j0;%Anx%G#^PRjT*q(`qqi~Oq0gpCIOhFZihDdGMZ8eNDQ6ib8;6bL z6rWOZazS8T#AypmuLY*w2}Ze6ru1G|&RAFycDM=ZHFLAe>Y8{UG)1J^E4tWa*WCq9 zWY#@x)xDQ`$fR-ILq-!8ajp`4o!x^vvj@a{0;M1$#5_x(lY&Gakoh8V&NQ;o)`(dv zF-!MMtHNy*np?hss@odB1Mk9kC{D^H&GJe~S9!c_IrzzetEmZv$%Z??y3=f(v=Fll zxsD`S2!(gtz^h)A!enev&1A%3WYg>hUia8mNxM;%!QS%1%qj8Iv1;0E>}H_R{~if( z@Fp(A{Z+IFKQi-5{BM(Gx|{Mc-r!YSx`Re~F5>gs}w{v*WyUFiUh literal 0 HcmV?d00001 diff --git a/testData/classes/pkg/TestGroovyClass$Nested.class b/testData/classes/pkg/TestGroovyClass$Nested.class new file mode 100644 index 0000000000000000000000000000000000000000..43d2e0e47161f590a8627a10a783a727660f80ef GIT binary patch literal 3807 zcmb7HYg-dX6n-aJjI66bR1`0*Rw^MuqbS}`TcwI<0Ba~VqNQuHgw>EucNf~!+Kau~ z`=97{s;$Oa`}j$pr$4Gs&+JS#3rW0uNyyB(yzhI?nHm25@2`IV?8UDPn@ZR7$qB=8 zhi%JRC=V5M$LSuU-$pJ1#?XFEU(k~Uy_ipqU%h5z-3Y=A8}pvESQnnv-4=$Q7V`{;f+^FkO^bt# zG^mL$WuclhC|(2y7$@HvcyA!l>My^C~g0#!(jyqwA*bF;^3i&-z(?ep=Fod^M zoWv=LkTaZ;ZRoj_>9`EXo<~DQof@IhtOb^<8isL(_t}WouM5_7gDOik9Amf~#3mZ1 zK0shaVr`HmI9`6@b4c;TqcpHZea>Kr*2khf-Okg92KQtHhV}BenqJm+Z6(_(8Ma&Y z8?h%yMdA!(lM#C-8CE%ldtSOToDKR(tAO8&i^7{|5*In)cj+iy&?=k%ycNMZ+P28 zKox(Eyv+;M2yqtqRhYr-vSX*dYRv`Ja0S(4dX50(LjA0watU=e(y6!B^wrf=HM|rUxpeyQGCr{nI>iG?Z>FENxmS5gA zf_XY?gBpm23Ql)bNbgzjp^623q@jcl_-*wu!{*v)Q^z!dPiPFNdx`Oq+t+WvPw|G+@>dwc+=70GelQ9KYT3G zcT%@a{c6FO;2#WX+M2hs#%YuP&_;?y!}b(19Be1F3dz0#E%aET>l;-nz;KqawADJ-w~y^GEu%pCa(ub;j=_T0v(jeh-^Q`{L7oVoTq}-@T&#M4uYj z(_;)<@e0LM_;W}`*hdjUWYI&OuSG+@VP(96*y0^}L?)i1jjvX)CzHC1c;X)REs`nP z86_T&0m=kVp~YcJKNbx|4?e`mEbT&m%@lY zA4Z}%j80D;k(}bo}H2P(cSLOdANz?t5mz&1! z;Kmbl(C0mT@t7RWJ>@6Gm*jjiL$2T4#SIeRdoKbZ{h541h~O9cRw+UV2k`@1{|8WF B>%#y5 literal 0 HcmV?d00001 diff --git a/testData/classes/pkg/TestGroovyClass$_closure1.class b/testData/classes/pkg/TestGroovyClass$_closure1.class new file mode 100644 index 0000000000000000000000000000000000000000..61d5314e56bcc1d9fec899cb02759448bbf2c349 GIT binary patch literal 2236 zcmb7FZBrXn6n<`!vaoDR2nDT(1x-t`(5BGZswr)0YGWjTHi#l>TsAjhY1m~po6hhP z{2_kF)}d%e$4_>~ALaC%-6ck{bf#bK-o5vn=e#}V+<*T4{Z9aMcq}ln_qdT;lP$04 zI?j{*Leprq(p9tRwA!wmQy>IJ8va$TY1oZiA-GWx7npV2M$U9l*t4^O@{s zv=d>BCds!*K6k8`*KiI)Dq=`#&~R2o0x5xnw{5iqE|y=LYzpIC)oFXuE!mU}+mr&S zUT*~ktBeJ4wZ|jjg8a$GZYoBJ+J(s0!XAPdEdG zw(CmU6S$WtcT=V4)8_Q7_qwKG5>tb?i1!6z79pO`LqUnXvH*(yGDmZfL- zln}T;YTcf6t|-OHlY~&93-ojKnNI}yKb!s`m30x_wW7V&FpujhHS7%y{TLXa*l!ACA{~k74+S4ly^kXdx@)1^ zd=O+dn(GmOl#fr4SMf1!2f&@UG~7X!FYXeV)69;pewyg2xGU?qic|L<$+{%=n375} zmNs2UBjdQ6{5Gu4(M4vnOSR&;mfgs6*D8Co^_q4+J|(h5sSDhsdPZjIG-mr|^V}vh z{JQ88*j4bkh5{Zi0n0Qa-W*!N%8AJoEc?B{86y~f*WP^iRq^8h`D#!XMT|NH zrocewaiO_bpeErV=MYoY4cFpXw8o3TP}#EON_%%py5WghaoVmaA6k5^m27%n{KUx? zrYN=q4YfYRlPb3eko*ZM2I;GE-l&-LmhniYwN8Hvh?52|c!c2?-9kgp7SDFoF?o;5TAE$iYC(*auGphi+12a^e8kPY>&hkDccA#$nM z&*;~W@ZrHz+$zt!#1NkzVPT{E47X+uagQD36cM3AfDwv?!4*9@e`A=|Lu~v-3QI4MI>P4C3#@OD e>JQJbrvHj9AAy3f$Zm{^wnJZ)uwtk|Lc9WjMNruQ literal 0 HcmV?d00001 diff --git a/testData/classes/pkg/TestGroovyClass$_closure2.class b/testData/classes/pkg/TestGroovyClass$_closure2.class new file mode 100644 index 0000000000000000000000000000000000000000..50c203eb3bdb7dae9f1d3bde25810e3b66b0ff33 GIT binary patch literal 1969 zcmb7E?^6?36g@YIELm0w5oy(;)TWYb&;_*GHew5Dr6~bhgD7H~S(cZ$HtaIH8)x_v z`iJy8)ebW4w9`*@rhinY_w6n*!nQMh*&pxSd)__go_GKL=hr^~%;0;%_|6Y)V^#RU zqUXBLcB>uJ_X|y{2|nfbWEphRHGdQX~LB2wGGSN5>L#oZ^Thv*9q)x zVJr$qcxE8BdKo7OV@FQ98YK~O1wSwY+X~OGIW3o<*AwAIt0Szyb{#H-Yn8DTg3@d< z!g7^Bj|c;|Y{w366DEuGr{*&=D*f)}Q_id$Un#8-Mha~aRLxGOVFzN~^UPhsY_YVF zTtv*#;&`9qjl;x>hEo_;kwQ*`hLb8X$P+Tb6Wb?TtpBgrOygA3?FPcDIjn|b2}1sO zwS=Lj#Ea-K*)3NdPq>^wwv?2w)h4$mWbNi=M-1XTA!P@I(PBchhO;;)30-6(NR1j{ zpO!^nhWZoEa$3JbdRxpVcT{}^9}otm)UtUD`No;yB5U{|E~_YDk}#9#fmr^A<=H#I z!fqg>3Fo)W9o9}kiEvW(zgGyMoG49l)f&o}QlaCDhCyVr%-tXq6AMW&qkH;mJjnPX`Ux|qu-6dvz@kr&-fm_J)na5Beyq_ZKID> zbV8-HCa+pm#R9(2@F^;?V|NJWUwiKue+6F=(%d8sU*m#`8kRKN!kjevGT}^rzv8hG z9dlR4enU86Mk8YS?FYm?G_qXlDw{uH94O#nl zw;i$4-QE;lyrMSTu4jomw%pcg4$t6FIN{@c=9b|e4IrIUrL%$Dk5DnhZ&m8X9US0& z9$Wle=f63mIRh9vz{rYTo_dMXKZk98#Lo%d1gDSU48P^q7~bJT`SmV;rTCjiM-Phi z=DjRKE$83cqdopfK?05O8&G;c3dTdA4PKS?WVj*;bs>h*IbLRH3{}@@9}^K8g=jLi zS5_{=tS`lR*W$cMeILbq>L(292e`WT9MkpkD-6rk1Ke1zzrb{PAD_qqr7-M@7+^e< z4;abc{vDq${f340d`f?bFAqa`^v9vsnXIg%_#BIWVT7OisQ<|cORtbWzzQeV);aat d7g*GP!Tk_{>wC;ODc0gUeyfa-!UH@6{R{TM1YrOG literal 0 HcmV?d00001 diff --git a/testData/classes/pkg/TestGroovyClass.class b/testData/classes/pkg/TestGroovyClass.class new file mode 100644 index 0000000000000000000000000000000000000000..de9df4bc23ea1520daa8aeedaf43867c3fcf33ba GIT binary patch literal 4911 zcmbVQ`(G5-75`pXSXsx2YeY$6s$?5sL02Rg18PdJ8Wb>LDY&sM9d`#lB)96130dR#2wGeS-n2V#8EzWO~VxRk$~hWxzBIOE@fry9ZZbjTB8&KbJFvlva3` zODfvgTq2z}(?!cNOgqu9=W-rb*ZLfXeX^6bl{Ke&k5YDHtYGVQHto1(z?{r0#0T@% z6qRI*X}wrTcs{X=$sGNZ&6|k|FVBZ3CMaR3pD3SFXqYi<-61P%AM|^3s7&CQEjR0o zDbyd%npyj(LTzi?n1&r_jv$14gn7!a#mr>ZHu@|}pI120+IBV=WYM&C{Rk zm+6+)wkm0^;k`I633o!nHZ+Np0fmq~oh>MA3u*bOdSeI_OzXz0EqF*3C?geL9hx&Re!r z_T%187#HX#x8hydw{A5a1`RVXBglb`UdtGTSDwkz1MJIrHoQyYEVBdb=7v z3`=r~x!dH%hf$o)XHJ{_?qxNskXf50tIEfJ=l1$^c;Exn`irE3q=-2|@-*ws)MwZb zqibc6rdv}4>!*1V*veOOtzg)aXsh~-hsP(?JJ~kIi;pM#hCE^AXAR5dy*1)D-#g)x z;g-#vI7Bk)6ZoVU`zeLGIXzdTwLb7HQUSl}9`e8kc#hb4AQ=0Te(di6sn5Y)rm`~tqV5nsjE z6*kgSE0Mj${a4-P8eYUVMdY_Al1^9=`N%uP&761%-w~PLWs(yn3-5m3CP8;V2{z^^!D2Z>QQNXYAT zIaV_;w7nb`-63?TRnqU@eCCM!Othmkz@m>@^s* zB)cpf$Ns z?Q`|fHqO(YmIufqc5jbg#>v!mgcio*DTbawmz{D*zKAb*2clj~>*MX@5#uCeFH}O- z%zz2(O^oiB|ZPDK{e^0RZ)fT~#vx literal 0 HcmV?d00001 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