Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix choosing the most specific method in case of java.lang.Object argument type #3084

Merged
merged 2 commits into from
Feb 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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();
}

}