Fix specificity test for varargs vs fixed

- We used to fail upon mixing varargs with fixed arity instead of
treating the vararg as a fixed arity as per the spec
This commit is contained in:
Juan Martín Sotuyo Dodero
2017-10-27 00:55:33 -03:00
parent d8f203a859
commit 83d513edca
3 changed files with 63 additions and 25 deletions

View File

@ -69,34 +69,21 @@ public final class MethodTypeResolution {
List<JavaTypeDefinition> subtypeableParams = subtypeableMethod.getParameterTypes();
List<JavaTypeDefinition> methodParams = method.getParameterTypes();
if (!method.getMethod().isVarArgs() && !subtypeableMethod.getMethod().isVarArgs()) {
// If we come from third-phase, both are varargs, otherwhise, treat all as fixed-arity
if (!method.getMethod().isVarArgs() || !subtypeableMethod.getMethod().isVarArgs()) {
for (int index = 0; index < subtypeableParams.size(); ++index) {
if (!isSubtypeable(methodParams.get(index), subtypeableParams.get(index))) {
return false;
}
}
} else if (method.getMethod().isVarArgs() && subtypeableMethod.getMethod().isVarArgs()) {
if (methodParams.size() < subtypeableParams.size()) {
for (int index = 0; index < subtypeableParams.size(); ++index) {
if (!isSubtypeable(method.getArgTypeIncludingVararg(index),
subtypeableMethod.getArgTypeIncludingVararg(index))) {
return false;
}
}
} else {
for (int index = 0; index < methodParams.size(); ++index) {
if (!isSubtypeable(method.getArgTypeIncludingVararg(index),
subtypeableMethod.getArgTypeIncludingVararg(index))) {
return false;
}
} else {
final int maxSize = Math.max(subtypeableParams.size(), methodParams.size());
for (int index = 0; index < maxSize; ++index) {
if (!isSubtypeable(method.getArgTypeIncludingVararg(index),
subtypeableMethod.getArgTypeIncludingVararg(index))) {
return false;
}
}
} else {
throw new IllegalStateException("These methods can only be vararg at the same time:\n"
+ method.toString() + "\n" + subtypeableMethod.toString());
}
return true;
@ -110,13 +97,12 @@ public final class MethodTypeResolution {
List<MethodType> methodsToSearch, ASTArgumentList argList) {
// TODO: check if explicit type arguments are applicable to the type parameter bounds
List<MethodType> selectedMethods = new ArrayList<>();
final int argCount = argList == null ? 0 : argList.jjtGetNumChildren();
outter:
for (int methodIndex = 0; methodIndex < methodsToSearch.size(); ++methodIndex) {
MethodType methodType = methodsToSearch.get(methodIndex);
final int argCount = argList == null ? 0 : argList.jjtGetNumChildren();
// vararg methods are considered fixed arity here, see 3rd phase
if (getArity(methodType.getMethod()) == argCount) {
if (!methodType.isParameterized()) {
@ -260,6 +246,7 @@ public final class MethodTypeResolution {
public static List<MethodType> selectMethodsSecondPhase(List<MethodType> methodsToSearch, ASTArgumentList argList) {
// TODO: check if explicit type arguments are applicable to the type parameter bounds
List<MethodType> selectedMethods = new ArrayList<>();
final int argCount = argList == null ? 0 : argList.jjtGetNumChildren();
for (int methodIndex = 0; methodIndex < methodsToSearch.size(); ++methodIndex) {
MethodType methodType = methodsToSearch.get(methodIndex);
@ -267,8 +254,6 @@ public final class MethodTypeResolution {
throw new ResolutionFailedException();
}
final int argCount = argList == null ? 0 : argList.jjtGetNumChildren();
// vararg methods are considered fixed arity here, see 3rd phase
if (getArity(methodType.getMethod()) == argCount) {
// check method convertability of each argument to the corresponding parameter

View File

@ -105,6 +105,7 @@ import net.sourceforge.pmd.typeresolution.testdata.SubTypeUsage;
import net.sourceforge.pmd.typeresolution.testdata.SuperExpression;
import net.sourceforge.pmd.typeresolution.testdata.ThisExpression;
import net.sourceforge.pmd.typeresolution.testdata.VarArgsMethodUseCase;
import net.sourceforge.pmd.typeresolution.testdata.VarargsAsFixedArity;
import net.sourceforge.pmd.typeresolution.testdata.VarargsZeroArity;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.Converter;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.GenericClass;
@ -1542,6 +1543,35 @@ public class ClassTypeResolverTest {
// Make sure we got them all
assertEquals("All expressions not tested", index, expressions.size());
}
@Test
public void testMethodTypeInferenceVarargsAsFixedArity() throws JaxenException {
ASTCompilationUnit acu = parseAndTypeResolveForClass15(VarargsAsFixedArity.class);
List<AbstractJavaTypeNode> expressions = convertList(
acu.findChildNodesWithXPath("//VariableInitializer/Expression/PrimaryExpression"),
AbstractJavaTypeNode.class);
int index = 0;
// int var = aMethod("");
assertEquals(int.class, expressions.get(index++).getType());
// String var2 = aMethod();
assertEquals(String.class, expressions.get(index++).getType());
// String var3 = aMethod("", "");
assertEquals(String.class, expressions.get(index++).getType());
// String var4 = aMethod(new Object[] { null });
assertEquals(String.class, expressions.get(index++).getType());
// null literal has null type
assertNull(expressions.get(index++).getType());
// Make sure we got them all
assertEquals("All expressions not tested", index, expressions.size());
}
@Test
public void testJavaTypeDefinitionEquals() {

View File

@ -0,0 +1,23 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.typeresolution.testdata;
public class VarargsAsFixedArity {
public void tester() {
int var = aMethod("");
String var2 = aMethod();
String var3 = aMethod("", "");
String var4 = aMethod(new Object[] { null });
}
public int aMethod(Object s) {
return 0;
}
public String aMethod(Object... s) {
return null;
}
}