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

View File

@ -23,7 +23,7 @@
/* /*
* @test * @test
* @bug 7021614 * @bug 7021614 8278373
* @summary extend com.sun.source API to support parsing javadoc comments * @summary extend com.sun.source API to support parsing javadoc comments
* @summary check references in at-see and {at-link} tags * @summary check references in at-see and {at-link} tags
* @modules jdk.compiler * @modules jdk.compiler
@ -39,19 +39,23 @@ import com.sun.source.doctree.SeeTree;
import com.sun.source.doctree.TextTree; import com.sun.source.doctree.TextTree;
import com.sun.source.util.DocTreePath; import com.sun.source.util.DocTreePath;
import com.sun.source.util.DocTreePathScanner; import com.sun.source.util.DocTreePathScanner;
import com.sun.source.util.DocTreeScanner;
import com.sun.source.util.DocTrees; import com.sun.source.util.DocTrees;
import com.sun.source.util.TreePath; import com.sun.source.util.TreePath;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion; import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element; 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.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic.Kind; import javax.tools.Diagnostic.Kind;
/** /**
@ -174,8 +178,18 @@ public class ReferenceTest extends AbstractProcessor {
if (label.size() > 0 && label.get(0) instanceof TextTree) if (label.size() > 0 && label.get(0) instanceof TextTree)
expect = ((TextTree) label.get(0)).getBody(); expect = ((TextTree) label.get(0)).getBody();
if (!expect.equalsIgnoreCase(found == null ? "bad" : found.getKind().name())) { if (expect.startsWith("signature:")) {
error(tree, "Unexpected value found: " + found +", expected: " + expect); 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()); 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... args) Method
* @see #varargs(int[]) Method * @see #varargs(int[]) Method
* @see #varargs(int[] args) 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 { class ReferenceTestExtras {
int ReferenceTestExtras; // field int ReferenceTestExtras; // field
@ -214,6 +262,20 @@ class ReferenceTestExtras {
void m(int i, int j) { } void m(int i, int j) { }
void varargs(int... args) { } 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) {}
} }