mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-15 16:44:36 +02:00
8319196: ExecutableElement.getReceiverType doesn't return receiver types for methods loaded from bytecode
Reviewed-by: vromero
This commit is contained in:
parent
0ea58048f9
commit
346dbd6d1c
4 changed files with 94 additions and 29 deletions
|
@ -2276,6 +2276,21 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||||
return asType().getReceiverType();
|
return asType().getReceiverType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Type implicitReceiverType() {
|
||||||
|
ClassSymbol enclosingClass = enclClass();
|
||||||
|
if (enclosingClass == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Type enclosingType = enclosingClass.type;
|
||||||
|
if (isConstructor()) {
|
||||||
|
return enclosingType.getEnclosingType();
|
||||||
|
}
|
||||||
|
if (!isStatic()) {
|
||||||
|
return enclosingType;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||||
public Type getReturnType() {
|
public Type getReturnType() {
|
||||||
return asType().getReturnType();
|
return asType().getReturnType();
|
||||||
|
|
|
@ -2333,8 +2333,13 @@ public class ClassReader {
|
||||||
}
|
}
|
||||||
mt.thrown = thrown.toList();
|
mt.thrown = thrown.toList();
|
||||||
mt.restype = addTypeAnnotations(mt.restype, TargetType.METHOD_RETURN);
|
mt.restype = addTypeAnnotations(mt.restype, TargetType.METHOD_RETURN);
|
||||||
if (mt.recvtype != null) {
|
|
||||||
mt.recvtype = addTypeAnnotations(mt.recvtype, TargetType.METHOD_RECEIVER);
|
Type recvtype = mt.recvtype != null ? mt.recvtype : s.implicitReceiverType();
|
||||||
|
if (recvtype != null) {
|
||||||
|
Type annotated = addTypeAnnotations(recvtype, TargetType.METHOD_RECEIVER);
|
||||||
|
if (annotated != recvtype) {
|
||||||
|
mt.recvtype = annotated;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
* @library /tools/javac/lib
|
* @library /tools/javac/lib
|
||||||
* @build JavacTestingAbstractProcessor TestExecutableReceiverType
|
* @build JavacTestingAbstractProcessor TestExecutableReceiverType
|
||||||
* @compile -processor TestExecutableReceiverType -proc:only TestExecutableReceiverType.java
|
* @compile -processor TestExecutableReceiverType -proc:only TestExecutableReceiverType.java
|
||||||
|
* @compile/process -processor TestExecutableReceiverType -proc:only MethodHost
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -45,8 +46,14 @@ public class TestExecutableReceiverType extends JavacTestingAbstractProcessor {
|
||||||
RoundEnvironment roundEnv) {
|
RoundEnvironment roundEnv) {
|
||||||
if (!roundEnv.processingOver()) {
|
if (!roundEnv.processingOver()) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
count += testType(elements.getTypeElement("MethodHost"));
|
for (ExecutableElement e : ElementFilter.methodsIn(
|
||||||
count += testType(elements.getTypeElement("MethodHost.Nested"));
|
roundEnv.getElementsAnnotatedWith(ReceiverTypeKind.class))) {
|
||||||
|
count += testExecutable(e);
|
||||||
|
}
|
||||||
|
for (ExecutableElement e : ElementFilter.constructorsIn(
|
||||||
|
roundEnv.getElementsAnnotatedWith(ReceiverTypeKind.class))) {
|
||||||
|
count += testExecutable(e);
|
||||||
|
}
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
messager.printError("No executables visited.");
|
messager.printError("No executables visited.");
|
||||||
|
@ -55,42 +62,42 @@ public class TestExecutableReceiverType extends JavacTestingAbstractProcessor {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int testType(TypeElement typeElement) {
|
|
||||||
int count = 0;
|
|
||||||
for (ExecutableElement executable :
|
|
||||||
ElementFilter.constructorsIn(typeElement.getEnclosedElements())) {
|
|
||||||
count += testExecutable(executable);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ExecutableElement executable :
|
|
||||||
ElementFilter.methodsIn(typeElement.getEnclosedElements())) {
|
|
||||||
count += testExecutable(executable);
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
int testExecutable(ExecutableElement executable) {
|
int testExecutable(ExecutableElement executable) {
|
||||||
TypeKind expectedKind = executable.getAnnotation(ReceiverTypeKind.class).value();
|
ReceiverTypeKind expected = executable.getAnnotation(ReceiverTypeKind.class);
|
||||||
TypeKind actualKind = executable.getReceiverType().getKind();
|
TypeKind expectedKind = expected.value();
|
||||||
|
String expectedType = expected.type();
|
||||||
|
TypeMirror actualType = executable.getReceiverType();
|
||||||
|
TypeKind actualKind = actualType.getKind();
|
||||||
|
|
||||||
if (actualKind != expectedKind) {
|
if (actualKind != expectedKind) {
|
||||||
messager.printError(String.format("Unexpected TypeKind on receiver of %s:" +
|
messager.printError(String.format("Unexpected TypeKind on receiver of %s:" +
|
||||||
" expected %s\t got %s%n",
|
" expected %s\t got %s%n",
|
||||||
executable, expectedKind, actualKind));
|
executable, expectedKind, actualKind), executable);
|
||||||
|
}
|
||||||
|
if (!expectedType.isEmpty() && !actualType.toString().equals(expectedType)) {
|
||||||
|
messager.printError(String.format("Unexpected receiver type of %s:" +
|
||||||
|
" expected %s\t got %s%n",
|
||||||
|
executable, expectedType, actualType), executable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get kind from the type of the executable directly
|
// Get kind from the type of the executable directly
|
||||||
TypeKind kindFromType = new TypeKindVisitor<TypeKind, Object>(null) {
|
TypeMirror fromType = new TypeKindVisitor<TypeMirror, Object>(null) {
|
||||||
@Override
|
@Override
|
||||||
public TypeKind visitExecutable(ExecutableType t, Object p) {
|
public TypeMirror visitExecutable(ExecutableType t, Object p) {
|
||||||
return t.getReceiverType().getKind();
|
return t.getReceiverType();
|
||||||
}
|
}
|
||||||
}.visit(executable.asType());
|
}.visit(executable.asType());
|
||||||
|
TypeKind kindFromType = fromType.getKind();
|
||||||
|
|
||||||
if (kindFromType != expectedKind) {
|
if (kindFromType != expectedKind) {
|
||||||
messager.printError(String.format("Unexpected TypeKind on executable's asType() of %s:" +
|
messager.printError(String.format("Unexpected TypeKind on executable's asType() of %s:" +
|
||||||
" expected %s\t got %s%n",
|
" expected %s\t got %s%n",
|
||||||
executable, expectedKind, kindFromType));
|
executable, expectedKind, kindFromType), executable);
|
||||||
|
}
|
||||||
|
if (!expectedType.isEmpty() && !fromType.toString().equals(expectedType)) {
|
||||||
|
messager.printError(String.format("Unexpected receiver type of %s:" +
|
||||||
|
" expected %s\t got %s%n",
|
||||||
|
executable, expectedType, fromType), executable);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -99,8 +106,12 @@ public class TestExecutableReceiverType extends JavacTestingAbstractProcessor {
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@interface ReceiverTypeKind {
|
@interface ReceiverTypeKind {
|
||||||
TypeKind value();
|
TypeKind value();
|
||||||
|
String type() default "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Target(ElementType.TYPE_USE)
|
||||||
|
@interface TA {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to host various methods, etc.
|
* Class to host various methods, etc.
|
||||||
*/
|
*/
|
||||||
|
@ -114,11 +125,29 @@ class MethodHost {
|
||||||
@ReceiverTypeKind(TypeKind.NONE)
|
@ReceiverTypeKind(TypeKind.NONE)
|
||||||
public void bar() {return;}
|
public void bar() {return;}
|
||||||
|
|
||||||
@ReceiverTypeKind(TypeKind.DECLARED)
|
@ReceiverTypeKind(value = TypeKind.DECLARED, type = "@TA MethodHost")
|
||||||
public void quux(MethodHost this) {return;}
|
public void quux(@TA MethodHost this) {return;}
|
||||||
|
|
||||||
private class Nested {
|
private class Nested {
|
||||||
@ReceiverTypeKind(TypeKind.DECLARED)
|
@ReceiverTypeKind(value = TypeKind.DECLARED, type = "@TA MethodHost")
|
||||||
public Nested(MethodHost MethodHost.this) {}
|
public Nested(@TA MethodHost MethodHost.this) {}
|
||||||
|
|
||||||
|
@ReceiverTypeKind(TypeKind.NONE)
|
||||||
|
public Nested(int foo) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class StaticNested {
|
||||||
|
@ReceiverTypeKind(TypeKind.NONE)
|
||||||
|
public StaticNested() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Generic<X> {
|
||||||
|
private class GenericNested<Y> {
|
||||||
|
@ReceiverTypeKind(value = TypeKind.DECLARED, type = "MethodHost.@TA Generic<X>")
|
||||||
|
GenericNested(@TA Generic<X> Generic.this) {}
|
||||||
|
|
||||||
|
@ReceiverTypeKind(TypeKind.NONE)
|
||||||
|
GenericNested(int x) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -573,4 +573,20 @@ public class BasicAnnoTests extends JavacTestingAbstractProcessor {
|
||||||
@Test(posn=4, annoType = TB.class, expect = "100")
|
@Test(posn=4, annoType = TB.class, expect = "100")
|
||||||
class Inner100<T extends Inner100<@TB(100) T>> {
|
class Inner100<T extends Inner100<@TB(100) T>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// receiver parameters
|
||||||
|
class Inner110 {
|
||||||
|
@Test(posn=2, annoType = TA.class, expect = "110")
|
||||||
|
void f(@TA(110) Inner110 this) {}
|
||||||
|
|
||||||
|
@Test(posn=2, annoType = TA.class, expect = "111")
|
||||||
|
Inner110(@TA(111) BasicAnnoTests BasicAnnoTests.this) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class GenericInner120<X> {
|
||||||
|
private class GenericNested<Y> {
|
||||||
|
@Test(posn=2, annoType = TA.class, expect = "120")
|
||||||
|
GenericNested(@TA(120) GenericInner120<X> GenericInner120.this) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue