[FIR] Set targets of annotation classes in FirJavaElementFinder
#KT-60504 Fixed
This commit is contained in:
committed by
Space Team
parent
daa02813c2
commit
81517a3d29
+5
@@ -29,6 +29,11 @@ public class FirOldFrontendLightClassesTestGenerated extends AbstractFirOldFront
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/lightClasses"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("annotationTargets.kt")
|
||||
public void testAnnotationTargets() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/lightClasses/annotationTargets.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("genericClasses.kt")
|
||||
public void testGenericClasses() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/lightClasses/genericClasses.kt");
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
annotation class A1
|
||||
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
annotation class A2
|
||||
|
||||
@Target(AnnotationTarget.ANNOTATION_CLASS)
|
||||
annotation class A3
|
||||
|
||||
@Target(AnnotationTarget.TYPE_PARAMETER)
|
||||
annotation class A4
|
||||
|
||||
@Target(AnnotationTarget.PROPERTY)
|
||||
annotation class A5
|
||||
|
||||
@Target(AnnotationTarget.FIELD)
|
||||
annotation class A6
|
||||
|
||||
@Target(AnnotationTarget.LOCAL_VARIABLE)
|
||||
annotation class A7
|
||||
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER)
|
||||
annotation class A8
|
||||
|
||||
@Target(AnnotationTarget.CONSTRUCTOR)
|
||||
annotation class A9
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
annotation class A10
|
||||
|
||||
@Target(AnnotationTarget.PROPERTY_GETTER)
|
||||
annotation class A11
|
||||
|
||||
@Target(AnnotationTarget.PROPERTY_SETTER)
|
||||
annotation class A12
|
||||
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
annotation class A13
|
||||
|
||||
@Target(AnnotationTarget.EXPRESSION)
|
||||
annotation class A14
|
||||
|
||||
@Target(AnnotationTarget.FILE)
|
||||
annotation class A15
|
||||
|
||||
@Target(AnnotationTarget.TYPEALIAS)
|
||||
annotation class A16
|
||||
|
||||
// LIGHT_CLASS_FQ_NAME: A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16
|
||||
@@ -0,0 +1,47 @@
|
||||
public final @interface A1 implements java.lang.annotation.Annotation {
|
||||
}
|
||||
@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE})
|
||||
public final @interface A2 implements java.lang.annotation.Annotation {
|
||||
}
|
||||
@java.lang.annotation.Target({java.lang.annotation.ElementType.ANNOTATION_TYPE})
|
||||
public final @interface A3 implements java.lang.annotation.Annotation {
|
||||
}
|
||||
@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE_PARAMETER})
|
||||
public final @interface A4 implements java.lang.annotation.Annotation {
|
||||
}
|
||||
@java.lang.annotation.Target({})
|
||||
public final @interface A5 implements java.lang.annotation.Annotation {
|
||||
}
|
||||
@java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD})
|
||||
public final @interface A6 implements java.lang.annotation.Annotation {
|
||||
}
|
||||
@java.lang.annotation.Target({java.lang.annotation.ElementType.LOCAL_VARIABLE})
|
||||
public final @interface A7 implements java.lang.annotation.Annotation {
|
||||
}
|
||||
@java.lang.annotation.Target({java.lang.annotation.ElementType.PARAMETER})
|
||||
public final @interface A8 implements java.lang.annotation.Annotation {
|
||||
}
|
||||
@java.lang.annotation.Target({java.lang.annotation.ElementType.CONSTRUCTOR})
|
||||
public final @interface A9 implements java.lang.annotation.Annotation {
|
||||
}
|
||||
@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
|
||||
public final @interface A10 implements java.lang.annotation.Annotation {
|
||||
}
|
||||
@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
|
||||
public final @interface A11 implements java.lang.annotation.Annotation {
|
||||
}
|
||||
@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
|
||||
public final @interface A12 implements java.lang.annotation.Annotation {
|
||||
}
|
||||
@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE_USE})
|
||||
public final @interface A13 implements java.lang.annotation.Annotation {
|
||||
}
|
||||
@java.lang.annotation.Target({})
|
||||
public final @interface A14 implements java.lang.annotation.Annotation {
|
||||
}
|
||||
@java.lang.annotation.Target({})
|
||||
public final @interface A15 implements java.lang.annotation.Annotation {
|
||||
}
|
||||
@java.lang.annotation.Target({})
|
||||
public final @interface A16 implements java.lang.annotation.Annotation {
|
||||
}
|
||||
@@ -27,11 +27,13 @@ import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.FirModuleData
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.FirSessionComponent
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getTargetAnnotation
|
||||
import org.jetbrains.kotlin.fir.caches.FirCache
|
||||
import org.jetbrains.kotlin.fir.caches.firCachesFactory
|
||||
import org.jetbrains.kotlin.fir.caches.getValue
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||
import org.jetbrains.kotlin.fir.moduleData
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
@@ -44,12 +46,14 @@ import org.jetbrains.kotlin.fir.resolve.transformers.SupertypeComputationSession
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.utils.exceptions.withConeTypeEntry
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.NotEvaluatedConstAware
|
||||
import org.jetbrains.kotlin.name.*
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import org.jetbrains.kotlin.resolve.jvm.KotlinFinderMarker
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
||||
import org.jetbrains.kotlin.utils.KOTLIN_TO_JAVA_ANNOTATION_TARGETS
|
||||
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
|
||||
|
||||
val FirSession.javaElementFinder: FirJavaElementFinder? by FirSession.nullableSessionComponentAccessor<FirJavaElementFinder>()
|
||||
@@ -166,7 +170,20 @@ class FirJavaElementFinder(
|
||||
buildFieldStubForConst(it, stub)
|
||||
}
|
||||
|
||||
PsiModifierListStubImpl(stub, firClass.packFlags())
|
||||
val modifierListStub = PsiModifierListStubImpl(stub, firClass.packFlags())
|
||||
|
||||
if (firClass.classKind == ClassKind.ANNOTATION_CLASS) {
|
||||
val targets = firClass.getTargetAnnotation(session)?.findTargets()
|
||||
if (targets != null) {
|
||||
val annotationString = buildString {
|
||||
append("@${JvmAnnotationNames.TARGET_ANNOTATION}({")
|
||||
targets.mapNotNull { KOTLIN_TO_JAVA_ANNOTATION_TARGETS[it] }
|
||||
.joinTo(this) { "${JvmAnnotationNames.ELEMENT_TYPE_ENUM}.$it" }
|
||||
append("})")
|
||||
}
|
||||
PsiAnnotationStubImpl(modifierListStub, annotationString)
|
||||
}
|
||||
}
|
||||
|
||||
newTypeParameterList(
|
||||
stub,
|
||||
@@ -187,6 +204,10 @@ class FirJavaElementFinder(
|
||||
return stub
|
||||
}
|
||||
|
||||
private fun FirAnnotation.findTargets(): List<String> = buildList {
|
||||
forEachAnnotationTarget { add(it.identifier) }
|
||||
}
|
||||
|
||||
private fun buildFieldStubForConst(firProperty: FirProperty, classStub: PsiClassStubImpl<ClsClassImpl>) {
|
||||
if (!firProperty.isConst) return
|
||||
|
||||
|
||||
+13
-7
@@ -78,22 +78,28 @@ fun FirAnnotation.useSiteTargetsFromMetaAnnotation(session: FirSession): Set<Ann
|
||||
}
|
||||
|
||||
private fun FirAnnotation.findUseSiteTargets(): Set<AnnotationUseSiteTarget> = buildSet {
|
||||
fun addIfMatching(arg: FirExpression) {
|
||||
if (arg !is FirQualifiedAccessExpression) return
|
||||
val callableSymbol = arg.calleeReference.toResolvedCallableSymbol() ?: return
|
||||
forEachAnnotationTarget {
|
||||
USE_SITE_TARGET_NAME_MAP[it.identifier]?.let { addAll(it) }
|
||||
}
|
||||
}
|
||||
|
||||
fun FirAnnotation.forEachAnnotationTarget(action: (Name) -> Unit) {
|
||||
fun take(arg: FirExpression) {
|
||||
if (arg !is FirQualifiedAccessExpression) return@take
|
||||
val callableSymbol = arg.calleeReference.toResolvedCallableSymbol() ?: return@take
|
||||
if (callableSymbol.containingClassLookupTag()?.classId == StandardClassIds.AnnotationTarget) {
|
||||
USE_SITE_TARGET_NAME_MAP[callableSymbol.callableId.callableName.identifier]?.let { addAll(it) }
|
||||
action(callableSymbol.callableId.callableName)
|
||||
}
|
||||
}
|
||||
|
||||
if (this@findUseSiteTargets is FirAnnotationCall) {
|
||||
if (this is FirAnnotationCall) {
|
||||
for (arg in argumentList.arguments) {
|
||||
arg.unwrapAndFlattenArgument(flattenArrays = true).forEach(::addIfMatching)
|
||||
arg.unwrapAndFlattenArgument(flattenArrays = true).forEach(::take)
|
||||
}
|
||||
} else {
|
||||
argumentMapping.mapping[StandardClassIds.Annotations.ParameterNames.targetAllowedTargets]
|
||||
?.unwrapAndFlattenArgument(flattenArrays = true)
|
||||
?.forEach(::addIfMatching)
|
||||
?.forEach(::take)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.utils
|
||||
|
||||
import java.lang.annotation.ElementType
|
||||
|
||||
val KOTLIN_TO_JAVA_ANNOTATION_TARGETS: Map<String, String> = mapOf(
|
||||
AnnotationTarget.CLASS.name to ElementType.TYPE.name,
|
||||
AnnotationTarget.ANNOTATION_CLASS.name to ElementType.ANNOTATION_TYPE.name,
|
||||
AnnotationTarget.FIELD.name to ElementType.FIELD.name,
|
||||
AnnotationTarget.LOCAL_VARIABLE.name to ElementType.LOCAL_VARIABLE.name,
|
||||
AnnotationTarget.VALUE_PARAMETER.name to ElementType.PARAMETER.name,
|
||||
AnnotationTarget.CONSTRUCTOR.name to ElementType.CONSTRUCTOR.name,
|
||||
AnnotationTarget.FUNCTION.name to ElementType.METHOD.name,
|
||||
AnnotationTarget.PROPERTY_GETTER.name to ElementType.METHOD.name,
|
||||
AnnotationTarget.PROPERTY_SETTER.name to ElementType.METHOD.name,
|
||||
AnnotationTarget.TYPE_PARAMETER.name to ElementType.TYPE_PARAMETER.name,
|
||||
AnnotationTarget.TYPE.name to ElementType.TYPE_USE.name,
|
||||
)
|
||||
+4
-13
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||
import org.jetbrains.kotlin.resolve.constants.KClassValue
|
||||
import org.jetbrains.kotlin.utils.KOTLIN_TO_JAVA_ANNOTATION_TARGETS
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
internal const val KOTLIN_JVM_INTERNAL_REPEATABLE_CONTAINER = "kotlin.jvm.internal.RepeatableContainer"
|
||||
@@ -55,19 +56,9 @@ private fun PsiAnnotation.extractArrayAnnotationFqNames(attributeName: String):
|
||||
|
||||
private val targetMapping = run {
|
||||
val javaAnnotationElementTypeId = ClassId.fromString(JvmAnnotationNames.ELEMENT_TYPE_ENUM.asString())
|
||||
hashMapOf(
|
||||
"kotlin.annotation.AnnotationTarget.CLASS" to EnumValue(javaAnnotationElementTypeId, Name.identifier("TYPE")),
|
||||
"kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS" to EnumValue(javaAnnotationElementTypeId, Name.identifier("ANNOTATION_TYPE")),
|
||||
"kotlin.annotation.AnnotationTarget.FIELD" to EnumValue(javaAnnotationElementTypeId, Name.identifier("FIELD")),
|
||||
"kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE" to EnumValue(javaAnnotationElementTypeId, Name.identifier("LOCAL_VARIABLE")),
|
||||
"kotlin.annotation.AnnotationTarget.VALUE_PARAMETER" to EnumValue(javaAnnotationElementTypeId, Name.identifier("PARAMETER")),
|
||||
"kotlin.annotation.AnnotationTarget.CONSTRUCTOR" to EnumValue(javaAnnotationElementTypeId, Name.identifier("CONSTRUCTOR")),
|
||||
"kotlin.annotation.AnnotationTarget.FUNCTION" to EnumValue(javaAnnotationElementTypeId, Name.identifier("METHOD")),
|
||||
"kotlin.annotation.AnnotationTarget.PROPERTY_GETTER" to EnumValue(javaAnnotationElementTypeId, Name.identifier("METHOD")),
|
||||
"kotlin.annotation.AnnotationTarget.PROPERTY_SETTER" to EnumValue(javaAnnotationElementTypeId, Name.identifier("METHOD")),
|
||||
"kotlin.annotation.AnnotationTarget.TYPE_PARAMETER" to EnumValue(javaAnnotationElementTypeId, Name.identifier("TYPE_PARAMETER")),
|
||||
"kotlin.annotation.AnnotationTarget.TYPE" to EnumValue(javaAnnotationElementTypeId, Name.identifier("TYPE_USE")),
|
||||
)
|
||||
KOTLIN_TO_JAVA_ANNOTATION_TARGETS.entries.associate { (key, value) ->
|
||||
"kotlin.annotation.AnnotationTarget.$key" to EnumValue(javaAnnotationElementTypeId, Name.identifier(value))
|
||||
}
|
||||
}
|
||||
|
||||
internal fun PsiAnnotation.tryConvertAsTarget(): KtLightAbstractAnnotation? {
|
||||
|
||||
Vendored
+1
-1
@@ -27,7 +27,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
annotation class An
|
||||
|
||||
class B : A {
|
||||
override fun foo(): <!RETURN_TYPE_MISMATCH_ON_OVERRIDE("foo; @NotNull() @An() @MyTypeQualifier() fun foo(): @EnhancedNullability String")!>String?<!> = null
|
||||
override fun foo(): <!RETURN_TYPE_MISMATCH_ON_OVERRIDE("foo; @NotNull() @An() @MyTypeQualifier() fun foo(): @EnhancedNullability @R|An|() String")!>String?<!> = null
|
||||
}
|
||||
|
||||
@An
|
||||
|
||||
Vendored
-45
@@ -1,45 +0,0 @@
|
||||
// LL_FIR_DIVERGENCE
|
||||
// KT-60504
|
||||
// LL_FIR_DIVERGENCE
|
||||
// !RENDER_DIAGNOSTICS_MESSAGES
|
||||
// SKIP_JAVAC
|
||||
|
||||
// FILE: A.java
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@javax.annotation.meta.TypeQualifier
|
||||
public @interface MyTypeQualifier {}
|
||||
|
||||
@An
|
||||
public interface A {
|
||||
@NotNull
|
||||
@An
|
||||
@MyTypeQualifier
|
||||
String foo();
|
||||
}
|
||||
|
||||
// FILE: k.kt
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER)
|
||||
annotation class An
|
||||
|
||||
class B : A {
|
||||
override fun foo(): <!RETURN_TYPE_MISMATCH_ON_OVERRIDE("foo; @NotNull() @An() @MyTypeQualifier() fun foo(): @EnhancedNullability @R|An|() String")!>String?<!> = null
|
||||
}
|
||||
|
||||
@An
|
||||
public interface C {
|
||||
@NotNull
|
||||
@An
|
||||
fun foo(): String
|
||||
}
|
||||
|
||||
class D : C {
|
||||
override fun foo(): <!RETURN_TYPE_MISMATCH_ON_OVERRIDE("foo; @NotNull() @An() fun foo(): String")!>String?<!> = null
|
||||
}
|
||||
Reference in New Issue
Block a user