8278373: JavacTrees.searchMethod finds incorrect match
Reviewed-by: vromero, jjg
This commit is contained in:
parent
d65c665839
commit
642ab34a60
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user