[FIR] Set targets of annotation classes in FirJavaElementFinder

#KT-60504 Fixed
This commit is contained in:
Kirill Rakhman
2023-11-29 10:01:54 +01:00
committed by Space Team
parent daa02813c2
commit 81517a3d29
9 changed files with 162 additions and 67 deletions
@@ -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
@@ -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)
}
}
@@ -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,
)
@@ -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? {
@@ -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
@@ -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
}