FIR IDE: handle annotation array values properly

This commit is contained in:
Jinseong Jeon
2021-09-20 23:05:31 -07:00
committed by Ilya Kirillov
parent ffd0a5ed14
commit 414881403b
13 changed files with 95 additions and 21 deletions
@@ -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
}
@@ -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 {
@@ -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,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)
@@ -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
@@ -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
@@ -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
@@ -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,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)
@@ -0,0 +1,6 @@
annotation class Annotation(vararg val strings: String)
annotation class AnnotationInner(val value: Annotation)
@AnnotationInner(<expr>Annotation("v1")</expr>)
class C
@@ -0,0 +1,5 @@
expression: Annotation("v1")
constant_value: KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
KtLiteralConstantValue(constantValueKind=String, value=v1)
]))
constant: null
@@ -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
@@ -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