Avoid explicit array creation for vararg parameters

This commit is contained in:
Dmitry Cherniachenko
2017-04-18 22:16:52 +02:00
committed by Egor.Ushakov
parent d149b53799
commit dfd90978c9
6 changed files with 193 additions and 6 deletions

View File

@@ -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);
buf.append(buff);
// 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;

View File

@@ -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;
}