8319196: ExecutableElement.getReceiverType doesn't return receiver types for methods loaded from bytecode

Reviewed-by: vromero
This commit is contained in:
Liam Miller-Cushon 2023-11-14 17:38:09 +00:00
parent 0ea58048f9
commit 346dbd6d1c
4 changed files with 94 additions and 29 deletions

View File

@ -2276,6 +2276,21 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
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)
public Type getReturnType() {
return asType().getReturnType();

View File

@ -2333,8 +2333,13 @@ public class ClassReader {
}
mt.thrown = thrown.toList();
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;
}

View File

@ -28,6 +28,7 @@
* @library /tools/javac/lib
* @build JavacTestingAbstractProcessor TestExecutableReceiverType
* @compile -processor TestExecutableReceiverType -proc:only TestExecutableReceiverType.java
* @compile/process -processor TestExecutableReceiverType -proc:only MethodHost
*/
import java.util.Set;
@ -45,8 +46,14 @@ public class TestExecutableReceiverType extends JavacTestingAbstractProcessor {
RoundEnvironment roundEnv) {
if (!roundEnv.processingOver()) {
int count = 0;
count += testType(elements.getTypeElement("MethodHost"));
count += testType(elements.getTypeElement("MethodHost.Nested"));
for (ExecutableElement e : ElementFilter.methodsIn(
roundEnv.getElementsAnnotatedWith(ReceiverTypeKind.class))) {
count += testExecutable(e);
}
for (ExecutableElement e : ElementFilter.constructorsIn(
roundEnv.getElementsAnnotatedWith(ReceiverTypeKind.class))) {
count += testExecutable(e);
}
if (count == 0) {
messager.printError("No executables visited.");
@ -55,42 +62,42 @@ public class TestExecutableReceiverType extends JavacTestingAbstractProcessor {
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) {
TypeKind expectedKind = executable.getAnnotation(ReceiverTypeKind.class).value();
TypeKind actualKind = executable.getReceiverType().getKind();
ReceiverTypeKind expected = executable.getAnnotation(ReceiverTypeKind.class);
TypeKind expectedKind = expected.value();
String expectedType = expected.type();
TypeMirror actualType = executable.getReceiverType();
TypeKind actualKind = actualType.getKind();
if (actualKind != expectedKind) {
messager.printError(String.format("Unexpected TypeKind on receiver of %s:" +
" 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
TypeKind kindFromType = new TypeKindVisitor<TypeKind, Object>(null) {
TypeMirror fromType = new TypeKindVisitor<TypeMirror, Object>(null) {
@Override
public TypeKind visitExecutable(ExecutableType t, Object p) {
return t.getReceiverType().getKind();
public TypeMirror visitExecutable(ExecutableType t, Object p) {
return t.getReceiverType();
}
}.visit(executable.asType());
TypeKind kindFromType = fromType.getKind();
if (kindFromType != expectedKind) {
messager.printError(String.format("Unexpected TypeKind on executable's asType() of %s:" +
" 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;
}
@ -99,8 +106,12 @@ public class TestExecutableReceiverType extends JavacTestingAbstractProcessor {
@Retention(RetentionPolicy.RUNTIME)
@interface ReceiverTypeKind {
TypeKind value();
String type() default "";
}
@Target(ElementType.TYPE_USE)
@interface TA {}
/**
* Class to host various methods, etc.
*/
@ -114,11 +125,29 @@ class MethodHost {
@ReceiverTypeKind(TypeKind.NONE)
public void bar() {return;}
@ReceiverTypeKind(TypeKind.DECLARED)
public void quux(MethodHost this) {return;}
@ReceiverTypeKind(value = TypeKind.DECLARED, type = "@TA MethodHost")
public void quux(@TA MethodHost this) {return;}
private class Nested {
@ReceiverTypeKind(TypeKind.DECLARED)
public Nested(MethodHost MethodHost.this) {}
@ReceiverTypeKind(value = TypeKind.DECLARED, type = "@TA MethodHost")
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) {}
}
}
}

View File

@ -573,4 +573,20 @@ public class BasicAnnoTests extends JavacTestingAbstractProcessor {
@Test(posn=4, annoType = TB.class, expect = "100")
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) {}
}
}
}