diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/MethodTypeResolution.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/MethodTypeResolution.java index 8e0b0c31f9..d0f9567bc1 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/MethodTypeResolution.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/MethodTypeResolution.java @@ -69,34 +69,21 @@ public final class MethodTypeResolution { List subtypeableParams = subtypeableMethod.getParameterTypes(); List 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 methodsToSearch, ASTArgumentList argList) { // TODO: check if explicit type arguments are applicable to the type parameter bounds List 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 selectMethodsSecondPhase(List methodsToSearch, ASTArgumentList argList) { // TODO: check if explicit type arguments are applicable to the type parameter bounds List 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 diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java index 40df739b28..3ed5700ea6 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java @@ -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 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() { diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/VarargsAsFixedArity.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/VarargsAsFixedArity.java new file mode 100644 index 0000000000..11df97d3dc --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/VarargsAsFixedArity.java @@ -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; + } +}