IDEA-157321 Debugger and Runtime Java Varargs inconsistent

This commit is contained in:
Egor.Ushakov
2016-06-23 11:26:36 +03:00
parent af402e2dc5
commit 1fa4233a00
2 changed files with 28 additions and 41 deletions
@@ -1041,20 +1041,37 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
// See IDEA-63581
// if vararg parameter array is of interface type and Object[] is expected, JDI wrap it into another array,
// in this case we have to unroll the array manually and pass its elements to the method instead of array object
int lastIndex = myArgs.size() - 1;
if (lastIndex >= 0) {
final Object lastArg = myArgs.get(lastIndex);
if (lastArg instanceof ArrayReference) {
final ArrayReference arrayRef = (ArrayReference)lastArg;
if (((ArrayType)arrayRef.referenceType()).componentType() instanceof InterfaceType) {
List<String> argTypes = myMethod.argumentTypeNames();
if (argTypes.size() > lastIndex && argTypes.get(lastIndex).startsWith(CommonClassNames.JAVA_LANG_OBJECT)) {
// unwrap array of interfaces for vararg param
myArgs.remove(lastIndex);
myArgs.addAll(arrayRef.getValues());
int lastIndex = myMethod.argumentTypeNames().size() - 1;
if (lastIndex >= 0 && myArgs.size() > lastIndex) { // at least one varargs param
Object firstVararg = myArgs.get(lastIndex);
if (myArgs.size() == lastIndex + 1) { // only one vararg param
if (firstVararg instanceof ArrayReference) {
ArrayReference arrayRef = (ArrayReference)firstVararg;
if (((ArrayType)arrayRef.referenceType()).componentType() instanceof InterfaceType) {
List<String> argTypes = myMethod.argumentTypeNames();
if (argTypes.size() > lastIndex && argTypes.get(lastIndex).startsWith(CommonClassNames.JAVA_LANG_OBJECT)) {
// unwrap array of interfaces for vararg param
myArgs.remove(lastIndex);
myArgs.addAll(arrayRef.getValues());
}
}
}
}
else if (firstVararg == null) { // more than one vararg params and the first one is null
// this is a workaround for a bug in jdi, see IDEA-157321
int argCount = myArgs.size();
List<Type> paramTypes = myMethod.argumentTypes();
int paramCount = paramTypes.size();
ArrayType lastParamType = (ArrayType)paramTypes.get(paramTypes.size() - 1);
int count = argCount - paramCount + 1;
ArrayReference argArray = lastParamType.newInstance(count);
argArray.setValues(0, myArgs, paramCount - 1, count);
myArgs.set(paramCount - 1, argArray);
for (int ii = paramCount; ii < argCount; ii++) {
myArgs.remove(paramCount);
}
}
}
}
@@ -1089,7 +1089,6 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
if (psiMethod != null) {
processBoxingConversions(psiMethod.getParameterList().getParameters(), argExpressions, resolveResult.getSubstitutor(), argumentEvaluators);
argumentEvaluators = wrapVarargs(psiMethod.getParameterList().getParameters(), argExpressions, resolveResult.getSubstitutor(), argumentEvaluators);
defaultInterfaceMethod = psiMethod.hasModifierProperty(PsiModifier.DEFAULT);
mustBeVararg = psiMethod.isVarArgs();
}
@@ -1319,7 +1318,6 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
if (constructor != null) {
processBoxingConversions(constructor.getParameterList().getParameters(), argExpressions, constructorResolveResult.getSubstitutor(), argumentEvaluators);
argumentEvaluators = wrapVarargs(constructor.getParameterList().getParameters(), argExpressions, constructorResolveResult.getSubstitutor(), argumentEvaluators);
}
if (aClass != null && aClass.getContainingClass() != null && !aClass.hasModifierProperty(PsiModifier.STATIC)) {
@@ -1410,34 +1408,6 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
}
}
private static Evaluator[] wrapVarargs(final PsiParameter[] declaredParams,
final PsiExpression[] actualArgumentExpressions,
final PsiSubstitutor methodResolveSubstitutor,
final Evaluator[] argumentEvaluators) {
int lastParam = declaredParams.length - 1;
if (lastParam >= 0 && declaredParams[lastParam].isVarArgs() && argumentEvaluators.length > lastParam) {
// only wrap if the first varargs parameter is null for now
if (!TypeConversionUtil.isNullType(actualArgumentExpressions[lastParam].getType())) {
return argumentEvaluators;
}
// do not wrap arrays twice
if (argumentEvaluators.length - lastParam == 1 && actualArgumentExpressions[lastParam].getType() instanceof PsiArrayType) {
return argumentEvaluators;
}
PsiEllipsisType declaredParamType = (PsiEllipsisType)methodResolveSubstitutor.substitute(declaredParams[lastParam].getType());
ArrayInitializerEvaluator varargArrayEvaluator =
new ArrayInitializerEvaluator(Arrays.copyOfRange(argumentEvaluators, lastParam, argumentEvaluators.length));
NewArrayInstanceEvaluator evaluator =
new NewArrayInstanceEvaluator(new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(declaredParamType.toArrayType())), null,
varargArrayEvaluator);
Evaluator[] res = new Evaluator[declaredParams.length];
System.arraycopy(argumentEvaluators, 0, res, 0, lastParam);
res[lastParam] = new DisableGC(evaluator);
return res;
}
return argumentEvaluators;
}
private static void processBoxingConversions(final PsiParameter[] declaredParams,
final PsiExpression[] actualArgumentExpressions,
final PsiSubstitutor methodResolveSubstitutor,