From 81517a3d29df4254eeb9a09501b2e269fb56d05a Mon Sep 17 00:00:00 2001 From: Kirill Rakhman Date: Wed, 29 Nov 2023 10:01:54 +0100 Subject: [PATCH] [FIR] Set targets of annotation classes in FirJavaElementFinder #KT-60504 Fixed --- ...rOldFrontendLightClassesTestGenerated.java | 5 ++ .../lightClasses/annotationTargets.kt | 48 +++++++++++++++++++ .../lightClasses/annotationTargets.txt | 47 ++++++++++++++++++ .../kotlin/fir/java/FirJavaElementFinder.kt | 23 ++++++++- .../fir/declarations/FirAnnotationUtils.kt | 20 +++++--- .../utils/kotlinToJavaAnnotationTargets.kt | 22 +++++++++ .../elements/KtToJvmAnnotationsConverter.kt | 17 ++----- .../typeMismatchOnOverrideJavaNullable.fir.kt | 2 +- .../typeMismatchOnOverrideJavaNullable.ll.kt | 45 ----------------- 9 files changed, 162 insertions(+), 67 deletions(-) create mode 100644 compiler/fir/analysis-tests/testData/lightClasses/annotationTargets.kt create mode 100644 compiler/fir/analysis-tests/testData/lightClasses/annotationTargets.txt create mode 100644 compiler/frontend.common.jvm/src/org/jetbrains/kotlin/utils/kotlinToJavaAnnotationTargets.kt delete mode 100644 compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchOnOverrideJavaNullable.ll.kt diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/java/FirOldFrontendLightClassesTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/java/FirOldFrontendLightClassesTestGenerated.java index cf4883c70a0..5de066ef1eb 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/java/FirOldFrontendLightClassesTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/java/FirOldFrontendLightClassesTestGenerated.java @@ -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"); diff --git a/compiler/fir/analysis-tests/testData/lightClasses/annotationTargets.kt b/compiler/fir/analysis-tests/testData/lightClasses/annotationTargets.kt new file mode 100644 index 00000000000..487f4644500 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/lightClasses/annotationTargets.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 \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/lightClasses/annotationTargets.txt b/compiler/fir/analysis-tests/testData/lightClasses/annotationTargets.txt new file mode 100644 index 00000000000..f5c7b68fc3c --- /dev/null +++ b/compiler/fir/analysis-tests/testData/lightClasses/annotationTargets.txt @@ -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 { +} diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt index 91bb5d733d9..d1986b39c4d 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt @@ -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() @@ -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 = buildList { + forEachAnnotationTarget { add(it.identifier) } + } + private fun buildFieldStubForConst(firProperty: FirProperty, classStub: PsiClassStubImpl) { if (!firProperty.isConst) return diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/FirAnnotationUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/FirAnnotationUtils.kt index 583c937c543..3f88ab0073b 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/FirAnnotationUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/FirAnnotationUtils.kt @@ -78,22 +78,28 @@ fun FirAnnotation.useSiteTargetsFromMetaAnnotation(session: FirSession): Set = 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) } } diff --git a/compiler/frontend.common.jvm/src/org/jetbrains/kotlin/utils/kotlinToJavaAnnotationTargets.kt b/compiler/frontend.common.jvm/src/org/jetbrains/kotlin/utils/kotlinToJavaAnnotationTargets.kt new file mode 100644 index 00000000000..8a46ecc6589 --- /dev/null +++ b/compiler/frontend.common.jvm/src/org/jetbrains/kotlin/utils/kotlinToJavaAnnotationTargets.kt @@ -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 = 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, +) \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtToJvmAnnotationsConverter.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtToJvmAnnotationsConverter.kt index 51f67efb337..e9b6515b358 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtToJvmAnnotationsConverter.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtToJvmAnnotationsConverter.kt @@ -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? { diff --git a/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchOnOverrideJavaNullable.fir.kt b/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchOnOverrideJavaNullable.fir.kt index b0ca546837b..694dccc4fe1 100644 --- a/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchOnOverrideJavaNullable.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchOnOverrideJavaNullable.fir.kt @@ -27,7 +27,7 @@ import org.jetbrains.annotations.NotNull; annotation class An class B : A { - override fun foo(): String? = null + override fun foo(): String? = null } @An diff --git a/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchOnOverrideJavaNullable.ll.kt b/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchOnOverrideJavaNullable.ll.kt deleted file mode 100644 index f9edc4e8487..00000000000 --- a/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchOnOverrideJavaNullable.ll.kt +++ /dev/null @@ -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(): String? = null -} - -@An -public interface C { - @NotNull - @An - fun foo(): String -} - -class D : C { - override fun foo(): String? = null -}