From 8b9687ed20e40fbf46dea055f0a423b49f1bf693 Mon Sep 17 00:00:00 2001 From: Egor Ushakov Date: Wed, 10 Jan 2018 16:28:43 +0300 Subject: [PATCH] IDEA-184560 Java decompiler doesn't use stored parameter names --- .../java/decompiler/code/CodeConstants.java | 5 +- .../java/decompiler/main/ClassWriter.java | 25 +++- .../main/extern/IFernflowerPreferences.java | 6 +- .../struct/attr/StructGeneralAttribute.java | 8 +- .../attr/StructMethodParametersAttribute.java | 56 ++++++++ .../java/decompiler/SingleClassesTest.java | 5 +- .../pkg/TestMethodParametersAttr$1Local.class | Bin 0 -> 729 bytes .../pkg/TestMethodParametersAttr$C1.class | Bin 0 -> 677 bytes .../pkg/TestMethodParametersAttr$C2.class | Bin 0 -> 627 bytes .../pkg/TestMethodParametersAttr$C3.class | Bin 0 -> 624 bytes .../pkg/TestMethodParametersAttr$C4.class | Bin 0 -> 488 bytes .../pkg/TestMethodParametersAttr$I1.class | Bin 0 -> 306 bytes .../pkg/TestMethodParametersAttr.class | Bin 0 -> 981 bytes testData/results/TestMethodParametersAttr.dec | 125 ++++++++++++++++++ .../src/pkg/TestMethodParametersAttr.java | 56 ++++++++ 15 files changed, 279 insertions(+), 7 deletions(-) create mode 100644 src/org/jetbrains/java/decompiler/struct/attr/StructMethodParametersAttribute.java create mode 100644 testData/classes/pkg/TestMethodParametersAttr$1Local.class create mode 100644 testData/classes/pkg/TestMethodParametersAttr$C1.class create mode 100644 testData/classes/pkg/TestMethodParametersAttr$C2.class create mode 100644 testData/classes/pkg/TestMethodParametersAttr$C3.class create mode 100644 testData/classes/pkg/TestMethodParametersAttr$C4.class create mode 100644 testData/classes/pkg/TestMethodParametersAttr$I1.class create mode 100644 testData/classes/pkg/TestMethodParametersAttr.class create mode 100644 testData/results/TestMethodParametersAttr.dec create mode 100644 testData/src/pkg/TestMethodParametersAttr.java diff --git a/src/org/jetbrains/java/decompiler/code/CodeConstants.java b/src/org/jetbrains/java/decompiler/code/CodeConstants.java index 4ff5daa..a8f9f36 100644 --- a/src/org/jetbrains/java/decompiler/code/CodeConstants.java +++ b/src/org/jetbrains/java/decompiler/code/CodeConstants.java @@ -1,4 +1,6 @@ -// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +/* + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ package org.jetbrains.java.decompiler.code; @SuppressWarnings({"unused", "SpellCheckingInspection"}) @@ -70,6 +72,7 @@ public interface CodeConstants { int ACC_SYNTHETIC = 0x1000; int ACC_ANNOTATION = 0x2000; int ACC_ENUM = 0x4000; + int ACC_MANDATED = 0x8000; // ---------------------------------------------------------------------- // CLASS FLAGS diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index 210529f..8d862c8 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package org.jetbrains.java.decompiler.main; @@ -697,6 +697,15 @@ public class ClassWriter { } } + List methodParameters = null; + if (DecompilerContext.getOption(IFernflowerPreferences.USE_METHOD_PARAMETERS)) { + StructMethodParametersAttribute attr = + (StructMethodParametersAttribute)mt.getAttribute(StructGeneralAttribute.ATTRIBUTE_METHOD_PARAMETERS); + if (attr != null) { + methodParameters = attr.getEntries(); + } + } + int index = isEnum && init ? 3 : thisVar ? 1 : 0; int start = isEnum && init ? 2 : 0; for (int i = start; i < md.params.length; i++) { @@ -707,7 +716,10 @@ public class ClassWriter { appendParameterAnnotations(buffer, mt, paramCount); - if (methodWrapper.varproc.getVarFinal(new VarVersionPair(index, 0)) == VarTypeProcessor.VAR_EXPLICIT_FINAL) { + if (methodParameters != null && paramCount < methodParameters.size()) { + appendModifiers(buffer, methodParameters.get(paramCount).myAccessFlags, CodeConstants.ACC_FINAL, isInterface, 0); + } + else if (methodWrapper.varproc.getVarFinal(new VarVersionPair(index, 0)) == VarTypeProcessor.VAR_EXPLICIT_FINAL) { buffer.append("final "); } @@ -741,7 +753,14 @@ public class ClassWriter { } buffer.append(' '); - String parameterName = methodWrapper.varproc.getVarName(new VarVersionPair(index, 0)); + + String parameterName; + if (methodParameters != null && paramCount < methodParameters.size()) { + parameterName = methodParameters.get(paramCount).myName; + } + else { + parameterName = methodWrapper.varproc.getVarName(new VarVersionPair(index, 0)); + } buffer.append(parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors paramCount++; diff --git a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java index cda288b..3c0fac5 100644 --- a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java +++ b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java @@ -1,4 +1,6 @@ -// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +/* + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ package org.jetbrains.java.decompiler.main.extern; import org.jetbrains.java.decompiler.util.InterpreterUtil; @@ -25,6 +27,7 @@ public interface IFernflowerPreferences { String SYNTHETIC_NOT_SET = "nns"; String UNDEFINED_PARAM_TYPE_OBJECT = "uto"; String USE_DEBUG_VAR_NAMES = "udv"; + String USE_METHOD_PARAMETERS = "ump"; String REMOVE_EMPTY_RANGES = "rer"; String FINALLY_DEINLINE = "fdi"; String IDEA_NOT_NULL_ANNOTATION = "inn"; @@ -67,6 +70,7 @@ public interface IFernflowerPreferences { defaults.put(SYNTHETIC_NOT_SET, "0"); defaults.put(UNDEFINED_PARAM_TYPE_OBJECT, "1"); defaults.put(USE_DEBUG_VAR_NAMES, "1"); + defaults.put(USE_METHOD_PARAMETERS, "1"); defaults.put(REMOVE_EMPTY_RANGES, "1"); defaults.put(FINALLY_DEINLINE, "1"); defaults.put(IDEA_NOT_NULL_ANNOTATION, "1"); diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java index 8cc8bdb..eb69af4 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java @@ -1,4 +1,6 @@ -// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +/* + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ package org.jetbrains.java.decompiler.struct.attr; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; @@ -33,6 +35,7 @@ public class StructGeneralAttribute { public static final String ATTRIBUTE_SYNTHETIC = "Synthetic"; public static final String ATTRIBUTE_DEPRECATED = "Deprecated"; public static final String ATTRIBUTE_LINE_NUMBER_TABLE = "LineNumberTable"; + public static final String ATTRIBUTE_METHOD_PARAMETERS = "MethodParameters"; private String name; @@ -81,6 +84,9 @@ public class StructGeneralAttribute { else if (ATTRIBUTE_LINE_NUMBER_TABLE.equals(name)) { attr = new StructLineNumberTableAttribute(); } + else if (ATTRIBUTE_METHOD_PARAMETERS.equals(name)) { + attr = new StructMethodParametersAttribute(); + } else { // unsupported attribute return null; diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructMethodParametersAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructMethodParametersAttribute.java new file mode 100644 index 0000000..08133a9 --- /dev/null +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructMethodParametersAttribute.java @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ +package org.jetbrains.java.decompiler.struct.attr; + +import org.jetbrains.java.decompiler.struct.consts.ConstantPool; +import org.jetbrains.java.decompiler.util.DataInputFullStream; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/* + u1 parameters_count; + { u2 name_index; + u2 access_flags; + } parameters[parameters_count]; +*/ +public class StructMethodParametersAttribute extends StructGeneralAttribute { + private List myEntries; + + @Override + public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { + int len = data.readUnsignedByte(); + List entries; + if (len > 0) { + entries = new ArrayList<>(len); + + for (int i = 0; i < len; i++) { + int nameIndex = data.readUnsignedShort(); + String name = nameIndex != 0 ? pool.getPrimitiveConstant(nameIndex).getString() : null; + int access_flags = data.readUnsignedShort(); + entries.add(new Entry(name, access_flags)); + } + } + else { + entries = Collections.emptyList(); + } + myEntries = Collections.unmodifiableList(entries); + } + + public List getEntries() { + return myEntries; + } + + public static class Entry { + public final String myName; + public final int myAccessFlags; + + public Entry(String name, int accessFlags) { + myName = name; + myAccessFlags = accessFlags; + } + } +} diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 9c971c3..15da93c 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -1,4 +1,6 @@ -// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +/* + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ package org.jetbrains.java.decompiler; import org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler; @@ -45,6 +47,7 @@ public class SingleClassesTest { @Test public void testDeprecations() { doTest("pkg/TestDeprecations"); } @Test public void testExtendsList() { doTest("pkg/TestExtendsList"); } @Test public void testMethodParameters() { doTest("pkg/TestMethodParameters"); } + @Test public void testMethodParametersAttr() { doTest("pkg/TestMethodParametersAttr"); } @Test public void testCodeConstructs() { doTest("pkg/TestCodeConstructs"); } @Test public void testConstants() { doTest("pkg/TestConstants"); } @Test public void testEnum() { doTest("pkg/TestEnum"); } diff --git a/testData/classes/pkg/TestMethodParametersAttr$1Local.class b/testData/classes/pkg/TestMethodParametersAttr$1Local.class new file mode 100644 index 0000000000000000000000000000000000000000..8cfb527cfc5cfa743544180a9df5f46c2a5446c5 GIT binary patch literal 729 zcma)4T}#_w6n;+AG;0=Z=G5ut$GTN$yJ6=xuQr5HCKl=ktn~hE`l69EktFWgzvRUj zc(EU_A2s&8v3OAs8p!!R&w0*C{{FlB1K=~>RAJ$ji!wGGY&zHyRPu{3YkUyw^v60# zCRbsk)6PI=`LWI~lJS{J)kNny&A#P%`h^W&!#KmR5G7d{pWh=p*!J)mbq_Ww9vsvK z?K!SGB};||w-c%OymLCb)IlzIJ4ZiH6`3<~*=B1<1{S|CAii&i&?@nD@PxWb>xkN- zcH8fMLE67jx-Dv4$_j+Cfv1!PhgI-Uqc)a7GkF(2o)Kk)~4_GCg?*IS* literal 0 HcmV?d00001 diff --git a/testData/classes/pkg/TestMethodParametersAttr$C1.class b/testData/classes/pkg/TestMethodParametersAttr$C1.class new file mode 100644 index 0000000000000000000000000000000000000000..9acce02b6cbbe46715b9fa66ec99400bc8e36e8a GIT binary patch literal 677 zcma)3$x6de6g{_7Y^*lcd8i5wvgiaA(ODda$80!peK$T8luILZ)XPmlsupy#Am4C(ef8LD>F`dqJVpwQ zpsl>73SHw5gDJyFkf>D!xw`M`u;!^K(u|EXbF)?@(PY2MeyIzbzpF6ZBdOAW8|w}P z_HFPOw)HvJ7Zm^7f3K^aR1Rrmaf&ybv8yo zz&cNt;uXbl%zRo2{uailv$QU#lhpRk?ki;H4T+aQjZK+>P%dDc(%`TPIpnF0WzbCC zhJz`h6liA?NIyFam~R?0!y!lX%vkx0y*R+0`$_&{3ucMPE3+kS9Me5Fkn@3S+PnAL=a=G8)($o1@(NtY8W-y!@gIy0pAswH`v7lO|(GhMG^gUn5YE#7OMyPJo zx#yAxLJ1jPDJ6HD+Brj_Upr!8b%xwe5wQd6k%De80x}dHGh`m3fpo<+(HYAB;SYQK ziQ6!-YGI9Gce;&e4Lw)&dH7hpYxjh!=-P_@o$VkxBkBZ@g zR5Bw?s=U@(?Faq^+p`lM?DnepOMlCFvB^2V8`)_sIoglKRK;||tp#@e>wP?y&(eX3 zriCqmgW1;M4Jx0P%KXW@kH!>hfxQ{L<}M8W*XmS}$AUkXmB(3dZXUftys$7}actG_ r3~koVcLC;Du@eheWYVcjyibjmf1@r#11oi}Rm^j?x!%A!Y_t6ZG@)!= literal 0 HcmV?d00001 diff --git a/testData/classes/pkg/TestMethodParametersAttr$I1.class b/testData/classes/pkg/TestMethodParametersAttr$I1.class new file mode 100644 index 0000000000000000000000000000000000000000..6b52d993d8f8425e551472af52992d4941f5b215 GIT binary patch literal 306 zcma)%%WA?<5QhJWiAiIs=>xd3NV_q#TWh1zb?$OUlx1%#bQdO)Mg=$-t?O`Vq6{^}t xt6k2iAx!?E*9SyT{sb&r4u>tdBbh^xo|N3{l7~>}hmMAip?F_-!T^tb?*gdJM$!NP literal 0 HcmV?d00001 diff --git a/testData/classes/pkg/TestMethodParametersAttr.class b/testData/classes/pkg/TestMethodParametersAttr.class new file mode 100644 index 0000000000000000000000000000000000000000..3549300662c2ede40f25f7914888ea060453140b GIT binary patch literal 981 zcma)4+fLg+5IvJPaT?MBX`n3y8g3yM)Q~_Qsv@K+QYB02MIz#TldQnVv61cYUp!Un z10T?jLYz(72xyVK($1OLJ##!W>)*G(ZU7u&FOM{~Y;4=uu~8AEI){RSg%wl z`W{b;lY~`1Q<8YwA@I!*Nr@r+5LS3l>7Eu;#C8&($ zn2e^U{Illw{)HaIf=YtKZ8Q61M7ENM=x_*$h#ih78Ig+hB+axYFN_VO_=}lkaWA6C z_$9rM;KL9z^`DSyIw_QBvpfa~OSH>V0`V0iQt=vZc)wzNVPMwVnc@dVM)4oD(mgeq zsR>r^tF1CKhqakn!zlevZE2!bm|kL?8u(k$I$hu$%Dgl^KB=+$Kx5ipilZ_OY;p!b ho7Q5Kv2w79IZp2xF`vz0j#yx^&xtR{o#$Qv?f~PG#$Esb literal 0 HcmV?d00001 diff --git a/testData/results/TestMethodParametersAttr.dec b/testData/results/TestMethodParametersAttr.dec new file mode 100644 index 0000000..ba00341 --- /dev/null +++ b/testData/results/TestMethodParametersAttr.dec @@ -0,0 +1,125 @@ +package decompiler; + +public class TestMethodParametersAttr { + TestMethodParametersAttr(int p01) { + }// 19 + + void m1(int p02) { + }// 20 + + static void m2(int p03) { + }// 21 + + void local() { + class Local { + Local(final int this$0) { + }// 36 + + void m(int p32) { + }// 37 + } + + }// 39 + + abstract static class C4 { + abstract void m1(int p51); + + abstract void m2(final int p52); + } + + abstract class C3 { + abstract void m1(int p51); + + abstract void m2(final int p52); + } + + interface I1 { + void m1(int p41); + + void m2(final int p42); + } + + static class C2 { + C2(int p21) { + }// 29 + + void m1(int p22) { + }// 30 + + static void m2(int p23) { + }// 31 + } + + class C1 { + C1(final int this$0) { + }// 24 + + void m(int p12) { + }// 25 + } +} + +class 'decompiler/TestMethodParametersAttr' { + method ' (I)V' { + 4 4 + } + + method 'm1 (I)V' { + 0 7 + } + + method 'm2 (I)V' { + 0 10 + } + + method 'local ()V' { + 0 21 + } +} + +class 'decompiler/TestMethodParametersAttr$1Local' { + method ' (Ldecompiler/TestMethodParametersAttr;I)V' { + 9 15 + } + + method 'm (I)V' { + 0 18 + } +} + +class 'decompiler/TestMethodParametersAttr$C2' { + method ' (I)V' { + 4 43 + } + + method 'm1 (I)V' { + 0 46 + } + + method 'm2 (I)V' { + 0 49 + } +} + +class 'decompiler/TestMethodParametersAttr$C1' { + method ' (Ldecompiler/TestMethodParametersAttr;I)V' { + 9 54 + } + + method 'm (I)V' { + 0 57 + } +} + +Lines mapping: +19 <-> 5 +20 <-> 8 +21 <-> 11 +24 <-> 55 +25 <-> 58 +29 <-> 44 +30 <-> 47 +31 <-> 50 +36 <-> 16 +37 <-> 19 +39 <-> 22 diff --git a/testData/src/pkg/TestMethodParametersAttr.java b/testData/src/pkg/TestMethodParametersAttr.java new file mode 100644 index 0000000..b98fc0b --- /dev/null +++ b/testData/src/pkg/TestMethodParametersAttr.java @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package decompiler; + +// compile with java 8: javap -parameters TestMethodParametersAttr.java +public class TestMethodParametersAttr { + TestMethodParametersAttr(int p01) { } + void m1(int p02) { } + static void m2(int p03) { } + + class C1 { + C1(int p11) { } + void m(int p12) { } + } + + static class C2 { + C2(int p21) { } + void m1(int p22) { } + static void m2(int p23) { } + } + + void local() { + class Local { + Local(int p31) { } + void m(int p32) { } + } + } + + interface I1 { + void m1(int p41); + void m2(final int p42); + } + + abstract class C3 { + abstract void m1(int p51); + abstract void m2(final int p52); + } + + static abstract class C4 { + abstract void m1(int p51); + abstract void m2(final int p52); + } +} \ No newline at end of file