diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/annotations/firAnnotationUtils.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/annotations/firAnnotationUtils.kt index ea747fddfbc..e2072ef60cc 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/annotations/firAnnotationUtils.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/annotations/firAnnotationUtils.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.analysis.api.fir.annotations +import java.lang.annotation.ElementType import org.jetbrains.kotlin.analysis.api.annotations.AnnotationUseSiteTargetFilter import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationInfo import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationWithArgumentsInfo @@ -68,6 +69,11 @@ internal fun annotationsByClassId( .mapIndexedToAnnotationApplication(useSiteTargetFilter, useSiteSession, classId) { index, annotation -> annotation.asKtAnnotationApplicationForTargetAnnotation(useSiteSession, index) } + } else if (classId == StandardClassIds.Annotations.Java.Target && firSymbol.fir.resolvePhase < FirResolvePhase.ANNOTATIONS_ARGUMENTS_MAPPING) { + annotationContainer.resolvedAnnotationsWithClassIds(firSymbol) + .mapIndexedToAnnotationApplication(useSiteTargetFilter, useSiteSession, classId) { index, annotation -> + annotation.asKtAnnotationApplicationForJavaTargetAnnotation(useSiteSession, index) + } } else { annotationContainer.resolvedAnnotationsWithArguments(firSymbol) .mapIndexedToAnnotationApplication(useSiteTargetFilter, useSiteSession, classId) { index, annotation -> @@ -88,20 +94,26 @@ private inline fun List.mapIndexedToAnnotationApplication( transformer(index, annotation) } -private fun FirAnnotation.asKtAnnotationApplicationForTargetAnnotation( +private fun FirAnnotation.asKtAnnotationApplicationForAnnotationWithEnumArgument( useSiteSession: FirSession, index: Int, + expectedEnumClassId: ClassId, + annotationParameterName: Name, + nameMapper: (String) -> String?, ): KtAnnotationApplicationWithArgumentsInfo { - val arguments = findAllowedTargets().ifNotEmpty { + val arguments = findFromRawArguments( + expectedEnumClass = expectedEnumClassId, + nameMapper, + ).ifNotEmpty { listOf( KtNamedAnnotationValue( - name = StandardClassIds.Annotations.ParameterNames.targetAllowedTargets, + name = annotationParameterName, expression = KtArrayAnnotationValue( values = map { KtEnumEntryAnnotationValue( callableId = CallableId( - classId = StandardClassIds.AnnotationTarget, - callableName = Name.identifier(it.name), + classId = expectedEnumClassId, + callableName = Name.identifier(it), ), sourcePsi = null, ) @@ -115,16 +127,38 @@ private fun FirAnnotation.asKtAnnotationApplicationForTargetAnnotation( return toKtAnnotationApplication(useSiteSession, index, arguments) } -private fun FirAnnotation.findAllowedTargets(): Set = buildSet { +private fun FirAnnotation.asKtAnnotationApplicationForTargetAnnotation( + useSiteSession: FirSession, + index: Int, +): KtAnnotationApplicationWithArgumentsInfo = asKtAnnotationApplicationForAnnotationWithEnumArgument( + useSiteSession = useSiteSession, + index = index, + expectedEnumClassId = StandardClassIds.AnnotationTarget, + annotationParameterName = StandardClassIds.Annotations.ParameterNames.targetAllowedTargets, + nameMapper = { KotlinTarget.valueOrNull(it)?.name }, +) + +private fun FirAnnotation.asKtAnnotationApplicationForJavaTargetAnnotation( + useSiteSession: FirSession, + index: Int, +): KtAnnotationApplicationWithArgumentsInfo = asKtAnnotationApplicationForAnnotationWithEnumArgument( + useSiteSession = useSiteSession, + index = index, + expectedEnumClassId = StandardClassIds.Annotations.Java.ElementType, + annotationParameterName = StandardClassIds.Annotations.ParameterNames.value, + nameMapper = { ElementType.values().firstOrNull { enumValue -> enumValue.name == it }?.name }, +) + +private fun FirAnnotation.findFromRawArguments(expectedEnumClass: ClassId, transformer: (String) -> T?): Set = buildSet { fun addIfMatching(arg: FirExpression) { if (arg !is FirQualifiedAccessExpression) return val callableSymbol = arg.calleeReference.toResolvedCallableSymbol() ?: return - if (callableSymbol.containingClassLookupTag()?.classId != StandardClassIds.AnnotationTarget) return + if (callableSymbol.containingClassLookupTag()?.classId != expectedEnumClass) return val identifier = callableSymbol.callableId.callableName.identifier - KotlinTarget.values().firstOrNull { identifier == it.name }?.let(::add) + transformer(identifier)?.let(::add) } - if (this@findAllowedTargets is FirAnnotationCall) { + if (this@findFromRawArguments is FirAnnotationCall) { for (arg in argumentList.arguments) { arg.unwrapAndFlattenArgument().forEach(::addIfMatching) } diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/annotationFromImplicitJavaTypeWithJavaAnnotation.kt b/analysis/low-level-api-fir/testdata/lazyResolve/annotationFromImplicitJavaTypeWithJavaAnnotation.kt new file mode 100644 index 00000000000..47022576829 --- /dev/null +++ b/analysis/low-level-api-fir/testdata/lazyResolve/annotationFromImplicitJavaTypeWithJavaAnnotation.kt @@ -0,0 +1,18 @@ +// SKIP_WHEN_OUT_OF_CONTENT_ROOT +// DISABLE_SEALED_INHERITOR_CALCULATOR +// FILE: main.kt +fun resolveMe(i: JavaInterface) = i.id + +// FILE: JavaClass.java +public interface JavaInterface { + @KotlinAnnotation + default int getId() { + return -1; + } +} + +// FILE: KotlinAnnotation.kt +import java.lang.annotation.ElementType + +@java.lang.annotation.Target(ElementType.TYPE_USE) +annotation class KotlinAnnotation \ No newline at end of file diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/annotationFromImplicitJavaTypeWithJavaAnnotation.txt b/analysis/low-level-api-fir/testdata/lazyResolve/annotationFromImplicitJavaTypeWithJavaAnnotation.txt new file mode 100644 index 00000000000..8708f0e0913 --- /dev/null +++ b/analysis/low-level-api-fir/testdata/lazyResolve/annotationFromImplicitJavaTypeWithJavaAnnotation.txt @@ -0,0 +1,79 @@ +RAW_FIR: +FILE: [ResolvedTo(RAW_FIR)] main.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(RAW_FIR)] fun resolveMe([ResolvedTo(RAW_FIR)] i: JavaInterface): { LAZY_BLOCK } + +IMPORTS: +FILE: [ResolvedTo(IMPORTS)] main.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(RAW_FIR)] fun resolveMe([ResolvedTo(RAW_FIR)] i: JavaInterface): { LAZY_BLOCK } + +COMPILER_REQUIRED_ANNOTATIONS: +FILE: [ResolvedTo(IMPORTS)] main.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(COMPILER_REQUIRED_ANNOTATIONS)] fun resolveMe([ResolvedTo(COMPILER_REQUIRED_ANNOTATIONS)] i: JavaInterface): { LAZY_BLOCK } + +COMPANION_GENERATION: +FILE: [ResolvedTo(IMPORTS)] main.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(COMPANION_GENERATION)] fun resolveMe([ResolvedTo(COMPANION_GENERATION)] i: JavaInterface): { LAZY_BLOCK } + +SUPER_TYPES: +FILE: [ResolvedTo(IMPORTS)] main.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] fun resolveMe([ResolvedTo(SUPER_TYPES)] i: JavaInterface): { LAZY_BLOCK } + +TYPES: +FILE: [ResolvedTo(IMPORTS)] main.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(TYPES)] fun resolveMe([ResolvedTo(TYPES)] i: R|JavaInterface|): { LAZY_BLOCK } + +STATUS: +FILE: [ResolvedTo(IMPORTS)] main.kt + [ResolvedTo(RAW_FIR)] annotations container + public final [ResolvedTo(STATUS)] fun resolveMe([ResolvedTo(STATUS)] i: R|JavaInterface|): { LAZY_BLOCK } + +EXPECT_ACTUAL_MATCHING: +FILE: [ResolvedTo(IMPORTS)] main.kt + [ResolvedTo(RAW_FIR)] annotations container + public final [ResolvedTo(EXPECT_ACTUAL_MATCHING)] fun resolveMe([ResolvedTo(EXPECT_ACTUAL_MATCHING)] i: R|JavaInterface|): { LAZY_BLOCK } + +ARGUMENTS_OF_ANNOTATIONS: +FILE: [ResolvedTo(IMPORTS)] main.kt + [ResolvedTo(RAW_FIR)] annotations container + public final [ResolvedTo(ARGUMENTS_OF_ANNOTATIONS)] fun resolveMe([ResolvedTo(ARGUMENTS_OF_ANNOTATIONS)] i: R|JavaInterface|): { LAZY_BLOCK } + +CONTRACTS: +FILE: [ResolvedTo(IMPORTS)] main.kt + [ResolvedTo(RAW_FIR)] annotations container + public final [ResolvedTo(CONTRACTS)] fun resolveMe([ResolvedTo(CONTRACTS)] i: R|JavaInterface|): { + ^resolveMe i#.id# + } + +IMPLICIT_TYPES_BODY_RESOLVE: +FILE: [ResolvedTo(IMPORTS)] main.kt + [ResolvedTo(RAW_FIR)] annotations container + public final [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] fun resolveMe([ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] i: R|JavaInterface|): R|kotlin/Int| { + ^resolveMe R|/i|.R|/JavaInterface.id| + } + +ANNOTATIONS_ARGUMENTS_MAPPING: +FILE: [ResolvedTo(IMPORTS)] main.kt + [ResolvedTo(RAW_FIR)] annotations container + public final [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] fun resolveMe([ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] i: R|JavaInterface|): R|kotlin/Int| { + ^resolveMe R|/i|.R|/JavaInterface.id| + } + +BODY_RESOLVE: +FILE: [ResolvedTo(IMPORTS)] main.kt + [ResolvedTo(RAW_FIR)] annotations container + public final [ResolvedTo(BODY_RESOLVE)] fun resolveMe([ResolvedTo(BODY_RESOLVE)] i: R|JavaInterface|): R|kotlin/Int| { + ^resolveMe R|/i|.R|/JavaInterface.id| + } + +FILE RAW TO BODY: +FILE: [ResolvedTo(IMPORTS)] main.kt + [ResolvedTo(BODY_RESOLVE)] annotations container + public final [ResolvedTo(BODY_RESOLVE)] fun resolveMe([ResolvedTo(BODY_RESOLVE)] i: R|JavaInterface|): R|kotlin/Int| { + ^resolveMe R|/i|.R|/JavaInterface.id| + } diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirOutOfContentRootLazyDeclarationResolveTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirOutOfContentRootLazyDeclarationResolveTestGenerated.java index f8f25eea843..1a06f723994 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirOutOfContentRootLazyDeclarationResolveTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirOutOfContentRootLazyDeclarationResolveTestGenerated.java @@ -36,6 +36,12 @@ public class FirOutOfContentRootLazyDeclarationResolveTestGenerated extends Abst runTest("analysis/low-level-api-fir/testdata/lazyResolve/annotationFromImplicitJavaType.kt"); } + @Test + @TestMetadata("annotationFromImplicitJavaTypeWithJavaAnnotation.kt") + public void testAnnotationFromImplicitJavaTypeWithJavaAnnotation() throws Exception { + runTest("analysis/low-level-api-fir/testdata/lazyResolve/annotationFromImplicitJavaTypeWithJavaAnnotation.kt"); + } + @Test @TestMetadata("annotationParameters.kt") public void testAnnotationParameters() throws Exception { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirSourceLazyDeclarationResolveTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirSourceLazyDeclarationResolveTestGenerated.java index 6de3c286cd4..324a7c7c77b 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirSourceLazyDeclarationResolveTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirSourceLazyDeclarationResolveTestGenerated.java @@ -36,6 +36,12 @@ public class FirSourceLazyDeclarationResolveTestGenerated extends AbstractFirSou runTest("analysis/low-level-api-fir/testdata/lazyResolve/annotationFromImplicitJavaType.kt"); } + @Test + @TestMetadata("annotationFromImplicitJavaTypeWithJavaAnnotation.kt") + public void testAnnotationFromImplicitJavaTypeWithJavaAnnotation() throws Exception { + runTest("analysis/low-level-api-fir/testdata/lazyResolve/annotationFromImplicitJavaTypeWithJavaAnnotation.kt"); + } + @Test @TestMetadata("annotationParameters.kt") public void testAnnotationParameters() throws Exception {