Skip to content

Commit c1d081a

Browse files
author
emmanue1
committed
Fix #14 : Not needed boxing method calls are emitted
1 parent 45f632b commit c1d081a

File tree

10 files changed

+116
-36
lines changed

10 files changed

+116
-36
lines changed

src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
package org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration;
99

10+
import org.jd.core.v1.model.classfile.ClassFile;
1011
import org.jd.core.v1.model.javasyntax.declaration.BaseMemberDeclaration;
1112
import org.jd.core.v1.model.javasyntax.declaration.BodyDeclaration;
1213
import org.jd.core.v1.model.javasyntax.type.BaseType;
@@ -20,6 +21,7 @@
2021
import java.util.Map;
2122

2223
public class ClassFileBodyDeclaration extends BodyDeclaration implements ClassFileMemberDeclaration {
24+
protected ClassFile classFile;
2325
protected List<ClassFileFieldDeclaration> fieldDeclarations;
2426
protected List<ClassFileConstructorOrMethodDeclaration> methodDeclarations;
2527
protected List<ClassFileTypeDeclaration> innerTypeDeclarations;
@@ -31,8 +33,9 @@ public class ClassFileBodyDeclaration extends BodyDeclaration implements ClassFi
3133
protected Map<String, TypeArgument> bindings;
3234
protected Map<String, BaseType> typeBounds;
3335

34-
public ClassFileBodyDeclaration(String internalTypeName, Map<String, TypeArgument> bindings, Map<String, BaseType> typeBounds, ClassFileBodyDeclaration outerBodyDeclaration) {
35-
super(internalTypeName, null);
36+
public ClassFileBodyDeclaration(ClassFile classFile, Map<String, TypeArgument> bindings, Map<String, BaseType> typeBounds, ClassFileBodyDeclaration outerBodyDeclaration) {
37+
super(classFile.getInternalTypeName(), null);
38+
this.classFile = classFile;
3639
this.bindings = bindings;
3740
this.typeBounds = typeBounds;
3841
this.outerBodyDeclaration = outerBodyDeclaration;
@@ -110,6 +113,10 @@ protected void updateFirstLineNumber(List<? extends ClassFileMemberDeclaration>
110113
}
111114
}
112115

116+
public ClassFile getClassFile() {
117+
return classFile;
118+
}
119+
113120
@Override
114121
public int getFirstLineNumber() {
115122
return firstLineNumber;

src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ protected ClassFileBodyDeclaration convertBodyDeclaration(TypeMaker parser, Anno
142142
typeParameters.accept(populateBindingsWithTypeParameterVisitor);
143143
}
144144

145-
ClassFileBodyDeclaration bodyDeclaration = new ClassFileBodyDeclaration(classFile.getInternalTypeName(), bindings, typeBounds, outerClassFileBodyDeclaration);
145+
ClassFileBodyDeclaration bodyDeclaration = new ClassFileBodyDeclaration(classFile, bindings, typeBounds, outerClassFileBodyDeclaration);
146146

147147
bodyDeclaration.setFieldDeclarations(convertFields(parser, converter, classFile));
148148
bodyDeclaration.setMethodDeclarations(convertMethods(parser, converter, bodyDeclaration, classFile));

src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ public class StatementMaker {
4444
protected static final SwitchCaseComparator SWITCH_CASE_COMPARATOR = new SwitchCaseComparator();
4545
protected static final NullExpression FINALLY_EXCEPTION_EXPRESSION = new NullExpression(new ObjectType("java/lang/Exception", "java.lang.Exception", "Exception"));
4646
protected static final MergeTryWithResourcesStatementVisitor MERGE_TRY_WITH_RESOURCES_STATEMENT_VISITOR = new MergeTryWithResourcesStatementVisitor();
47-
protected static final AutoboxingVisitor AUTOBOXING_VISITOR = new AutoboxingVisitor();
4847

4948
protected TypeMaker typeMaker;
5049
protected Map<String, BaseType> typeBounds;
@@ -61,7 +60,6 @@ public class StatementMaker {
6160
protected MemberVisitor memberVisitor = new MemberVisitor();
6261
protected boolean removeFinallyStatementsFlag = false;
6362
protected boolean mergeTryWithResourcesStatementFlag = false;
64-
protected boolean autoBoxingSupported;
6563

6664
public StatementMaker(
6765
TypeMaker typeMaker, LocalVariableMaker localVariableMaker,
@@ -76,7 +74,6 @@ public StatementMaker(
7674
this.removeFinallyStatementsVisitor = new RemoveFinallyStatementsVisitor(localVariableMaker);
7775
this.removeBinaryOpReturnStatementsVisitor = new RemoveBinaryOpReturnStatementsVisitor(localVariableMaker);
7876
this.updateIntegerConstantTypeVisitor = new UpdateIntegerConstantTypeVisitor(comd.getReturnedType());
79-
this.autoBoxingSupported = (majorVersion >= 49); // (majorVersion >= Java 5)
8077
}
8178

8279
public Statements make(ControlFlowGraph cfg) {
@@ -116,10 +113,6 @@ public Statements make(ControlFlowGraph cfg) {
116113
// Change ++i; with i++;
117114
replacePreOperatorWithPostOperator(statements);
118115

119-
if (autoBoxingSupported) {
120-
statements.accept(AUTOBOXING_VISITOR);
121-
}
122-
123116
if (!jumps.isEmpty()) {
124117
updateJumpStatements(jumps);
125118
}

src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AutoboxingVisitor.java

Lines changed: 67 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,78 @@
77

88
package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor;
99

10+
import org.jd.core.v1.model.javasyntax.declaration.*;
1011
import org.jd.core.v1.model.javasyntax.expression.Expression;
12+
import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileBodyDeclaration;
13+
14+
import java.util.HashMap;
1115

1216
public class AutoboxingVisitor extends AbstractUpdateExpressionVisitor {
17+
protected static final HashMap<String, String> VALUEOF_DESCRIPTOR_MAP = new HashMap<>();
18+
19+
protected static final HashMap<String, String> VALUE_DESCRIPTOR_MAP = new HashMap<>();
20+
protected static final HashMap<String, String> VALUE_METHODNAME_MAP = new HashMap<>();
21+
22+
static {
23+
VALUEOF_DESCRIPTOR_MAP.put("java/lang/Byte", "(B)Ljava/lang/Byte;");
24+
VALUEOF_DESCRIPTOR_MAP.put("java/lang/Character", "(C)Ljava/lang/Character;");
25+
VALUEOF_DESCRIPTOR_MAP.put("java/lang/Float", "(F)Ljava/lang/Float;");
26+
VALUEOF_DESCRIPTOR_MAP.put("java/lang/Integer", "(I)Ljava/lang/Integer;");
27+
VALUEOF_DESCRIPTOR_MAP.put("java/lang/Long", "(J)Ljava/lang/Long;");
28+
VALUEOF_DESCRIPTOR_MAP.put("java/lang/Short", "(S)Ljava/lang/Short;");
29+
VALUEOF_DESCRIPTOR_MAP.put("java/lang/Double", "(D)Ljava/lang/Double;");
30+
VALUEOF_DESCRIPTOR_MAP.put("java/lang/Boolean", "(Z)Ljava/lang/Boolean;");
31+
32+
VALUE_DESCRIPTOR_MAP.put("java/lang/Byte", "()B");
33+
VALUE_DESCRIPTOR_MAP.put("java/lang/Character", "()C");
34+
VALUE_DESCRIPTOR_MAP.put("java/lang/Float", "()F");
35+
VALUE_DESCRIPTOR_MAP.put("java/lang/Integer", "()I");
36+
VALUE_DESCRIPTOR_MAP.put("java/lang/Long", "()J");
37+
VALUE_DESCRIPTOR_MAP.put("java/lang/Short", "()S");
38+
VALUE_DESCRIPTOR_MAP.put("java/lang/Double", "()D");
39+
VALUE_DESCRIPTOR_MAP.put("java/lang/Boolean", "()Z");
40+
41+
VALUE_METHODNAME_MAP.put("java/lang/Byte", "byteValue");
42+
VALUE_METHODNAME_MAP.put("java/lang/Character", "charValue");
43+
VALUE_METHODNAME_MAP.put("java/lang/Float", "floatValue");
44+
VALUE_METHODNAME_MAP.put("java/lang/Integer", "intValue");
45+
VALUE_METHODNAME_MAP.put("java/lang/Long", "longValue");
46+
VALUE_METHODNAME_MAP.put("java/lang/Short", "shortValue");
47+
VALUE_METHODNAME_MAP.put("java/lang/Double", "doubleValue");
48+
VALUE_METHODNAME_MAP.put("java/lang/Boolean", "booleanValue");
49+
}
1350

51+
@Override
52+
public void visit(BodyDeclaration declaration) {
53+
ClassFileBodyDeclaration cfbd = (ClassFileBodyDeclaration)declaration;
54+
boolean autoBoxingSupported = (cfbd.getClassFile().getMajorVersion() >= 49); // (majorVersion >= Java 5)
55+
56+
if (autoBoxingSupported) {
57+
safeAccept(declaration.getMemberDeclarations());
58+
}
59+
}
60+
61+
@Override
1462
protected Expression updateExpression(Expression expression) {
15-
if (expression.isMethodInvocationExpression()) {
16-
switch (expression.getInternalTypeName()) {
17-
case "java/lang/Boolean":
18-
case "java/lang/Byte":
19-
case "java/lang/Character":
20-
case "java/lang/Float":
21-
case "java/lang/Integer":
22-
case "java/lang/Long":
23-
case "java/lang/Short":
24-
case "java/lang/Double":
25-
if (expression.getExpression().isObjectTypeReferenceExpression()) {
26-
// static method invocation
27-
if (expression.getName().equals("valueOf") && (expression.getParameters().size() == 1)) {
28-
return expression.getParameters().getFirst();
29-
}
30-
} else {
31-
// non-static method invocation
32-
if (expression.getName().endsWith("Value") && (expression.getParameters() == null)) {
33-
return expression.getExpression();
34-
}
35-
}
63+
if (expression.isMethodInvocationExpression() && expression.getInternalTypeName().startsWith("java/lang/")) {
64+
int parameterSize = (expression.getParameters() == null) ? 0 : expression.getParameters().size();
65+
66+
if (expression.getExpression().isObjectTypeReferenceExpression()) {
67+
// static method invocation
68+
if ((parameterSize == 1) &&
69+
expression.getName().equals("valueOf") &&
70+
expression.getDescriptor().equals(VALUEOF_DESCRIPTOR_MAP.get(expression.getInternalTypeName())))
71+
{
72+
return expression.getParameters().getFirst();
73+
}
74+
} else {
75+
// non-static method invocation
76+
if ((parameterSize == 0) &&
77+
expression.getName().equals(VALUE_METHODNAME_MAP.get(expression.getInternalTypeName())) &&
78+
expression.getDescriptor().equals(VALUE_DESCRIPTOR_MAP.get(expression.getInternalTypeName())))
79+
{
80+
return expression.getExpression();
81+
}
3682
}
3783
}
3884

src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep2Visitor.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
public class UpdateJavaSyntaxTreeStep2Visitor extends AbstractJavaSyntaxVisitor {
1717
protected static final AggregateFieldsVisitor AGGREGATE_FIELDS_VISITOR = new AggregateFieldsVisitor();
1818
protected static final SortMembersVisitor SORT_MEMBERS_VISITOR = new SortMembersVisitor();
19+
protected static final AutoboxingVisitor AUTOBOXING_VISITOR = new AutoboxingVisitor();
1920

2021
protected InitStaticFieldVisitor initStaticFieldVisitor = new InitStaticFieldVisitor();
2122
protected InitInstanceFieldVisitor initInstanceFieldVisitor = new InitInstanceFieldVisitor();
@@ -66,6 +67,9 @@ public void visit(BodyDeclaration declaration) {
6667

6768
// Add cast expressions
6869
addCastExpressionVisitor.visit(declaration);
70+
71+
// Autoboxing
72+
AUTOBOXING_VISITOR.visit(declaration);
6973
}
7074
}
7175

src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ protected void test(InputStream inputStream) throws Exception {
158158
String internalTypeName = path.substring(0, path.length() - 6); // 6 = ".class".length()
159159

160160
// TODO DEBUG if (!internalTypeName.endsWith("/Debug")) continue;
161+
//if (!internalTypeName.endsWith("/MapUtils")) continue;
161162

162163
message.setHeader("mainInternalTypeName", internalTypeName);
163164
printer.init();

src/test/java/org/jd/core/v1/JavaEnumTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public void testJdk170Enum() throws Exception {
6060
assertTrue(source.matches(PatternMaker.make(": 49 */", "double earthWeight = Double.parseDouble(args[0]);")));
6161
assertTrue(source.matches(PatternMaker.make(": 50 */", "double mass = earthWeight / EARTH.surfaceGravity();")));
6262
assertTrue(source.matches(PatternMaker.make(": 51 */", "for (Planet p : values()) {")));
63-
assertTrue(source.matches(PatternMaker.make(": 52 */", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );")));
63+
assertTrue(source.matches(PatternMaker.make(": 52 */", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, p.surfaceWeight(mass) } );")));
6464

6565
assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}")));
6666

@@ -90,7 +90,7 @@ public void testJdk901Enum() throws Exception {
9090
assertTrue(source.matches(PatternMaker.make(": 49 */", "double earthWeight = Double.parseDouble(args[0]);")));
9191
assertTrue(source.matches(PatternMaker.make(": 50 */", "double mass = earthWeight / EARTH.surfaceGravity();")));
9292
assertTrue(source.matches(PatternMaker.make(": 51 */", "for (Planet p : values()) {")));
93-
assertTrue(source.matches(PatternMaker.make(": 52 */", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );")));
93+
assertTrue(source.matches(PatternMaker.make(": 52 */", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, p.surfaceWeight(mass) } );")));
9494

9595
assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}")));
9696

@@ -120,7 +120,7 @@ public void testJdk1002Enum() throws Exception {
120120
assertTrue(source.matches(PatternMaker.make(": 49 */", "double earthWeight = Double.parseDouble(args[0]);")));
121121
assertTrue(source.matches(PatternMaker.make(": 50 */", "double mass = earthWeight / EARTH.surfaceGravity();")));
122122
assertTrue(source.matches(PatternMaker.make(": 51 */", "for (Planet p : values()) {")));
123-
assertTrue(source.matches(PatternMaker.make(": 52 */", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );")));
123+
assertTrue(source.matches(PatternMaker.make(": 52 */", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, p.surfaceWeight(mass) } );")));
124124

125125
assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}")));
126126

src/test/java/org/jd/core/v1/JavaLambdaTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public void testJdk180Lambda() throws Exception {
5252
assertTrue(source.indexOf("Consumer<String> println = s -> System.out.println(s);") != -1);
5353
assertTrue(source.matches(PatternMaker.make(": 27 */", "list.stream().filter(filter).forEach(println);")));
5454
assertTrue(source.matches(PatternMaker.make(": 31 */", "((Map)list.stream()")));
55-
assertTrue(source.matches(PatternMaker.make(": 32 */", ".collect(Collectors.toMap(lambda -> Integer.valueOf(lambda.index), Function.identity())))")));
55+
assertTrue(source.matches(PatternMaker.make(": 32 */", ".collect(Collectors.toMap(lambda -> lambda.index, Function.identity())))")));
5656
assertTrue(source.matches(PatternMaker.make(": 33 */", ".forEach((key, value) ->")));
5757
assertTrue(source.matches(PatternMaker.make(": 48 */", "Thread thread = new Thread(() -> {")));
5858
assertTrue(source.matches(PatternMaker.make(": 58 */", "Consumer<String> staticMethodReference = String::valueOf;")));

src/test/java/org/jd/core/v1/JavaMethodOverloadingTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,34 @@ void test4() {
7070
assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source)));
7171
}
7272

73+
@Test
74+
// https://github.com/java-decompiler/jd-core/issues/32
75+
// public void testGenericParameterMethod() throws Exception {
76+
// class GenericParameterMethod {
77+
// /* static */ void use(Integer i) {
78+
// System.out.println("use(Integer)");
79+
// }
80+
// /* static */ <T> void use(T t) {
81+
// System.out.println("use(T)");
82+
// }
83+
//
84+
// public /* static */ void main(String... args) {
85+
// use(1);
86+
// use((Object) 1); // Calls use(T)
87+
// }
88+
// }
89+
//
90+
// String internalClassName = GenericParameterMethod.class.getName().replace('.', '/');
91+
// String source = decompile(new ClassPathLoader(), new PlainTextPrinter(), internalClassName);
92+
//
93+
// // Check decompiled source code
94+
// assertTrue(source.matches(PatternMaker.make(": 85 */", "use(1);")));
95+
// assertTrue(source.matches(PatternMaker.make(": 86 */", "use((Object)1);")));
96+
//
97+
// // Recompile decompiled source code and check errors
98+
// assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source)));
99+
// }
100+
73101
protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception {
74102
return decompile(loader, printer, internalTypeName, Collections.emptyMap());
75103
}

src/test/java/org/jd/core/v1/MergeMembersUtilTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,8 @@ protected DefaultList<ClassFileMemberDeclaration> newInnerTypes(int lineNumber)
256256
DefaultList<ClassFileFieldDeclaration> fields = new DefaultList<>();
257257
fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("d"), lineNumber));
258258

259-
ClassFileBodyDeclaration bodyDeclaration = new ClassFileBodyDeclaration("A", null, null, null);
259+
ClassFile classFile = new ClassFile(49, 0, 0, "A", "java/lang/Object", null, null, null, null);
260+
ClassFileBodyDeclaration bodyDeclaration = new ClassFileBodyDeclaration(classFile, null, null, null);
260261
bodyDeclaration.setFieldDeclarations(fields);
261262

262263
innerTypes.add(new ClassFileClassDeclaration(null, 0, "A", "A", null, null, null, bodyDeclaration));

0 commit comments

Comments
 (0)