[FIR] Fix loading of classId for nested enums in java annotation arguments
^KT-55887 Fixed ^KT-55976
This commit is contained in:
committed by
Space Team
parent
da0dd519d0
commit
259303ca50
+5
@@ -431,6 +431,11 @@ public class FirTypeEnhancementTestGenerated extends AbstractFirTypeEnhancementT
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/NestedEnumArgument.java");
|
||||
}
|
||||
|
||||
@TestMetadata("NestedEnumInAnnotation.java")
|
||||
public void testNestedEnumInAnnotation() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/NestedEnumInAnnotation.java");
|
||||
}
|
||||
|
||||
@TestMetadata("PrimitiveValueInParam.java")
|
||||
public void testPrimitiveValueInParam() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/PrimitiveValueInParam.java");
|
||||
|
||||
+41
-1
@@ -246,7 +246,47 @@ class BinaryJavaAnnotationVisitor(
|
||||
}
|
||||
|
||||
override fun visitEnum(name: String?, desc: String, value: String) {
|
||||
val enumClassId = context.mapInternalNameToClassId(Type.getType(desc).internalName)
|
||||
/**
|
||||
* There are cases when enum is an inner class of some class which is not related to current loading Java class.
|
||||
* And in this cases `mapInternalNameToClassId` leaves `$` in name as is, which may lead to unresolved errors later
|
||||
* in compiler
|
||||
*
|
||||
* @Api(status = Api.Status.Ok) // classId will be /Api$Status.Ok
|
||||
* public class NestedEnumInAnnotation {}
|
||||
*
|
||||
* public @interface Api {
|
||||
* Status status();
|
||||
*
|
||||
* enum Status {
|
||||
* Ok, Error;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* It's impossible to use `resolveByInternalName` (which always provides correct classId), because it may lead to
|
||||
* StackOverflowError for cases when enum and annotation are declared in same outer class, which will lead to
|
||||
* infinite loading of this class
|
||||
*
|
||||
* public class NestedEnumArgument {
|
||||
* public enum E {
|
||||
* FIRST
|
||||
* }
|
||||
*
|
||||
* public @interface Anno {
|
||||
* E value();
|
||||
* }
|
||||
*
|
||||
* @Anno(E.FIRST)
|
||||
* void foo() {}
|
||||
* }
|
||||
*
|
||||
* So to avoid such recursion and in the same time fix original case we use simple heuristic about names with $
|
||||
* for enums in annotation arguments which contain `$` in internal name
|
||||
*/
|
||||
val internalName = Type.getType(desc).internalName
|
||||
var enumClassId = context.mapInternalNameToClassId(internalName)
|
||||
if (enumClassId.asString().contains("$")) {
|
||||
enumClassId = context.convertNestedClassInternalNameWithSimpleHeuristic(internalName) ?: enumClassId
|
||||
}
|
||||
addArgument(PlainJavaEnumValueAnnotationArgument(name, enumClassId, value))
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ class ClassifierResolutionContext private constructor(
|
||||
}
|
||||
|
||||
// See com.intellij.psi.impl.compiled.StubBuildingVisitor.GUESSING_MAPPER
|
||||
private fun convertNestedClassInternalNameWithSimpleHeuristic(internalName: String): ClassId? {
|
||||
internal fun convertNestedClassInternalNameWithSimpleHeuristic(internalName: String): ClassId? {
|
||||
val splitPoints = SmartList<Int>()
|
||||
for (p in internalName.indices) {
|
||||
val c = internalName[p]
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
public final annotation class Api : R|kotlin/Annotation| {
|
||||
public constructor(status: R|test/Api.Status|): R|test/Api|
|
||||
|
||||
public final enum class Status : R|kotlin/Enum<test/Api.Status!>| {
|
||||
public final static enum entry Ok: R|@EnhancedNullability test/Api.Status|
|
||||
public final static enum entry Error: R|@EnhancedNullability test/Api.Status|
|
||||
public final static fun values(): R|kotlin/Array<test/Api.Status>| {
|
||||
}
|
||||
|
||||
public final static fun valueOf(value: R|kotlin/String|): R|test/Api.Status| {
|
||||
}
|
||||
|
||||
public final static val entries: R|kotlin/enums/EnumEntries<test/Api.Status>|
|
||||
public get(): R|kotlin/enums/EnumEntries<test/Api.Status>|
|
||||
|
||||
}
|
||||
}
|
||||
@R|test/Api|(status = R|test/Api.Status.Ok|()) public open class NestedEnumInAnnotation : R|kotlin/Any| {
|
||||
public constructor(): R|test/NestedEnumInAnnotation|
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// FILE: NestedEnumInAnnotation.java
|
||||
|
||||
package test;
|
||||
|
||||
@Api(status = Api.Status.Ok)
|
||||
public class NestedEnumInAnnotation {}
|
||||
|
||||
// FILE: Api.java
|
||||
package test;
|
||||
|
||||
public @interface Api {
|
||||
Status status();
|
||||
|
||||
enum Status {
|
||||
Ok, Error;
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package test
|
||||
|
||||
public final annotation class Api : kotlin.Annotation {
|
||||
public constructor Api(/*0*/ status: test.Api.Status)
|
||||
public final val status: test.Api.Status
|
||||
|
||||
public final enum class Status : kotlin.Enum<test.Api.Status!> {
|
||||
enum entry Ok
|
||||
|
||||
enum entry Error
|
||||
|
||||
private constructor Status()
|
||||
@kotlin.internal.IntrinsicConstEvaluation public final override /*1*/ /*fake_override*/ val name: kotlin.String
|
||||
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
|
||||
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
|
||||
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: test.Api.Status!): kotlin.Int
|
||||
protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
|
||||
public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<test.Api.Status!>!
|
||||
|
||||
// Static members
|
||||
public final /*synthesized*/ val entries: kotlin.enums.EnumEntries<test.Api.Status>
|
||||
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): test.Api.Status
|
||||
public final /*synthesized*/ fun values(): kotlin.Array<test.Api.Status>
|
||||
}
|
||||
}
|
||||
|
||||
@test.Api(status = Status.Ok) public open class NestedEnumInAnnotation {
|
||||
public constructor NestedEnumInAnnotation()
|
||||
}
|
||||
+5
@@ -433,6 +433,11 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest {
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/NestedEnumArgument.java");
|
||||
}
|
||||
|
||||
@TestMetadata("NestedEnumInAnnotation.java")
|
||||
public void testNestedEnumInAnnotation() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/NestedEnumInAnnotation.java");
|
||||
}
|
||||
|
||||
@TestMetadata("PrimitiveValueInParam.java")
|
||||
public void testPrimitiveValueInParam() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/PrimitiveValueInParam.java");
|
||||
|
||||
Generated
+5
@@ -431,6 +431,11 @@ public class LoadJavaWithPsiClassReadingTestGenerated extends AbstractLoadJavaWi
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/NestedEnumArgument.java");
|
||||
}
|
||||
|
||||
@TestMetadata("NestedEnumInAnnotation.java")
|
||||
public void testNestedEnumInAnnotation() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/NestedEnumInAnnotation.java");
|
||||
}
|
||||
|
||||
@TestMetadata("PrimitiveValueInParam.java")
|
||||
public void testPrimitiveValueInParam() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/PrimitiveValueInParam.java");
|
||||
|
||||
+5
@@ -434,6 +434,11 @@ public class IrLoadJavaTestGenerated extends AbstractIrLoadJavaTest {
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/NestedEnumArgument.java");
|
||||
}
|
||||
|
||||
@TestMetadata("NestedEnumInAnnotation.java")
|
||||
public void testNestedEnumInAnnotation() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/NestedEnumInAnnotation.java");
|
||||
}
|
||||
|
||||
@TestMetadata("PrimitiveValueInParam.java")
|
||||
public void testPrimitiveValueInParam() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/PrimitiveValueInParam.java");
|
||||
|
||||
Generated
+5
@@ -433,6 +433,11 @@ public class LoadJavaUsingJavacTestGenerated extends AbstractLoadJavaUsingJavacT
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/NestedEnumArgument.java");
|
||||
}
|
||||
|
||||
@TestMetadata("NestedEnumInAnnotation.java")
|
||||
public void testNestedEnumInAnnotation() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/NestedEnumInAnnotation.java");
|
||||
}
|
||||
|
||||
@TestMetadata("PrimitiveValueInParam.java")
|
||||
public void testPrimitiveValueInParam() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/PrimitiveValueInParam.java");
|
||||
|
||||
+5
@@ -3279,6 +3279,11 @@ public class JvmRuntimeDescriptorLoaderTestGenerated extends AbstractJvmRuntimeD
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/NestedEnumArgument.java");
|
||||
}
|
||||
|
||||
@TestMetadata("NestedEnumInAnnotation.java")
|
||||
public void testNestedEnumInAnnotation() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/NestedEnumInAnnotation.java");
|
||||
}
|
||||
|
||||
@TestMetadata("PrimitiveValueInParam.java")
|
||||
public void testPrimitiveValueInParam() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledJava/annotations/PrimitiveValueInParam.java");
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// WITH_STDLIB
|
||||
// ISSUE: KT-55887
|
||||
|
||||
// MODULE: lib
|
||||
// FILE: NoArg.kt
|
||||
annotation class NoArg
|
||||
|
||||
// FILE: Api.java
|
||||
@NoArg
|
||||
public @interface Api {
|
||||
Status status();
|
||||
|
||||
enum Status {
|
||||
Ok, Error;
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: ExtendWith.java
|
||||
@Api(status = Api.Status.Ok)
|
||||
public @interface ExtendWith {}
|
||||
|
||||
// MODULE: main(lib)
|
||||
// FILE: main.kt
|
||||
@ExtendWith
|
||||
class Test(val x: Int)
|
||||
|
||||
fun box(): String {
|
||||
Test::class.java.newInstance()
|
||||
return "OK"
|
||||
}
|
||||
Generated
+6
@@ -37,6 +37,12 @@ public class BlackBoxCodegenTestForNoArgGenerated extends AbstractBlackBoxCodege
|
||||
runTest("plugins/noarg/testData/box/initializersWithoutInvokeInitializers.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaAnnotationWithInnerEnum.kt")
|
||||
public void testJavaAnnotationWithInnerEnum() throws Exception {
|
||||
runTest("plugins/noarg/testData/box/javaAnnotationWithInnerEnum.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt18245.kt")
|
||||
public void testKt18245() throws Exception {
|
||||
|
||||
Generated
+6
@@ -37,6 +37,12 @@ public class FirBlackBoxCodegenTestForNoArgGenerated extends AbstractFirBlackBox
|
||||
runTest("plugins/noarg/testData/box/initializersWithoutInvokeInitializers.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaAnnotationWithInnerEnum.kt")
|
||||
public void testJavaAnnotationWithInnerEnum() throws Exception {
|
||||
runTest("plugins/noarg/testData/box/javaAnnotationWithInnerEnum.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt18245.kt")
|
||||
public void testKt18245() throws Exception {
|
||||
|
||||
Generated
+6
@@ -37,6 +37,12 @@ public class IrBlackBoxCodegenTestForNoArgGenerated extends AbstractIrBlackBoxCo
|
||||
runTest("plugins/noarg/testData/box/initializersWithoutInvokeInitializers.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaAnnotationWithInnerEnum.kt")
|
||||
public void testJavaAnnotationWithInnerEnum() throws Exception {
|
||||
runTest("plugins/noarg/testData/box/javaAnnotationWithInnerEnum.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt18245.kt")
|
||||
public void testKt18245() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user