Avoid explicit array creation for vararg parameters
This commit is contained in:
committed by
Egor.Ushakov
parent
d149b53799
commit
dfd90978c9
@@ -343,14 +343,18 @@ public class InvocationExprent extends Exprent {
|
||||
|
||||
BitSet setAmbiguousParameters = getAmbiguousParameters();
|
||||
|
||||
// omit 'new Type[] {}' for the last parameter of a vararg method call
|
||||
if (lstParameters.size() == descriptor.params.length && isVarArgCall()) {
|
||||
Exprent lastParam = lstParameters.get(lstParameters.size() - 1);
|
||||
if (lastParam.type == EXPRENT_NEW && lastParam.getExprType().arrayDim >= 1) {
|
||||
((NewExprent) lastParam).setVarArgParam(true);
|
||||
}
|
||||
}
|
||||
|
||||
boolean firstParameter = true;
|
||||
int start = isEnum ? 2 : 0;
|
||||
for (int i = start; i < lstParameters.size(); i++) {
|
||||
if (sigFields == null || sigFields.get(i) == null) {
|
||||
if (!firstParameter) {
|
||||
buf.append(", ");
|
||||
}
|
||||
|
||||
TextBuffer buff = new TextBuffer();
|
||||
boolean ambiguous = setAmbiguousParameters.get(i);
|
||||
|
||||
@@ -361,7 +365,14 @@ public class InvocationExprent extends Exprent {
|
||||
}
|
||||
// 'byte' and 'short' literals need an explicit narrowing type cast when used as a parameter
|
||||
ExprProcessor.getCastedExprent(param, descriptor.params[i], buff, indent, true, ambiguous, true, tracer);
|
||||
|
||||
// the last "new Object[0]" in the vararg call is not printed
|
||||
if (buff.length() > 0) {
|
||||
if (!firstParameter) {
|
||||
buf.append(", ");
|
||||
}
|
||||
buf.append(buff);
|
||||
}
|
||||
|
||||
firstParameter = false;
|
||||
}
|
||||
@@ -372,6 +383,20 @@ public class InvocationExprent extends Exprent {
|
||||
return buf;
|
||||
}
|
||||
|
||||
private boolean isVarArgCall() {
|
||||
StructClass cl = DecompilerContext.getStructContext().getClass(classname);
|
||||
if (cl != null) {
|
||||
StructMethod mt = cl.getMethod(InterpreterUtil.makeUniqueKey(name, stringDescriptor));
|
||||
if (mt != null) {
|
||||
return mt.hasModifier(CodeConstants.ACC_VARARGS);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: try to check the class on the classpath
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isBoxingCall() {
|
||||
if (isStatic && "valueOf".equals(name) && lstParameters.size() == 1) {
|
||||
int paramType = lstParameters.get(0).getExprType().type;
|
||||
|
||||
@@ -44,6 +44,7 @@ public class NewExprent extends Exprent {
|
||||
private List<Exprent> lstDims = new ArrayList<>();
|
||||
private List<Exprent> lstArrayElements = new ArrayList<>();
|
||||
private boolean directArrayInit;
|
||||
private boolean isVarArgParam;
|
||||
private boolean anonymous;
|
||||
private boolean lambda;
|
||||
private boolean enumConst;
|
||||
@@ -349,6 +350,30 @@ public class NewExprent extends Exprent {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (isVarArgParam) {
|
||||
// just print the array elements
|
||||
VarType leftType = newType.decreaseArrayDim();
|
||||
for (int i = 0; i < lstArrayElements.size(); i++) {
|
||||
if (i > 0) {
|
||||
buf.append(", ");
|
||||
}
|
||||
|
||||
// new String[][]{{"abc"}, {"DEF"}} => new String[]{"abc"}, new String[]{"DEF"}
|
||||
Exprent element = lstArrayElements.get(i);
|
||||
if (element.type == EXPRENT_NEW) {
|
||||
((NewExprent) element).setDirectArrayInit(false);
|
||||
}
|
||||
ExprProcessor.getCastedExprent(element, leftType, buf, indent, false, tracer);
|
||||
}
|
||||
|
||||
// if there is just one element of Object[] type it needs to be casted to resolve ambiguity
|
||||
if (lstArrayElements.size() == 1) {
|
||||
VarType elementType = lstArrayElements.get(0).getExprType();
|
||||
if (elementType.type == CodeConstants.TYPE_OBJECT && elementType.value.equals("java/lang/Object") && elementType.arrayDim >= 1) {
|
||||
buf.prepend("(Object)");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
buf.append("new ").append(ExprProcessor.getTypeName(newType));
|
||||
|
||||
@@ -478,6 +503,10 @@ public class NewExprent extends Exprent {
|
||||
this.directArrayInit = directArrayInit;
|
||||
}
|
||||
|
||||
public void setVarArgParam(boolean isVarArgParam) {
|
||||
this.isVarArgParam = isVarArgParam;
|
||||
}
|
||||
|
||||
public boolean isLambda() {
|
||||
return lambda;
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ public class SingleClassesTest {
|
||||
"pkg/SharedName2", "pkg/SharedName3", "pkg/SharedName4", "pkg/NonSharedName",
|
||||
"pkg/TestClashNameParent", "ext/TestClashNameParent","pkg/TestClashNameIface", "ext/TestClashNameIface"); }
|
||||
@Test public void testSwitchOnEnum() { doTest("pkg/TestSwitchOnEnum","pkg/TestSwitchOnEnum$1");}
|
||||
|
||||
@Test public void testVarArgCalls() { doTest("pkg/TestVarArgCalls"); }
|
||||
|
||||
private void doTest(String testFile, String... companionFiles) {
|
||||
ConsoleDecompiler decompiler = fixture.getDecompiler();
|
||||
|
||||
BIN
testData/classes/pkg/TestVarArgCalls.class
Normal file
BIN
testData/classes/pkg/TestVarArgCalls.class
Normal file
Binary file not shown.
104
testData/results/TestVarArgCalls.dec
Normal file
104
testData/results/TestVarArgCalls.dec
Normal file
@@ -0,0 +1,104 @@
|
||||
package pkg;
|
||||
|
||||
public class TestVarArgCalls {
|
||||
public void doSmth() {
|
||||
this.printAll("Test");// 5
|
||||
this.printAll("Test: %s", "abc");// 6
|
||||
this.printAll("Test: %s - %s", "abc", "DEF");// 7
|
||||
this.printComplex("Test");// 9
|
||||
this.printComplex("Test: %[0]s", new String[]{"abc"});// 10
|
||||
this.printComplex("Test: %[0]s - %[0]s", new String[]{"abc"}, new String[]{"DEF"});// 11
|
||||
String.format("Test", new Object[0]);// 13
|
||||
String.format("Test: %d", new Object[]{Integer.valueOf(123)});// 14
|
||||
String.format("Test: %d - %s", new Object[]{Integer.valueOf(123), "DEF"});// 15
|
||||
Object[] data = new Object[]{"Hello"};// 17
|
||||
String.format("Test: %s", new Object[]{data});// 18
|
||||
String.format("Test: %s", (Object[])data);// 19
|
||||
}// 20
|
||||
|
||||
public void printAll(String fmt, String... params) {
|
||||
System.out.println(String.format(fmt, (Object[])params));// 23
|
||||
}// 24
|
||||
|
||||
public void printComplex(String fmt, String[]... params) {
|
||||
System.out.println(String.format(fmt, (Object[])params));// 27
|
||||
}// 28
|
||||
}
|
||||
|
||||
class 'pkg/TestVarArgCalls' {
|
||||
method 'doSmth ()V' {
|
||||
1 4
|
||||
7 4
|
||||
b 5
|
||||
13 5
|
||||
16 5
|
||||
1a 6
|
||||
22 6
|
||||
27 6
|
||||
2a 6
|
||||
2e 7
|
||||
34 7
|
||||
38 8
|
||||
46 8
|
||||
4a 8
|
||||
4e 9
|
||||
5c 9
|
||||
68 9
|
||||
6c 9
|
||||
6f 10
|
||||
71 10
|
||||
75 10
|
||||
79 11
|
||||
81 11
|
||||
83 11
|
||||
87 11
|
||||
8b 12
|
||||
93 12
|
||||
95 12
|
||||
9b 12
|
||||
9e 12
|
||||
a8 13
|
||||
ab 13
|
||||
ac 14
|
||||
b6 14
|
||||
ba 15
|
||||
bd 15
|
||||
c0 15
|
||||
c4 16
|
||||
}
|
||||
|
||||
method 'printAll (Ljava/lang/String;[Ljava/lang/String;)V' {
|
||||
0 19
|
||||
5 19
|
||||
8 19
|
||||
b 19
|
||||
e 20
|
||||
}
|
||||
|
||||
method 'printComplex (Ljava/lang/String;[[Ljava/lang/String;)V' {
|
||||
0 23
|
||||
5 23
|
||||
8 23
|
||||
b 23
|
||||
e 24
|
||||
}
|
||||
}
|
||||
|
||||
Lines mapping:
|
||||
5 <-> 5
|
||||
6 <-> 6
|
||||
7 <-> 7
|
||||
9 <-> 8
|
||||
10 <-> 9
|
||||
11 <-> 10
|
||||
13 <-> 11
|
||||
14 <-> 12
|
||||
15 <-> 13
|
||||
17 <-> 14
|
||||
18 <-> 15
|
||||
19 <-> 16
|
||||
20 <-> 17
|
||||
23 <-> 20
|
||||
24 <-> 21
|
||||
27 <-> 24
|
||||
28 <-> 25
|
||||
29
testData/src/pkg/TestVarArgCalls.java
Normal file
29
testData/src/pkg/TestVarArgCalls.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package pkg;
|
||||
|
||||
public class TestVarArgCalls {
|
||||
public void doSmth() {
|
||||
printAll("Test");
|
||||
printAll("Test: %s", "abc");
|
||||
printAll("Test: %s - %s", "abc", "DEF");
|
||||
|
||||
printComplex("Test");
|
||||
printComplex("Test: %[0]s", new String[] { "abc" });
|
||||
printComplex("Test: %[0]s - %[0]s", new String[] { "abc" }, new String[] { "DEF" });
|
||||
|
||||
String.format("Test");
|
||||
String.format("Test: %d", 123);
|
||||
String.format("Test: %d - %s", 123, "DEF");
|
||||
|
||||
Object[] data = { "Hello" };
|
||||
String.format("Test: %s", (Object) data);
|
||||
String.format("Test: %s", (Object[]) data);
|
||||
}
|
||||
|
||||
public void printAll(String fmt, String... params) {
|
||||
System.out.println(String.format(fmt, (Object[]) params));
|
||||
}
|
||||
|
||||
public void printComplex(String fmt, String[]... params) {
|
||||
System.out.println(String.format(fmt, (Object[]) params));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user