FIR IDE: handle annotation array values properly
This commit is contained in:
committed by
Ilya Kirillov
parent
ffd0a5ed14
commit
414881403b
+37
-16
@@ -11,13 +11,13 @@ import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.realPsi
|
||||
import org.jetbrains.kotlin.fir.psi
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirEnumEntrySymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.psi.KtCallElement
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.resolve.ArrayFqNames
|
||||
|
||||
internal object KtFirConstantValueConverter {
|
||||
@@ -39,18 +39,37 @@ internal object KtFirConstantValueConverter {
|
||||
firConstExpression.convertConstantExpression()
|
||||
|
||||
private fun <T> FirConstExpression<T>.convertConstantExpression(): KtLiteralConstantValue<T> =
|
||||
KtLiteralConstantValue(kind, value, realPsi as? KtElement)
|
||||
KtLiteralConstantValue(kind, value, psi as? KtElement)
|
||||
|
||||
private fun Collection<FirExpression>.convertConstantExpression(
|
||||
session: FirSession,
|
||||
): Collection<KtConstantValue> =
|
||||
mapNotNull { it.convertConstantExpression(session) }
|
||||
|
||||
private fun Collection<KtConstantValue>.toArrayConstantValueIfNecessary(kotlinOrigin: KtElement?): KtConstantValue {
|
||||
return if (size == 1)
|
||||
single()
|
||||
else
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Collection<KtConstantValue>.toArrayConstantValueIfNecessary(kotlinOrigin: KtElement?): KtConstantValue? {
|
||||
val valueArgument = if (kotlinOrigin is ValueArgument) kotlinOrigin else
|
||||
(kotlinOrigin?.parents?.firstOrNull { it is ValueArgument } as? ValueArgument)
|
||||
val wrap = valueArgument?.arrayConversionExpected() ?: false
|
||||
return if (wrap) {
|
||||
KtArrayConstantValue(this, kotlinOrigin)
|
||||
} else {
|
||||
singleOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
fun toConstantValue(
|
||||
@@ -67,13 +86,15 @@ internal object KtFirConstantValueConverter {
|
||||
is FirNamedArgumentExpression -> {
|
||||
expression.convertConstantExpression(session)
|
||||
}
|
||||
is FirSpreadArgumentExpression -> {
|
||||
expression.convertConstantExpression(session)
|
||||
}
|
||||
is FirVarargArgumentsExpression -> {
|
||||
arguments.convertConstantExpression(session)
|
||||
.toArrayConstantValueIfNecessary(realPsi as? KtElement)
|
||||
arguments.convertConstantExpression(session).toArrayConstantValueIfNecessary(psi as? KtElement)
|
||||
}
|
||||
is FirArrayOfCall -> {
|
||||
argumentList.arguments.convertConstantExpression(session)
|
||||
.toArrayConstantValueIfNecessary(realPsi as? KtElement)
|
||||
// Desugared collection literals.
|
||||
KtArrayConstantValue(argumentList.arguments.convertConstantExpression(session), psi as? KtElement)
|
||||
}
|
||||
is FirFunctionCall -> {
|
||||
val reference = calleeReference as? FirResolvedNamedReference ?: return null
|
||||
@@ -88,14 +109,14 @@ internal object KtFirConstantValueConverter {
|
||||
KtAnnotationConstantValue(
|
||||
resolvedSymbol.callableId.classId,
|
||||
toNamedConstantValue(resultMap, session),
|
||||
this.realPsi as? KtCallElement
|
||||
psi as? KtCallElement
|
||||
)
|
||||
} else null
|
||||
}
|
||||
is FirNamedFunctionSymbol -> {
|
||||
// arrayOf call with a single vararg argument.
|
||||
if (resolvedSymbol.callableId.asSingleFqName() in ArrayFqNames.ARRAY_CALL_FQ_NAMES)
|
||||
argumentList.arguments.convertConstantExpression(session)
|
||||
.toArrayConstantValueIfNecessary(realPsi as? KtElement)
|
||||
argumentList.arguments.single().convertConstantExpression(session)
|
||||
else null
|
||||
}
|
||||
else -> null
|
||||
@@ -105,7 +126,7 @@ internal object KtFirConstantValueConverter {
|
||||
val reference = calleeReference as? FirResolvedNamedReference ?: return null
|
||||
when (val resolvedSymbol = reference.resolvedSymbol) {
|
||||
is FirEnumEntrySymbol -> {
|
||||
KtEnumEntryConstantValue(resolvedSymbol.callableId, realPsi as? KtElement)
|
||||
KtEnumEntryConstantValue(resolvedSymbol.callableId, psi as? KtElement)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
+18
@@ -36,6 +36,12 @@ public class CompileTimeConstantEvaluatorTestGenerated extends AbstractCompileTi
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantEvaluator/annotationInAnnotation_collectionLiteral.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationInAnnotation_collectionLiteral_spread.kt")
|
||||
public void testAnnotationInAnnotation_collectionLiteral_spread() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantEvaluator/annotationInAnnotation_collectionLiteral_spread.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationInAnnotation_multipleAnnotations_arrayOf.kt")
|
||||
public void testAnnotationInAnnotation_multipleAnnotations_arrayOf() throws Exception {
|
||||
@@ -48,6 +54,18 @@ public class CompileTimeConstantEvaluatorTestGenerated extends AbstractCompileTi
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantEvaluator/annotationInAnnotation_multipleAnnotations_collectionLiteral.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationInAnnotation_single.kt")
|
||||
public void testAnnotationInAnnotation_single() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantEvaluator/annotationInAnnotation_single.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationInAnnotation_vararg.kt")
|
||||
public void testAnnotationInAnnotation_vararg() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantEvaluator/annotationInAnnotation_vararg.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("enumAsAnnotationValue.kt")
|
||||
public void testEnumAsAnnotationValue() throws Exception {
|
||||
|
||||
+1
-1
@@ -2,5 +2,5 @@ annotation class Annotation(vararg val strings: String)
|
||||
|
||||
annotation class AnnotationInner(val value: Annotation)
|
||||
|
||||
@AnnotationInner(<expr>Annotation(["v1", "v2"])</expr>)
|
||||
@AnnotationInner(<expr>Annotation(strings = ["v1", "v2"])</expr>)
|
||||
class C
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
expression: Annotation(["v1", "v2"])
|
||||
expression: Annotation(strings = ["v1", "v2"])
|
||||
constant_value: KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v1)
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v2)
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
annotation class Annotation(vararg val strings: String)
|
||||
|
||||
annotation class AnnotationInner(val value: Annotation)
|
||||
|
||||
@AnnotationInner(<expr>Annotation(*["v1", "v2"])</expr>)
|
||||
class C
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
expression: Annotation(*["v1", "v2"])
|
||||
constant_value: KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v1)
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v2)
|
||||
]))
|
||||
constant: null
|
||||
+1
-1
@@ -2,5 +2,5 @@ annotation class Annotation(vararg val strings: String)
|
||||
|
||||
annotation class AnnotationArray(vararg val annos: Annotation)
|
||||
|
||||
@AnnotationArray(<expr>annos = arrayOf(Annotation("v1", "v2"), Annotation(strings = arrayOf("v3", "v4")))</expr>)
|
||||
@AnnotationArray(annos = <expr>arrayOf(Annotation("v1", "v2"), Annotation(strings = arrayOf("v3", "v4")))</expr>)
|
||||
class C
|
||||
|
||||
+1
-1
@@ -2,5 +2,5 @@ annotation class Annotation(vararg val strings: String)
|
||||
|
||||
annotation class AnnotationArray(vararg val annos: Annotation)
|
||||
|
||||
@AnnotationArray(<expr>[Annotation("v1", "v2"), Annotation(["v3", "v4"])]</expr>)
|
||||
@AnnotationArray(annos = <expr>[Annotation("v1", "v2"), Annotation(strings = ["v3", "v4"])]</expr>)
|
||||
class C
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
expression: [Annotation("v1", "v2"), Annotation(["v3", "v4"])]
|
||||
expression: [Annotation("v1", "v2"), Annotation(strings = ["v3", "v4"])]
|
||||
constant_value: KtArrayConstantValue [
|
||||
KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v1)
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
annotation class Annotation(vararg val strings: String)
|
||||
|
||||
annotation class AnnotationInner(val value: Annotation)
|
||||
|
||||
@AnnotationInner(<expr>Annotation("v1")</expr>)
|
||||
class C
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
expression: Annotation("v1")
|
||||
constant_value: KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v1)
|
||||
]))
|
||||
constant: null
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
annotation class Annotation(vararg val strings: String)
|
||||
|
||||
annotation class AnnotationInner(val value: Annotation)
|
||||
|
||||
@AnnotationInner(<expr>Annotation("v1", "v2")</expr>)
|
||||
class C
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
expression: Annotation("v1", "v2")
|
||||
constant_value: KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v1)
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v2)
|
||||
]))
|
||||
constant: null
|
||||
Reference in New Issue
Block a user