From 346dbd6d1c1ac24da374dcdf4f432c0adf68efeb Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Tue, 14 Nov 2023 17:38:09 +0000 Subject: [PATCH] 8319196: ExecutableElement.getReceiverType doesn't return receiver types for methods loaded from bytecode Reviewed-by: vromero --- .../com/sun/tools/javac/code/Symbol.java | 15 ++++ .../com/sun/tools/javac/jvm/ClassReader.java | 9 +- .../element/TestExecutableReceiverType.java | 83 +++++++++++++------ .../processing/model/type/BasicAnnoTests.java | 16 ++++ 4 files changed, 94 insertions(+), 29 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java index 9e08a8cdd83..b3dcde6c8cf 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java @@ -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(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index f86a95e501c..232beb83b25 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -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; } diff --git a/test/langtools/tools/javac/processing/model/element/TestExecutableReceiverType.java b/test/langtools/tools/javac/processing/model/element/TestExecutableReceiverType.java index da979caa791..0b4f13ec8b5 100644 --- a/test/langtools/tools/javac/processing/model/element/TestExecutableReceiverType.java +++ b/test/langtools/tools/javac/processing/model/element/TestExecutableReceiverType.java @@ -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(null) { + TypeMirror fromType = new TypeKindVisitor(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 { + private class GenericNested { + @ReceiverTypeKind(value = TypeKind.DECLARED, type = "MethodHost.@TA Generic") + GenericNested(@TA Generic Generic.this) {} + + @ReceiverTypeKind(TypeKind.NONE) + GenericNested(int x) {} + } } } diff --git a/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java b/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java index af63575052c..219896c3305 100644 --- a/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java +++ b/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java @@ -573,4 +573,20 @@ public class BasicAnnoTests extends JavacTestingAbstractProcessor { @Test(posn=4, annoType = TB.class, expect = "100") class Inner100> { } + + // 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 { + private class GenericNested { + @Test(posn=2, annoType = TA.class, expect = "120") + GenericNested(@TA(120) GenericInner120 GenericInner120.this) {} + } + } }