Skip to content

Commit

Permalink
Merge pull request #3084 from jlerbsc/master
Browse files Browse the repository at this point in the history
Fix choosing the most specific method in case of java.lang.Object argument type
  • Loading branch information
jlerbsc committed Feb 16, 2021
2 parents dd3785d + 9f8bfa7 commit 9ee8894
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ private static boolean isApplicable(ResolvedMethodDeclaration methodDeclaration,
matchedParameters.put(expectedDeclaredType.asTypeParameter().getName(), actualArgumentType);
continue;
}

boolean isAssignableWithoutSubstitution = expectedDeclaredType.isAssignableBy(actualArgumentType) ||
(methodDeclaration.getParam(i).isVariadic() && new ResolvedArrayType(expectedDeclaredType).isAssignableBy(actualArgumentType));

Expand Down Expand Up @@ -624,6 +624,7 @@ private static boolean isMoreSpecific(ResolvedMethodDeclaration methodA, Resolve
final ResolvedType lastArgType = numberOfArgs > 0 ? argumentTypes.get(numberOfArgs - 1) : null;
final boolean isLastArgArray = lastArgType != null && lastArgType.isArray();
int omittedArgs = 0;
boolean isMethodAMoreSpecific = false;

// If one method declaration has exactly the correct amount of parameters and is not variadic then it is always
// preferred to a declaration that is variadic (and hence possibly also has a different amount of parameters).
Expand Down Expand Up @@ -679,9 +680,10 @@ else if (argType != null &&
// and the type of paramA or paramB (which are not more specific at this stage) is java.lang.Object
// then we have to consider others parameters before concluding
} else if ((i < numberOfArgs - 1)
&& (paramTypeB.isReferenceType() && paramTypeB.asReferenceType().getQualifiedName().equals("java.lang.Object")
|| (paramTypeA.isReferenceType() && paramTypeA.asReferenceType().getQualifiedName().equals("java.lang.Object")))) {
&& (isJavaLangObject(paramTypeB) || (isJavaLangObject(paramTypeA)))) {
// consider others parameters
// but eventually mark the method A as more specific if the methodB has an argument of type java.lang.Object
isMethodAMoreSpecific = isMethodAMoreSpecific || isJavaLangObject(paramTypeB);
}
// If we get to this point then we check whether one of the methods contains a parameter type that is more
// specific. If it does, we can assume the entire declaration is more specific as we would otherwise have
Expand Down Expand Up @@ -709,7 +711,11 @@ else if (argType != null &&
return !isLastArgArray;
}

return false;
return isMethodAMoreSpecific;
}

private static boolean isJavaLangObject(ResolvedType paramType ) {
return paramType.isReferenceType() && paramType.asReferenceType().getQualifiedName().equals("java.lang.Object");
}

private static boolean isMoreSpecific(MethodUsage methodA, MethodUsage methodB) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.github.javaparser.symbolsolver;

import org.junit.jupiter.api.Test;

import com.github.javaparser.ParserConfiguration;
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.symbolsolver.resolution.AbstractResolutionTest;
import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;

public class Issue3083Test extends AbstractResolutionTest {

@Test
void test() {
String code =
"class A {\n" +
" public void getFromMap() {\n" +
" final java.util.Map<String, String> expected = new java.util.HashMap<>();\n" +
" java.util.Map.Entry<String, String> entry = get(expected, 0);\n" +
" }\n" +
" <V, K> java.util.Map.Entry<K,V> get(java.util.Map<K,V> map, int index) {\n" +
" return null;\n" +
" }\n" +
" Object get(Object map, int index) {\n" +
" return null;\n" +
" }\n" +
" }";
ParserConfiguration config = new ParserConfiguration();
StaticJavaParser.getConfiguration().setSymbolResolver(new JavaSymbolSolver(new ReflectionTypeSolver()));
CompilationUnit cu = StaticJavaParser.parse(code);
MethodCallExpr mce = cu.findFirst(MethodCallExpr.class).get();
// this test must not throw a MethodAmbiguityException on the get(expected, 0) call
mce.resolve();
}

}

0 comments on commit 9ee8894

Please sign in to comment.