FIR IDE: split conversion utils for KtConstantValue to its own object

This commit is contained in:
Jinseong Jeon
2021-09-20 13:58:38 -07:00
committed by Ilya Kirillov
parent 4c8d975ae5
commit ce445700b8
6 changed files with 136 additions and 99 deletions
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
import org.jetbrains.kotlin.analysis.api.components.KtCompileTimeConstantProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.utils.convertConstantExpression
import org.jetbrains.kotlin.analysis.api.fir.evaluate.KtFirConstantValueConverter
import org.jetbrains.kotlin.analysis.api.symbols.markers.*
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
@@ -25,8 +25,8 @@ internal class KtFirCompileTimeConstantProvider(
override fun evaluate(expression: KtExpression): KtConstantValue? = withValidityAssertion {
when (val fir = expression.getOrBuildFir(firResolveState)) {
is FirExpression -> {
FirCompileTimeConstantEvaluator().evaluate(fir)?.convertConstantExpression()
?: fir.convertConstantExpression(firResolveState.rootModuleSession, firSymbolBuilder)
FirCompileTimeConstantEvaluator().evaluate(fir)?.let { KtFirConstantValueConverter.toConstantValue(it) }
?: KtFirConstantValueConverter.toConstantValue(fir, firResolveState.rootModuleSession, firSymbolBuilder)
}
else -> throwUnexpectedFirElementError(fir, expression)
}
@@ -0,0 +1,123 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.evaluate
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.buildSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntrySymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.*
import org.jetbrains.kotlin.descriptors.ClassKind
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.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.resolve.ArrayFqNames
internal object KtFirConstantValueConverter {
fun toNamedConstantValue(
argumentMapping: Map<String, FirExpression>,
session: FirSession,
firSymbolBuilder: KtSymbolByFirBuilder
): List<KtNamedConstantValue> =
argumentMapping.map { (name, expression) ->
KtNamedConstantValue(
name,
expression.convertConstantExpression(session, firSymbolBuilder) ?: KtUnsupportedConstantValue
)
}
fun <T> toConstantValue(
firConstExpression: FirConstExpression<T>,
): KtSimpleConstantValue<T> =
firConstExpression.convertConstantExpression()
private fun <T> FirConstExpression<T>.convertConstantExpression(): KtSimpleConstantValue<T> =
KtSimpleConstantValue(kind, value, realPsi as? KtElement)
private fun Collection<FirExpression>.convertConstantExpression(
session: FirSession,
firSymbolBuilder: KtSymbolByFirBuilder
): Collection<KtConstantValue> =
mapNotNull { it.convertConstantExpression(session, firSymbolBuilder) }
private fun Collection<KtConstantValue>.toArrayConstantValueIfNecessary(kotlinOrigin: KtElement?): KtConstantValue {
return if (size == 1)
single()
else
KtArrayConstantValue(this, kotlinOrigin)
}
fun toConstantValue(
firExpression: FirExpression,
session: FirSession,
firSymbolBuilder: KtSymbolByFirBuilder
): KtConstantValue? =
firExpression.convertConstantExpression(session, firSymbolBuilder)
private fun FirExpression.convertConstantExpression(
session: FirSession,
firSymbolBuilder: KtSymbolByFirBuilder
): KtConstantValue? {
return when (this) {
is FirConstExpression<*> -> convertConstantExpression()
is FirNamedArgumentExpression -> {
expression.convertConstantExpression(session, firSymbolBuilder)
}
is FirVarargArgumentsExpression -> {
arguments.convertConstantExpression(session, firSymbolBuilder)
.toArrayConstantValueIfNecessary(realPsi as? KtElement)
}
is FirArrayOfCall -> {
argumentList.arguments.convertConstantExpression(session, firSymbolBuilder)
.toArrayConstantValueIfNecessary(realPsi as? KtElement)
}
is FirFunctionCall -> {
val reference = calleeReference as? FirResolvedNamedReference ?: return null
when (val resolvedSymbol = reference.resolvedSymbol) {
is FirConstructorSymbol -> {
val classSymbol = resolvedSymbol.getContainingClassSymbol(session) ?: return null
if ((classSymbol.fir as? FirClass)?.classKind == ClassKind.ANNOTATION_CLASS) {
val resultMap = mutableMapOf<String, FirExpression>()
argumentMapping?.entries?.forEach { (arg, param) ->
resultMap[param.name.asString()] = arg
}
KtAnnotationConstantValue(
resolvedSymbol.callableId.className?.asString(),
toNamedConstantValue(resultMap, session, firSymbolBuilder),
this.realPsi as? KtCallElement
)
} else null
}
is FirNamedFunctionSymbol -> {
if (resolvedSymbol.callableId.asSingleFqName() in ArrayFqNames.ARRAY_CALL_FQ_NAMES)
argumentList.arguments.convertConstantExpression(session, firSymbolBuilder)
.toArrayConstantValueIfNecessary(realPsi as? KtElement)
else null
}
else -> null
}
}
is FirPropertyAccessExpression -> {
val reference = calleeReference as? FirResolvedNamedReference ?: return null
when (val resolvedSymbol = reference.resolvedSymbol) {
is FirEnumEntrySymbol -> {
KtEnumEntryValue(resolvedSymbol.fir.buildSymbol(firSymbolBuilder) as KtEnumEntrySymbol, realPsi as? KtElement)
}
else -> null
}
}
else -> KtUnsupportedConstantValue
}
}
}
@@ -17,13 +17,13 @@ import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.evaluate.KtFirConstantValueConverter
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.containsAnnotation
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.getAnnotationClassIds
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.toAnnotationsList
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirMemberPropertySymbolPointer
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.createSignature
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.convertConstantExpression
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtKotlinPropertySymbol
@@ -72,7 +72,7 @@ internal class KtFirKotlinPropertySymbol(
override val isExtension: Boolean get() = firRef.withFir { it.receiverTypeRef != null }
override val initializer: KtConstantValue? by firRef.withFirAndCache(FirResolvePhase.BODY_RESOLVE) { fir ->
fir.initializer?.convertConstantExpression(resolveState.rootModuleSession, _builder)
fir.initializer?.let { KtFirConstantValueConverter.toConstantValue(it, resolveState.rootModuleSession, _builder) }
}
override val symbolKind: KtSymbolKind
get() = firRef.withFir { fir ->
@@ -15,12 +15,12 @@ import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.evaluate.KtFirConstantValueConverter
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.containsAnnotation
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.getAnnotationClassIds
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.toAnnotationsList
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirJavaSyntheticPropertySymbolPointer
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.convertConstantExpression
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.*
@@ -60,7 +60,7 @@ internal class KtFirSyntheticJavaPropertySymbol(
}
override val isExtension: Boolean get() = firRef.withFir { it.receiverTypeRef != null }
override val initializer: KtConstantValue? by firRef.withFirAndCache(FirResolvePhase.BODY_RESOLVE) { fir ->
fir.initializer?.convertConstantExpression(resolveState.rootModuleSession, _builder)
fir.initializer?.let { KtFirConstantValueConverter.toConstantValue(it, resolveState.rootModuleSession, _builder) }
}
override val modality: Modality get() = getModality()
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.analysis.api.fir.symbols.annotations
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.evaluate.KtFirConstantValueConverter
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
@@ -41,7 +42,11 @@ internal class KtFirAnnotationCall(
override val useSiteTarget: AnnotationUseSiteTarget? get() = annotationCallRef.useSiteTarget
override val arguments: List<KtNamedConstantValue> by containingDeclaration.withFirAndCache(ResolveType.AnnotationsArguments) { fir ->
mapAnnotationParameters(annotationCallRef, fir.moduleData.session).toNamedConstantValue(fir.moduleData.session, _builder)
KtFirConstantValueConverter.toNamedConstantValue(
mapAnnotationParameters(annotationCallRef, fir.moduleData.session),
fir.moduleData.session,
_builder
)
}
override fun equals(other: Any?): Boolean {
@@ -5,8 +5,6 @@
package org.jetbrains.kotlin.analysis.api.fir.utils
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.buildSymbol
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.classKind
@@ -22,19 +20,13 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.analysis.api.fir.getCandidateSymbols
import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntrySymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.withFirDeclaration
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveType
import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.realPsi
import org.jetbrains.kotlin.fir.symbols.impl.FirEnumEntrySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.ArrayFqNames
internal fun PsiElement.unwrap(): PsiElement {
return when (this) {
@@ -98,89 +90,6 @@ internal fun mapAnnotationParameters(annotation: FirAnnotation, session: FirSess
return resultSet
}
internal fun Map<String, FirExpression>.toNamedConstantValue(
session: FirSession,
firSymbolBuilder: KtSymbolByFirBuilder
): List<KtNamedConstantValue> =
map { (name, expression) ->
KtNamedConstantValue(
name,
expression.convertConstantExpression(session, firSymbolBuilder) ?: KtUnsupportedConstantValue
)
}
internal fun <T> FirConstExpression<T>.convertConstantExpression(): KtSimpleConstantValue<T> =
KtSimpleConstantValue(kind, value, realPsi as? KtElement)
private fun Collection<FirExpression>.convertConstantExpression(
session: FirSession,
firSymbolBuilder: KtSymbolByFirBuilder
): Collection<KtConstantValue> =
mapNotNull { it.convertConstantExpression(session, firSymbolBuilder) }
private fun Collection<KtConstantValue>.toArrayConstantValueIfNecessary(kotlinOrigin: KtElement?): KtConstantValue {
return if (size == 1)
single()
else
KtArrayConstantValue(this, kotlinOrigin)
}
internal fun FirExpression.convertConstantExpression(
session: FirSession,
firSymbolBuilder: KtSymbolByFirBuilder
): KtConstantValue? {
return when (this) {
is FirConstExpression<*> -> convertConstantExpression()
is FirNamedArgumentExpression -> {
expression.convertConstantExpression(session, firSymbolBuilder)
}
is FirVarargArgumentsExpression -> {
arguments.convertConstantExpression(session, firSymbolBuilder)
.toArrayConstantValueIfNecessary(realPsi as? KtElement)
}
is FirArrayOfCall -> {
argumentList.arguments.convertConstantExpression(session, firSymbolBuilder)
.toArrayConstantValueIfNecessary(realPsi as? KtElement)
}
is FirFunctionCall -> {
val reference = calleeReference as? FirResolvedNamedReference ?: return null
when (val resolvedSymbol = reference.resolvedSymbol) {
is FirConstructorSymbol -> {
val classSymbol = resolvedSymbol.getContainingClassSymbol(session) ?: return null
if ((classSymbol.fir as? FirClass)?.classKind == ClassKind.ANNOTATION_CLASS) {
val resultMap = mutableMapOf<String, FirExpression>()
argumentMapping?.entries?.forEach { (arg, param) ->
resultMap[param.name.asString()] = arg
}
KtAnnotationConstantValue(
resolvedSymbol.callableId.className?.asString(),
resultMap.toNamedConstantValue(session, firSymbolBuilder),
this.realPsi as? KtCallElement
)
} else null
}
is FirNamedFunctionSymbol -> {
if (resolvedSymbol.callableId.asSingleFqName() in ArrayFqNames.ARRAY_CALL_FQ_NAMES)
argumentList.arguments.convertConstantExpression(session, firSymbolBuilder)
.toArrayConstantValueIfNecessary(realPsi as? KtElement)
else null
}
else -> null
}
}
is FirPropertyAccessExpression -> {
val reference = calleeReference as? FirResolvedNamedReference ?: return null
when (val resolvedSymbol = reference.resolvedSymbol) {
is FirEnumEntrySymbol -> {
KtEnumEntryValue(resolvedSymbol.fir.buildSymbol(firSymbolBuilder) as KtEnumEntrySymbol, realPsi as? KtElement)
}
else -> null
}
}
else -> KtUnsupportedConstantValue
}
}
internal fun KtTypeNullability.toConeNullability() = when (this) {
KtTypeNullability.NULLABLE -> ConeNullability.NULLABLE
KtTypeNullability.NON_NULLABLE -> ConeNullability.NOT_NULL