Skip to content

Commit 45f632b

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

File tree

10 files changed

+149
-0
lines changed

10 files changed

+149
-0
lines changed

src/main/java/org/jd/core/v1/model/javasyntax/expression/BaseExpression.java

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

88
package org.jd.core.v1.model.javasyntax.expression;
99

10+
import org.jd.core.v1.model.javasyntax.type.ObjectType;
1011
import org.jd.core.v1.util.Base;
1112

1213
import static org.jd.core.v1.model.javasyntax.expression.NoExpression.NO_EXPRESSION;
@@ -55,7 +56,9 @@ public interface BaseExpression extends Base<Expression> {
5556
default double getDoubleValue() { return 0D; }
5657
default float getFloatValue() { return 0F; }
5758
default int getIntegerValue() { return 0; }
59+
default String getInternalTypeName() { return ""; }
5860
default long getLongValue() { return 0L; }
5961
default String getName() { return ""; }
62+
default ObjectType getObjectType() { return ObjectType.TYPE_UNDEFINED_OBJECT; }
6063
default String getOperator() { return ""; }
6164
}

src/main/java/org/jd/core/v1/model/javasyntax/expression/ConstructorReferenceExpression.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public ConstructorReferenceExpression(int lineNumber, Type type, ObjectType obje
2626
this.descriptor = descriptor;
2727
}
2828

29+
@Override
2930
public ObjectType getObjectType() {
3031
return objectType;
3132
}

src/main/java/org/jd/core/v1/model/javasyntax/expression/EnumConstantReferenceExpression.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public Type getType() {
3131
return type;
3232
}
3333

34+
@Override
3435
public ObjectType getObjectType() {
3536
return type;
3637
}

src/main/java/org/jd/core/v1/model/javasyntax/expression/FieldReferenceExpression.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public void setExpression(Expression expression) {
4040
this.expression = expression;
4141
}
4242

43+
@Override
4344
public String getInternalTypeName() {
4445
return internalTypeName;
4546
}

src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodReferenceExpression.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public void setExpression(Expression expression) {
4040
this.expression = expression;
4141
}
4242

43+
@Override
4344
public String getInternalTypeName() {
4445
return internalTypeName;
4546
}

src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public NewExpression(int lineNumber, ObjectType type, String descriptor, BodyDec
3030
this.bodyDeclaration = bodyDeclaration;
3131
}
3232

33+
@Override
3334
public ObjectType getObjectType() {
3435
return type;
3536
}

src/main/java/org/jd/core/v1/model/javasyntax/expression/ObjectTypeReferenceExpression.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public int getLineNumber() {
4242
return lineNumber;
4343
}
4444

45+
@Override
4546
public ObjectType getObjectType() {
4647
return type;
4748
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ 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();
4748

4849
protected TypeMaker typeMaker;
4950
protected Map<String, BaseType> typeBounds;
@@ -60,6 +61,7 @@ public class StatementMaker {
6061
protected MemberVisitor memberVisitor = new MemberVisitor();
6162
protected boolean removeFinallyStatementsFlag = false;
6263
protected boolean mergeTryWithResourcesStatementFlag = false;
64+
protected boolean autoBoxingSupported;
6365

6466
public StatementMaker(
6567
TypeMaker typeMaker, LocalVariableMaker localVariableMaker,
@@ -74,6 +76,7 @@ public StatementMaker(
7476
this.removeFinallyStatementsVisitor = new RemoveFinallyStatementsVisitor(localVariableMaker);
7577
this.removeBinaryOpReturnStatementsVisitor = new RemoveBinaryOpReturnStatementsVisitor(localVariableMaker);
7678
this.updateIntegerConstantTypeVisitor = new UpdateIntegerConstantTypeVisitor(comd.getReturnedType());
79+
this.autoBoxingSupported = (majorVersion >= 49); // (majorVersion >= Java 5)
7780
}
7881

7982
public Statements make(ControlFlowGraph cfg) {
@@ -113,6 +116,10 @@ public Statements make(ControlFlowGraph cfg) {
113116
// Change ++i; with i++;
114117
replacePreOperatorWithPostOperator(statements);
115118

119+
if (autoBoxingSupported) {
120+
statements.accept(AUTOBOXING_VISITOR);
121+
}
122+
116123
if (!jumps.isEmpty()) {
117124
updateJumpStatements(jumps);
118125
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (c) 2008, 2019 Emmanuel Dupuy.
3+
* This project is distributed under the GPLv3 license.
4+
* This is a Copyleft license that gives the user the right to use,
5+
* copy and modify the code freely for non-commercial purposes.
6+
*/
7+
8+
package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor;
9+
10+
import org.jd.core.v1.model.javasyntax.expression.Expression;
11+
12+
public class AutoboxingVisitor extends AbstractUpdateExpressionVisitor {
13+
14+
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+
}
36+
}
37+
}
38+
39+
return expression;
40+
}
41+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright (c) 2008, 2019 Emmanuel Dupuy.
3+
* This project is distributed under the GPLv3 license.
4+
* This is a Copyleft license that gives the user the right to use,
5+
* copy and modify the code freely for non-commercial purposes.
6+
*/
7+
8+
package org.jd.core.v1;
9+
10+
import junit.framework.TestCase;
11+
import org.jd.core.v1.api.loader.Loader;
12+
import org.jd.core.v1.api.printer.Printer;
13+
import org.jd.core.v1.compiler.CompilerUtil;
14+
import org.jd.core.v1.compiler.JavaSourceFileObject;
15+
import org.jd.core.v1.loader.ClassPathLoader;
16+
import org.jd.core.v1.model.message.Message;
17+
import org.jd.core.v1.printer.PlainTextPrinter;
18+
import org.jd.core.v1.regex.PatternMaker;
19+
import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor;
20+
import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor;
21+
import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor;
22+
import org.jd.core.v1.service.layouter.LayoutFragmentProcessor;
23+
import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor;
24+
import org.jd.core.v1.service.writer.WriteTokenProcessor;
25+
import org.junit.Test;
26+
27+
import java.util.Collections;
28+
import java.util.Map;
29+
30+
public class JavaAutoboxingTest extends TestCase {
31+
protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor();
32+
protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor();
33+
protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor();
34+
protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor();
35+
//protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor();
36+
protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor();
37+
protected WriteTokenProcessor writer = new WriteTokenProcessor();
38+
39+
@Test
40+
// https://github.com/java-decompiler/jd-core/issues/14
41+
public void testAutoboxing() throws Exception {
42+
class AutoboxingAndUnboxing {
43+
void test() {
44+
Integer intObj = 10;
45+
int i = intObj;
46+
}
47+
}
48+
49+
String internalClassName = AutoboxingAndUnboxing.class.getName().replace('.', '/');
50+
String source = decompile(new ClassPathLoader(), new PlainTextPrinter(), internalClassName);
51+
52+
// Check decompiled source code
53+
assertTrue(source.matches(PatternMaker.make(": 44 */", "Integer intObj = 10;")));
54+
assertTrue(source.matches(PatternMaker.make(": 45 */", "int i = intObj;")));
55+
56+
// Recompile decompiled source code and check errors
57+
assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source)));
58+
}
59+
60+
protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception {
61+
return decompile(loader, printer, internalTypeName, Collections.emptyMap());
62+
}
63+
64+
protected String decompile(Loader loader, Printer printer, String internalTypeName, Map<String, Object> configuration) throws Exception {
65+
Message message = new Message();
66+
message.setHeader("loader", loader);
67+
message.setHeader("printer", printer);
68+
message.setHeader("mainInternalTypeName", internalTypeName);
69+
message.setHeader("configuration", configuration);
70+
71+
deserializer.process(message);
72+
converter.process(message);
73+
fragmenter.process(message);
74+
layouter.process(message);
75+
tokenizer.process(message);
76+
writer.process(message);
77+
78+
String source = printer.toString();
79+
80+
printSource(source);
81+
82+
assertTrue(source.indexOf("// Byte code:") == -1);
83+
84+
return source;
85+
}
86+
87+
protected void printSource(String source) {
88+
System.out.println("- - - - - - - - ");
89+
System.out.println(source);
90+
System.out.println("- - - - - - - - ");
91+
}
92+
}

0 commit comments

Comments
 (0)