8278373: JavacTrees.searchMethod finds incorrect match

Reviewed-by: vromero, jjg
This commit is contained in:
Jan Lahoda 2022-01-10 08:33:46 +00:00
parent d65c665839
commit 642ab34a60
2 changed files with 87 additions and 18 deletions

View File

@ -507,10 +507,16 @@ public class JavacTrees extends DocTrees {
}
ClassSymbol sym = (ClassSymbol) types.skipTypeVars(tsym.type, false).tsym;
Symbol msym = (memberName == sym.name)
? findConstructor(sym, paramTypes)
: findMethod(sym, memberName, paramTypes);
? findConstructor(sym, paramTypes, true)
: findMethod(sym, memberName, paramTypes, true);
if (msym == null) {
msym = (memberName == sym.name)
? findConstructor(sym, paramTypes, false)
: findMethod(sym, memberName, paramTypes, false);
}
if (paramTypes != null) {
// explicit (possibly empty) arg list given, so cannot be a field
return msym;
@ -608,10 +614,10 @@ public class JavacTrees extends DocTrees {
return null;
}
MethodSymbol findConstructor(ClassSymbol tsym, List<Type> paramTypes) {
MethodSymbol findConstructor(ClassSymbol tsym, List<Type> paramTypes, boolean strict) {
for (Symbol sym : tsym.members().getSymbolsByName(names.init)) {
if (sym.kind == MTH) {
if (hasParameterTypes((MethodSymbol) sym, paramTypes)) {
if (hasParameterTypes((MethodSymbol) sym, paramTypes, strict)) {
return (MethodSymbol) sym;
}
}
@ -619,12 +625,13 @@ public class JavacTrees extends DocTrees {
return null;
}
private MethodSymbol findMethod(ClassSymbol tsym, Name methodName, List<Type> paramTypes) {
return searchMethod(tsym, methodName, paramTypes, new HashSet<>());
private MethodSymbol findMethod(ClassSymbol tsym, Name methodName, List<Type> paramTypes, boolean strict) {
return searchMethod(tsym, methodName, paramTypes, strict, new HashSet<>());
}
private MethodSymbol searchMethod(ClassSymbol tsym, Name methodName,
List<Type> paramTypes, Set<ClassSymbol> searched) {
List<Type> paramTypes, boolean strict,
Set<ClassSymbol> searched) {
//### Note that this search is not necessarily what the compiler would do!
// do not match constructors
@ -662,7 +669,7 @@ public class JavacTrees extends DocTrees {
for (Symbol sym : tsym.members().getSymbolsByName(methodName)) {
if (sym != null &&
sym.kind == MTH) {
if (hasParameterTypes((MethodSymbol) sym, paramTypes)) {
if (hasParameterTypes((MethodSymbol) sym, paramTypes, strict)) {
return (MethodSymbol) sym;
}
}
@ -675,7 +682,7 @@ public class JavacTrees extends DocTrees {
// search superclass
Type superclass = tsym.getSuperclass();
if (superclass.tsym != null) {
MethodSymbol msym = searchMethod((ClassSymbol) superclass.tsym, methodName, paramTypes, searched);
MethodSymbol msym = searchMethod((ClassSymbol) superclass.tsym, methodName, paramTypes, strict, searched);
if (msym != null) {
return msym;
}
@ -686,7 +693,7 @@ public class JavacTrees extends DocTrees {
for (List<Type> l = intfs; l.nonEmpty(); l = l.tail) {
Type intf = l.head;
if (intf.isErroneous()) continue;
MethodSymbol msym = searchMethod((ClassSymbol) intf.tsym, methodName, paramTypes, searched);
MethodSymbol msym = searchMethod((ClassSymbol) intf.tsym, methodName, paramTypes, strict, searched);
if (msym != null) {
return msym;
}
@ -695,7 +702,7 @@ public class JavacTrees extends DocTrees {
// search enclosing class
ClassSymbol encl = tsym.owner.enclClass();
if (encl != null) {
MethodSymbol msym = searchMethod(encl, methodName, paramTypes, searched);
MethodSymbol msym = searchMethod(encl, methodName, paramTypes, strict, searched);
if (msym != null) {
return msym;
}
@ -704,7 +711,7 @@ public class JavacTrees extends DocTrees {
return null;
}
private boolean hasParameterTypes(MethodSymbol method, List<Type> paramTypes) {
private boolean hasParameterTypes(MethodSymbol method, List<Type> paramTypes, boolean strict) {
if (paramTypes == null)
return true;
@ -712,7 +719,7 @@ public class JavacTrees extends DocTrees {
return false;
List<Type> methodParamTypes = method.asType().getParameterTypes();
if (!Type.isErroneous(paramTypes) && types.isSubtypes(paramTypes, methodParamTypes)) {
if (!strict && !Type.isErroneous(paramTypes) && types.isSubtypes(paramTypes, methodParamTypes)) {
return true;
}

View File

@ -23,7 +23,7 @@
/*
* @test
* @bug 7021614
* @bug 7021614 8278373
* @summary extend com.sun.source API to support parsing javadoc comments
* @summary check references in at-see and {at-link} tags
* @modules jdk.compiler
@ -39,19 +39,23 @@ import com.sun.source.doctree.SeeTree;
import com.sun.source.doctree.TextTree;
import com.sun.source.util.DocTreePath;
import com.sun.source.util.DocTreePathScanner;
import com.sun.source.util.DocTreeScanner;
import com.sun.source.util.DocTrees;
import com.sun.source.util.TreePath;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.QualifiedNameable;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic.Kind;
/**
@ -174,8 +178,18 @@ public class ReferenceTest extends AbstractProcessor {
if (label.size() > 0 && label.get(0) instanceof TextTree)
expect = ((TextTree) label.get(0)).getBody();
if (!expect.equalsIgnoreCase(found == null ? "bad" : found.getKind().name())) {
error(tree, "Unexpected value found: " + found +", expected: " + expect);
if (expect.startsWith("signature:")) {
expect = expect.substring("signature:".length());
String signature = found.getKind().name() + ":" + elementSignature(found);
if (!expect.equalsIgnoreCase(signature)) {
error(tree, "Unexpected value found: " + signature +", expected: " + expect);
}
} else {
if (!expect.equalsIgnoreCase(found == null ? "bad" : found.getKind().name())) {
error(tree, "Unexpected value found: " + found +", expected: " + expect);
}
}
}
@ -183,6 +197,29 @@ public class ReferenceTest extends AbstractProcessor {
trees.printMessage(Kind.ERROR, msg, tree, dc, path.getCompilationUnit());
}
}
String elementSignature(Element el) {
return switch (el.getKind()) {
case METHOD -> elementSignature(el.getEnclosingElement()) + "." + el.getSimpleName() + "(" + executableParamNames((ExecutableElement) el) + ")";
case CLASS, INTERFACE -> ((QualifiedNameable) el).getQualifiedName().toString();
default -> throw new AssertionError("Unhandled Element kind: " + el.getKind());
};
}
String executableParamNames(ExecutableElement ee) {
return ee.getParameters()
.stream()
.map(p -> type2Name(p.asType()))
.collect(Collectors.joining(", "));
}
String type2Name(TypeMirror type) {
return switch (type.getKind()) {
case DECLARED -> elementSignature(((DeclaredType) type).asElement());
case INT, LONG -> type.toString();
default -> throw new AssertionError("Unhandled type kind: " + type.getKind());
};
}
}
/**
@ -199,6 +236,17 @@ public class ReferenceTest extends AbstractProcessor {
* @see #varargs(int... args) Method
* @see #varargs(int[]) Method
* @see #varargs(int[] args) Method
*
* @see #methodSearch(String) signature:METHOD:ReferenceTestExtras.methodSearch(java.lang.String)
* @see #methodSearch(StringBuilder) signature:METHOD:ReferenceTestExtras.methodSearch(java.lang.CharSequence)
* @see #methodSearchPrimitive1(int, int) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive1(int, int)
* @see #methodSearchPrimitive1(long, int) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive1(long, int)
* @see #methodSearchPrimitive1(int, long) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive1(int, long)
* @see #methodSearchPrimitive1(long, long) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive1(long, long)
* @see #methodSearchPrimitive2(int, int) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive2(int, int)
* @see #methodSearchPrimitive2(long, int) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive2(long, int)
* @see #methodSearchPrimitive2(int, long) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive2(int, long)
* @see #methodSearchPrimitive2(long, long) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive2(long, long)
*/
class ReferenceTestExtras {
int ReferenceTestExtras; // field
@ -214,6 +262,20 @@ class ReferenceTestExtras {
void m(int i, int j) { }
void varargs(int... args) { }
void methodSearch(Object o) {}
void methodSearch(String s) {}
void methodSearch(CharSequence cs) {}
void methodSearchPrimitive1(int i, int j) {}
void methodSearchPrimitive1(long i, int j) {}
void methodSearchPrimitive1(int i, long j) {}
void methodSearchPrimitive1(long i, long j) {}
void methodSearchPrimitive2(long i, long j) {}
void methodSearchPrimitive2(int i, long j) {}
void methodSearchPrimitive2(long i, int j) {}
void methodSearchPrimitive2(int i, int j) {}
}