[AA-FIR] Fix handling of Java annotation parameters.
This changes FirAnnotationValueConverter to no longer rely on PSI information when projecting annotation parameter information to AA. For annotations defined in Java, including many meta-annotations, PSI information is not available for the annotation. This caused those annotation values to be projected as KtUnsupportedAnnotationValue. Instead of using PSI information, this changes FirAnnotationValueConverter to use the tree structure instead. Spread and named parameter arguments are spliced into the parameter list of their surrounding vararg calls, meaning that callers see the expected structure. (See the varargSpreadParameter.kt test file for an example.)
This commit is contained in:
committed by
Yan Zhulanow
parent
fbcde11b04
commit
212baf580c
+24
@@ -67,6 +67,12 @@ public class Fe10IdeNormalAnalysisSourceModuleAnalysisApiAnnotationsOnDeclaratio
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("emptyJavaSpreadParameter.kt")
|
||||
public void testEmptyJavaSpreadParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/emptyJavaSpreadParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("onClass.kt")
|
||||
public void testOnClass() throws Exception {
|
||||
@@ -103,11 +109,29 @@ public class Fe10IdeNormalAnalysisSourceModuleAnalysisApiAnnotationsOnDeclaratio
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/onTypeAlias.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargComplexParameter.kt")
|
||||
public void testVarargComplexParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargComplexParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargNamedParameter.kt")
|
||||
public void testVarargNamedParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargNamedParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargParameter.kt")
|
||||
public void testVarargParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargSpreadParameter.kt")
|
||||
public void testVarargSpreadParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargSpreadParameter.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
+20
-27
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.psi
|
||||
import org.jetbrains.kotlin.fir.realPsi
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirEnumEntrySymbol
|
||||
@@ -41,37 +42,26 @@ internal object FirAnnotationValueConverter {
|
||||
return KtConstantAnnotationValue(constantValue)
|
||||
}
|
||||
|
||||
private fun Collection<FirExpression>.convertConstantExpression(
|
||||
private fun Collection<FirExpression>.convertVarargsExpression(
|
||||
session: FirSession,
|
||||
): Collection<KtAnnotationValue> =
|
||||
mapNotNull { it.convertConstantExpression(session) }
|
||||
): Pair<Collection<KtAnnotationValue>, KtElement?> {
|
||||
var representativePsi: KtElement? = null
|
||||
val flattenedVarargs = buildList {
|
||||
for (expr in this@convertVarargsExpression) {
|
||||
val converted = expr.convertConstantExpression(session) ?: continue
|
||||
|
||||
// Refer to KtLightAnnotationParameterList#checkIfToArrayConversionExpected
|
||||
private fun ValueArgument?.arrayConversionExpected(): Boolean {
|
||||
return when {
|
||||
this == null -> false
|
||||
this is KtValueArgument && isSpread -> {
|
||||
// Anno(*[1,2,3])
|
||||
false
|
||||
}
|
||||
|
||||
else -> {
|
||||
// Anno(a = [1,2,3]) v.s. Anno(1) or Anno(1,2,3)
|
||||
!isNamed()
|
||||
if (expr is FirSpreadArgumentExpression || expr is FirNamedArgumentExpression) {
|
||||
addAll((converted as KtArrayAnnotationValue).values)
|
||||
} else {
|
||||
add(converted)
|
||||
}
|
||||
representativePsi = representativePsi ?: converted.sourcePsi
|
||||
}
|
||||
}
|
||||
|
||||
return flattenedVarargs to representativePsi
|
||||
}
|
||||
|
||||
private fun Collection<KtAnnotationValue>.toArrayConstantValueIfNecessary(sourcePsi: KtElement?): KtAnnotationValue? {
|
||||
val valueArgument = if (sourcePsi is ValueArgument) sourcePsi else
|
||||
(sourcePsi?.parents?.firstOrNull { it is ValueArgument } as? ValueArgument)
|
||||
val wrap = valueArgument?.arrayConversionExpected() ?: false
|
||||
return if (wrap) {
|
||||
KtArrayAnnotationValue(this, sourcePsi)
|
||||
} else {
|
||||
singleOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
fun toConstantValue(
|
||||
firExpression: FirExpression,
|
||||
@@ -94,12 +84,15 @@ internal object FirAnnotationValueConverter {
|
||||
}
|
||||
|
||||
is FirVarargArgumentsExpression -> {
|
||||
arguments.convertConstantExpression(session).toArrayConstantValueIfNecessary(sourcePsi)
|
||||
// Vararg arguments may have multiple independent expressions associated.
|
||||
// Choose one to be the representative PSI value for the entire assembled argument.
|
||||
val (annotationValues, representativePsi) = arguments.convertVarargsExpression(session)
|
||||
KtArrayAnnotationValue(annotationValues, representativePsi ?: sourcePsi)
|
||||
}
|
||||
|
||||
is FirArrayOfCall -> {
|
||||
// Desugared collection literals.
|
||||
KtArrayAnnotationValue(argumentList.arguments.convertConstantExpression(session), sourcePsi)
|
||||
KtArrayAnnotationValue(argumentList.arguments.convertVarargsExpression(session).first, sourcePsi)
|
||||
}
|
||||
|
||||
is FirFunctionCall -> {
|
||||
|
||||
+24
@@ -67,6 +67,12 @@ public class FirIdeDependentAnalysisSourceModuleAnalysisApiAnnotationsOnDeclarat
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("emptyJavaSpreadParameter.kt")
|
||||
public void testEmptyJavaSpreadParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/emptyJavaSpreadParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("onClass.kt")
|
||||
public void testOnClass() throws Exception {
|
||||
@@ -103,11 +109,29 @@ public class FirIdeDependentAnalysisSourceModuleAnalysisApiAnnotationsOnDeclarat
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/onTypeAlias.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargComplexParameter.kt")
|
||||
public void testVarargComplexParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargComplexParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargNamedParameter.kt")
|
||||
public void testVarargNamedParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargNamedParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargParameter.kt")
|
||||
public void testVarargParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargSpreadParameter.kt")
|
||||
public void testVarargSpreadParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargSpreadParameter.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
+24
@@ -67,6 +67,12 @@ public class FirIdeNormalAnalysisSourceModuleAnalysisApiAnnotationsOnDeclaration
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("emptyJavaSpreadParameter.kt")
|
||||
public void testEmptyJavaSpreadParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/emptyJavaSpreadParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("onClass.kt")
|
||||
public void testOnClass() throws Exception {
|
||||
@@ -103,11 +109,29 @@ public class FirIdeNormalAnalysisSourceModuleAnalysisApiAnnotationsOnDeclaration
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/onTypeAlias.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargComplexParameter.kt")
|
||||
public void testVarargComplexParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargComplexParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargNamedParameter.kt")
|
||||
public void testVarargNamedParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargNamedParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargParameter.kt")
|
||||
public void testVarargParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargSpreadParameter.kt")
|
||||
public void testVarargSpreadParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargSpreadParameter.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
+24
@@ -67,6 +67,12 @@ public class FirStandaloneNormalAnalysisSourceModuleAnalysisApiAnnotationsOnDecl
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("emptyJavaSpreadParameter.kt")
|
||||
public void testEmptyJavaSpreadParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/emptyJavaSpreadParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("onClass.kt")
|
||||
public void testOnClass() throws Exception {
|
||||
@@ -103,11 +109,29 @@ public class FirStandaloneNormalAnalysisSourceModuleAnalysisApiAnnotationsOnDecl
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/onTypeAlias.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargComplexParameter.kt")
|
||||
public void testVarargComplexParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargComplexParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargNamedParameter.kt")
|
||||
public void testVarargNamedParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargNamedParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargParameter.kt")
|
||||
public void testVarargParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargSpreadParameter.kt")
|
||||
public void testVarargSpreadParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargSpreadParameter.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// FILE: A.java
|
||||
public @interface A {
|
||||
String[] value() default {"foo", "bar"};
|
||||
}
|
||||
|
||||
// FILE: Test.kt
|
||||
annotation class B(vararg val a: A)
|
||||
|
||||
@B(A(), A(*[]))
|
||||
class <caret>Foo
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
KtDeclaration: KtClass Foo
|
||||
annotations: [
|
||||
B(a = [/A, /A(value = [], )])
|
||||
psi: KtAnnotationEntry
|
||||
]
|
||||
analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargComplexParameter.kt
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
annotation class A(vararg val strings: String)
|
||||
annotation class AArray(vararg val value: A)
|
||||
|
||||
@AArray(A(strings = ["foo", "bar"]))
|
||||
class F<caret>oo
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
KtDeclaration: KtClass Foo
|
||||
annotations: [
|
||||
AArray(value = [/A(strings = ["foo", "bar"], )])
|
||||
psi: KtAnnotationEntry
|
||||
]
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
annotation class A(vararg val strings: String)
|
||||
|
||||
@A(strings = ["foo", "bar"])
|
||||
class F<caret>oo
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
KtDeclaration: KtClass Foo
|
||||
annotations: [
|
||||
A(strings = ["foo", "bar"])
|
||||
psi: KtAnnotationEntry
|
||||
]
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
KtDeclaration: KtClass Foo
|
||||
annotations: [
|
||||
A(strings = [["foo", "bar"], "baz", ["quux"]])
|
||||
psi: KtAnnotationEntry
|
||||
]
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
annotation class A(vararg val strings: String)
|
||||
|
||||
@A(*arrayOf("foo", "bar"), "baz", *["quux"])
|
||||
class F<caret>oo
|
||||
analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargSpreadParameter.txt
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
KtDeclaration: KtClass Foo
|
||||
annotations: [
|
||||
A(strings = ["foo", "bar", "baz", "quux"])
|
||||
psi: KtAnnotationEntry
|
||||
]
|
||||
+1
-1
@@ -3,7 +3,7 @@ annotations: [
|
||||
JavaAnno(value = [java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD])
|
||||
psi: KtAnnotationEntry
|
||||
annotations: [
|
||||
kotlin/annotation/Target(allowedTargets = error("non-annotation value"))
|
||||
kotlin/annotation/Target(allowedTargets = [kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER])
|
||||
psi: null
|
||||
annotations: [
|
||||
kotlin/annotation/Target(allowedTargets = [kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS])
|
||||
|
||||
Reference in New Issue
Block a user