From ce445700b81c7b10eccf8e3d8e8295489fed602d Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Mon, 20 Sep 2021 13:58:38 -0700 Subject: [PATCH] FIR IDE: split conversion utils for KtConstantValue to its own object --- .../KtFirCompileTimeConstantProvider.kt | 6 +- .../evaluate/KtFirConstantValueConverter.kt | 123 ++++++++++++++++++ .../fir/symbols/KtFirKotlinPropertySymbol.kt | 4 +- .../KtFirSyntheticJavaPropertySymbol.kt | 4 +- .../annotations/KtFirAnnotationCall.kt | 7 +- .../kotlin/analysis/api/fir/utils/firUtils.kt | 91 ------------- 6 files changed, 136 insertions(+), 99 deletions(-) create mode 100644 analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/evaluate/KtFirConstantValueConverter.kt diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompileTimeConstantProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompileTimeConstantProvider.kt index b6b79f3a03e..4229f5fc742 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompileTimeConstantProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompileTimeConstantProvider.kt @@ -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) } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/evaluate/KtFirConstantValueConverter.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/evaluate/KtFirConstantValueConverter.kt new file mode 100644 index 00000000000..15e1ec826a6 --- /dev/null +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/evaluate/KtFirConstantValueConverter.kt @@ -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, + session: FirSession, + firSymbolBuilder: KtSymbolByFirBuilder + ): List = + argumentMapping.map { (name, expression) -> + KtNamedConstantValue( + name, + expression.convertConstantExpression(session, firSymbolBuilder) ?: KtUnsupportedConstantValue + ) + } + + fun toConstantValue( + firConstExpression: FirConstExpression, + ): KtSimpleConstantValue = + firConstExpression.convertConstantExpression() + + private fun FirConstExpression.convertConstantExpression(): KtSimpleConstantValue = + KtSimpleConstantValue(kind, value, realPsi as? KtElement) + + private fun Collection.convertConstantExpression( + session: FirSession, + firSymbolBuilder: KtSymbolByFirBuilder + ): Collection = + mapNotNull { it.convertConstantExpression(session, firSymbolBuilder) } + + private fun Collection.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() + 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 + } + } +} diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirKotlinPropertySymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirKotlinPropertySymbol.kt index 90c3f18b735..fe20ee3ec4e 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirKotlinPropertySymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirKotlinPropertySymbol.kt @@ -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 -> diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSyntheticJavaPropertySymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSyntheticJavaPropertySymbol.kt index 184cffb27df..674c39c32b2 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSyntheticJavaPropertySymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSyntheticJavaPropertySymbol.kt @@ -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() diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/annotations/KtFirAnnotationCall.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/annotations/KtFirAnnotationCall.kt index 22293283bf2..f6d59c90cb9 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/annotations/KtFirAnnotationCall.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/annotations/KtFirAnnotationCall.kt @@ -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 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 { diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/utils/firUtils.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/utils/firUtils.kt index 28e544fa8a9..96d22ec0b50 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/utils/firUtils.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/utils/firUtils.kt @@ -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.toNamedConstantValue( - session: FirSession, - firSymbolBuilder: KtSymbolByFirBuilder -): List = - map { (name, expression) -> - KtNamedConstantValue( - name, - expression.convertConstantExpression(session, firSymbolBuilder) ?: KtUnsupportedConstantValue - ) - } - -internal fun FirConstExpression.convertConstantExpression(): KtSimpleConstantValue = - KtSimpleConstantValue(kind, value, realPsi as? KtElement) - -private fun Collection.convertConstantExpression( - session: FirSession, - firSymbolBuilder: KtSymbolByFirBuilder -): Collection = - mapNotNull { it.convertConstantExpression(session, firSymbolBuilder) } - -private fun Collection.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() - 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