Generate InnerClasses attribute for nested classes in annotation arguments
Otherwise we incorrectly try to load a nested class "A.B" as if it is a top level class named "A$B" and fail. #KT-38853 Fixed
This commit is contained in:
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.descriptors.annotations.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.resolve.AnnotationChecker;
|
||||
@@ -432,8 +433,13 @@ public abstract class AnnotationCodegen {
|
||||
|
||||
@Override
|
||||
public Void visitEnumValue(EnumValue value, Void data) {
|
||||
String enumClassInternalName = AsmUtil.asmTypeByClassId(value.getEnumClassId()).getDescriptor();
|
||||
ClassId enumClassId = value.getEnumClassId();
|
||||
String enumClassInternalName = AsmUtil.asmTypeByClassId(enumClassId).getDescriptor();
|
||||
String enumEntryName = value.getEnumEntryName().asString();
|
||||
ClassDescriptor descriptor = FindClassInModuleKt.findClassAcrossModuleDependencies(state.getModule(), enumClassId);
|
||||
if (descriptor != null) {
|
||||
innerClassConsumer.addInnerClassInfoFromAnnotation(descriptor);
|
||||
}
|
||||
annotationVisitor.visitEnum(name, enumClassInternalName, enumEntryName);
|
||||
return null;
|
||||
}
|
||||
@@ -450,8 +456,9 @@ public abstract class AnnotationCodegen {
|
||||
|
||||
@Override
|
||||
public Void visitAnnotationValue(AnnotationValue value, Void data) {
|
||||
String internalAnnName = typeMapper.mapType(value.getValue().getType()).getDescriptor();
|
||||
AnnotationVisitor visitor = annotationVisitor.visitAnnotation(name, internalAnnName);
|
||||
KotlinType classType = value.getValue().getType();
|
||||
innerClassConsumer.addInnerClassInfoFromAnnotation(DescriptorUtils.getClassDescriptorForType(classType));
|
||||
AnnotationVisitor visitor = annotationVisitor.visitAnnotation(name, typeMapper.mapType(classType).getDescriptor());
|
||||
genAnnotationArguments(value.getValue(), visitor);
|
||||
visitor.visitEnd();
|
||||
return null;
|
||||
@@ -459,7 +466,9 @@ public abstract class AnnotationCodegen {
|
||||
|
||||
@Override
|
||||
public Void visitKClassValue(KClassValue value, Void data) {
|
||||
annotationVisitor.visit(name, typeMapper.mapType(value.getArgumentType(module)));
|
||||
KotlinType classType = value.getArgumentType(module);
|
||||
innerClassConsumer.addInnerClassInfoFromAnnotation(DescriptorUtils.getClassDescriptorForType(classType));
|
||||
annotationVisitor.visit(name, typeMapper.mapType(classType));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// FILE: annotations.kt
|
||||
|
||||
import kotlin.reflect.*
|
||||
|
||||
annotation class Anno(
|
||||
val k: KClass<*>,
|
||||
val e: C.NestedEnum,
|
||||
val a: C.NestedAnno,
|
||||
)
|
||||
|
||||
annotation class AnnoWithDefault(val k: KClass<*> = Nested0::class) {
|
||||
class Nested0
|
||||
}
|
||||
|
||||
class C {
|
||||
class Nested1
|
||||
|
||||
enum class NestedEnum { E }
|
||||
|
||||
annotation class NestedAnno(val k: KClass<*>) {
|
||||
class Nested2
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: usage.kt
|
||||
|
||||
interface I {
|
||||
@Anno(
|
||||
C.Nested1::class,
|
||||
C.NestedEnum.E,
|
||||
C.NestedAnno(C.NestedAnno.Nested2::class),
|
||||
)
|
||||
@AnnoWithDefault
|
||||
fun foo(): String = "OK"
|
||||
}
|
||||
|
||||
// @I.class:
|
||||
// 5 INNERCLASS
|
||||
// 1 INNERCLASS C\$Nested1 C Nested1
|
||||
// 1 INNERCLASS C\$NestedEnum C NestedEnum
|
||||
// 1 INNERCLASS C\$NestedAnno C NestedAnno
|
||||
// 1 INNERCLASS C\$NestedAnno\$Nested2 C\$NestedAnno Nested2
|
||||
// 1 INNERCLASS I\$DefaultImpls I DefaultImpls
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// FILE: 1.kt
|
||||
|
||||
import kotlin.reflect.*
|
||||
|
||||
annotation class Anno(
|
||||
val k: KClass<*>,
|
||||
val e: C.NestedEnum,
|
||||
val a: C.NestedAnno,
|
||||
)
|
||||
|
||||
annotation class AnnoWithDefault(val k: KClass<*> = Nested0::class) {
|
||||
class Nested0
|
||||
}
|
||||
|
||||
class C {
|
||||
class Nested1
|
||||
|
||||
enum class NestedEnum { E }
|
||||
|
||||
annotation class NestedAnno(val k: KClass<*>) {
|
||||
class Nested2
|
||||
}
|
||||
}
|
||||
|
||||
interface I {
|
||||
@Anno(
|
||||
C.Nested1::class,
|
||||
C.NestedEnum.E,
|
||||
C.NestedAnno(C.NestedAnno.Nested2::class),
|
||||
)
|
||||
@AnnoWithDefault
|
||||
fun foo(): String = "OK"
|
||||
}
|
||||
|
||||
// FILE: 2.kt
|
||||
|
||||
class D : I {
|
||||
fun box(): String = foo()
|
||||
}
|
||||
|
||||
fun box(): String = D().box()
|
||||
@@ -3052,6 +3052,24 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeText/innerClasses")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class InnerClasses extends AbstractBytecodeTextTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInInnerClasses() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/innerClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("nestedClassInAnnotationArgument.kt")
|
||||
public void testNestedClassInAnnotationArgument() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/innerClasses/nestedClassInAnnotationArgument.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeText/interfaces")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+5
@@ -268,6 +268,11 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/nestedClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nestedClassInAnnotationArgument.kt")
|
||||
public void testNestedClassInAnnotationArgument() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/nestedClassInAnnotationArgument.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nestedEnum.kt")
|
||||
public void testNestedEnum() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/nestedEnum.kt");
|
||||
|
||||
+18
@@ -3137,6 +3137,24 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeText/innerClasses")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class InnerClasses extends AbstractIrBytecodeTextTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInInnerClasses() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/innerClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@TestMetadata("nestedClassInAnnotationArgument.kt")
|
||||
public void testNestedClassInAnnotationArgument() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/innerClasses/nestedClassInAnnotationArgument.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeText/interfaces")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Generated
+5
@@ -263,6 +263,11 @@ public class IrCompileKotlinAgainstKotlinTestGenerated extends AbstractIrCompile
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/nestedClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nestedClassInAnnotationArgument.kt")
|
||||
public void testNestedClassInAnnotationArgument() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/nestedClassInAnnotationArgument.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nestedEnum.kt")
|
||||
public void testNestedEnum() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/nestedEnum.kt");
|
||||
|
||||
Reference in New Issue
Block a user