Fixed narrowing cast from 'int' to 'Byte' / 'Short'

This commit is contained in:
Dmitry Cherniachenko
2017-06-23 22:37:37 +02:00
committed by Egor.Ushakov
parent 5db9ad29c8
commit aa78b7df28
7 changed files with 472 additions and 233 deletions

View File

@@ -877,10 +877,20 @@ public class ExprProcessor implements CodeConstants {
castAlways ||
(!leftType.isSuperset(rightType) && (rightType.equals(VarType.VARTYPE_OBJECT) || leftType.type != CodeConstants.TYPE_OBJECT)) ||
(castNull && rightType.type == CodeConstants.TYPE_NULL && !UNDEFINED_TYPE_STRING.equals(getTypeName(leftType))) ||
(castNarrowing && isIntConstant(exprent) && VarType.VARTYPE_INT.isStrictSuperset(leftType));
(castNarrowing && isIntConstant(exprent) && isNarrowedIntType(leftType));
boolean quote = cast && exprent.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST);
// cast instead to 'byte' / 'short' when int constant is used as a value for 'Byte' / 'Short'
if (castNarrowing && exprent.type == Exprent.EXPRENT_CONST) {
if (leftType.equals(VarType.VARTYPE_BYTE_OBJ)) {
leftType = VarType.VARTYPE_BYTE;
}
else if (leftType.equals(VarType.VARTYPE_SHORT_OBJ)) {
leftType = VarType.VARTYPE_SHORT;
}
}
if (cast) buffer.append('(').append(getCastTypeName(leftType)).append(')');
if (quote) buffer.append('(');
@@ -910,4 +920,9 @@ public class ExprProcessor implements CodeConstants {
return false;
}
private static boolean isNarrowedIntType(VarType type) {
return VarType.VARTYPE_INT.isStrictSuperset(type) ||
type.equals(VarType.VARTYPE_BYTE_OBJ) || type.equals(VarType.VARTYPE_SHORT_OBJ);
}
}

View File

@@ -360,11 +360,7 @@ public class InvocationExprent extends Exprent {
TextBuffer buff = new TextBuffer();
boolean ambiguous = setAmbiguousParameters.get(i);
Exprent param = lstParameters.get(i);
// "unbox" invocation parameters, e.g. 'byteSet.add((byte)123)' or 'new ShortContainer((short)813)'
if (param.type == Exprent.EXPRENT_INVOCATION && ((InvocationExprent)param).isBoxingCall()) {
param = ((InvocationExprent)param).lstParameters.get(0);
}
Exprent param = unboxIfNeeded(lstParameters.get(i));
// '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);
@@ -385,6 +381,14 @@ public class InvocationExprent extends Exprent {
return buf;
}
public static Exprent unboxIfNeeded(Exprent param) {
// "unbox" invocation parameters, e.g. 'byteSet.add((byte)123)' or 'new ShortContainer((short)813)'
if (param.type == Exprent.EXPRENT_INVOCATION && ((InvocationExprent)param).isBoxingCall()) {
param = ((InvocationExprent)param).lstParameters.get(0);
}
return param;
}
private boolean isVarArgCall() {
StructClass cl = DecompilerContext.getStructContext().getClass(classname);
if (cl != null) {

View File

@@ -326,7 +326,7 @@ public class NewExprent extends Exprent {
boolean firstParam = true;
for (int i = start; i < lstParameters.size(); i++) {
if (sigFields == null || sigFields.get(i) == null) {
Exprent expr = lstParameters.get(i);
Exprent expr = InvocationExprent.unboxIfNeeded(lstParameters.get(i));
VarType leftType = constructor.getDescriptor().params[i];
if (i == lstParameters.size() - 1 && expr.getExprType() == VarType.VARTYPE_NULL) {

View File

@@ -40,6 +40,8 @@ public class VarType { // TODO: optimize switch
public static final VarType VARTYPE_OBJECT = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Object");
public static final VarType VARTYPE_INTEGER = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Integer");
public static final VarType VARTYPE_CHARACTER = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Character");
public static final VarType VARTYPE_BYTE_OBJ = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Byte");
public static final VarType VARTYPE_SHORT_OBJ = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Short");
public static final VarType VARTYPE_VOID = new VarType(CodeConstants.TYPE_VOID);
public final int type;