From 4bca296dc652242d5f1377e91a16fef7cb265169 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Fri, 9 Jul 2021 17:47:08 +0200 Subject: [PATCH] LL API: introduce helper function for throwing invalid FirElement exception --- .../api/api/InvalidFirElementTypeException.kt | 43 +++++++++++++++++++ .../low/level/api/api/LowLevelFirApiFacade.kt | 12 ++---- .../low/level/api/util/declarationUtils.kt | 3 +- .../KtFirCompileTimeConstantProvider.kt | 3 +- .../components/KtFirExpressionTypeProvider.kt | 2 +- .../fir/components/KtFirPsiTypeProvider.kt | 7 +-- 6 files changed, 55 insertions(+), 15 deletions(-) create mode 100644 idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/InvalidFirElementTypeException.kt diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/InvalidFirElementTypeException.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/InvalidFirElementTypeException.kt new file mode 100644 index 00000000000..129bfe0746f --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/InvalidFirElementTypeException.kt @@ -0,0 +1,43 @@ +/* + * 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.idea.fir.low.level.api.api + +import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.psi.KtElement +import java.util.* +import kotlin.reflect.KClass + +class InvalidFirElementTypeException( + actualFirClass: KClass?, + ktElement: KtElement?, + expectedFirClasses: List>, +) : IllegalStateException() { + override val message: String = buildString { + if (ktElement != null) { + append("For $ktElement with text `${ktElement.text}`, ") + } + val message = when (expectedFirClasses.size) { + 0 -> "Unexpected FirElement of type:" + 1 -> "The FirElement of type ${expectedFirClasses.single()} expected, but" + else -> "One of [${expectedFirClasses.joinToString()}] FirElement types expected, but" + } + append(if (ktElement == null) message else message.replaceFirstChar { it.lowercase(Locale.getDefault()) }) + if (actualFirClass != null) { + append(" ${actualFirClass.simpleName} found") + } else { + append(" no FirElement found") + } + } +} + + +fun throwUnexpectedFirElementError( + firElement: FirElement?, + ktElement: KtElement? = null, + vararg expectedFirClasses: KClass +): Nothing { + throw InvalidFirElementTypeException(firElement?.let { it::class }, ktElement, expectedFirClasses.toList()) +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacade.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacade.kt index cd5a3745283..6fab95b929b 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacade.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacade.kt @@ -93,7 +93,7 @@ inline fun KtDeclaration.withFirDeclarationOfTyp phase: FirResolvePhase = FirResolvePhase.RAW_FIR, action: (F) -> R ): R = withFirDeclaration(resolveState, phase) { firDeclaration -> - if (firDeclaration !is F) throw InvalidFirElementTypeException(this, F::class, firDeclaration::class) + if (firDeclaration !is F) throwUnexpectedFirElementError(firDeclaration, this, F::class) action(firDeclaration) } @@ -111,7 +111,7 @@ inline fun KtLambdaExpression.withFirDeclaration action: (F) -> R ): R { val firDeclaration = resolveState.findSourceFirDeclaration(this) - if (firDeclaration !is F) throw InvalidFirElementTypeException(this, F::class, firDeclaration::class) + if (firDeclaration !is F) throwUnexpectedFirElementError(firDeclaration, this, F::class) return action(firDeclaration) } @@ -233,7 +233,7 @@ inline fun KtElement.getOrBuildFirOfType( ): E { val fir = this.getOrBuildFir(resolveState) if (fir is E) return fir - throw InvalidFirElementTypeException(this, E::class, fir::class) + throwUnexpectedFirElementError(fir, this, E::class) } /** @@ -242,9 +242,3 @@ inline fun KtElement.getOrBuildFirOfType( */ fun KtFile.getOrBuildFirFile(resolveState: FirModuleResolveState): FirFile = resolveState.getOrBuildFirFile(this) - -class InvalidFirElementTypeException( - ktElement: KtElement, - expectedFirClass: KClass, - actualFirClass: KClass -) : IllegalStateException("For $ktElement with text `${ktElement.text}` the $expectedFirClass expected, but $actualFirClass found") diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/util/declarationUtils.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/util/declarationUtils.kt index 0486e410050..db1f47e762e 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/util/declarationUtils.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/util/declarationUtils.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.realPsi import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.idea.fir.low.level.api.api.InvalidFirElementTypeException +import org.jetbrains.kotlin.idea.fir.low.level.api.api.throwUnexpectedFirElementError import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.getNonLocalContainingOrThisDeclaration import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache @@ -56,7 +57,7 @@ internal inline fun KtDeclaration.findFirDeclaratio moduleFileCache: ModuleFileCache ): FirDeclaration { val fir = findFirDeclarationForAnyFirSourceDeclaration(firFileBuilder, firSymbolProvider, moduleFileCache) - if (fir !is F) throw InvalidFirElementTypeException(this, F::class, fir::class) + if (fir !is F) throwUnexpectedFirElementError(fir, this, F::class) return fir } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCompileTimeConstantProvider.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCompileTimeConstantProvider.kt index 0908ffa4240..49c05053296 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCompileTimeConstantProvider.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCompileTimeConstantProvider.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.components import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.idea.fir.evaluate.FirCompileTimeConstantEvaluator import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFir +import org.jetbrains.kotlin.idea.fir.low.level.api.api.throwUnexpectedFirElementError import org.jetbrains.kotlin.idea.frontend.api.components.KtCompileTimeConstantProvider import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.fir.utils.convertConstantExpression @@ -24,7 +25,7 @@ internal class KtFirCompileTimeConstantProvider( override fun evaluate(expression: KtExpression): KtSimpleConstantValue<*>? = withValidityAssertion { when (val fir = expression.getOrBuildFir(firResolveState)) { is FirExpression -> FirCompileTimeConstantEvaluator().evaluate(fir)?.convertConstantExpression() - else -> error("Unexpected ${fir::class}") + else -> throwUnexpectedFirElementError(fir, expression) } } } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirExpressionTypeProvider.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirExpressionTypeProvider.kt index c9ce4739e00..be75532823f 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirExpressionTypeProvider.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirExpressionTypeProvider.kt @@ -39,7 +39,7 @@ internal class KtFirExpressionTypeProvider( is FirExpression -> fir.typeRef.coneType.asKtType() is FirNamedReference -> fir.getReferencedElementType().asKtType() is FirStatement -> with(analysisSession) { builtinTypes.UNIT } - else -> error("Unexpected ${fir::class}") + else -> error("Unexpected ${fir?.let { it::class }}") } } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirPsiTypeProvider.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirPsiTypeProvider.kt index bb61b176ff8..c11d3d5570d 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirPsiTypeProvider.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirPsiTypeProvider.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.references.FirNamedReference import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFir +import org.jetbrains.kotlin.idea.fir.low.level.api.api.throwUnexpectedFirElementError import org.jetbrains.kotlin.idea.frontend.api.components.KtPsiTypeProvider import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.fir.utils.getReferencedElementType @@ -36,7 +37,7 @@ internal class KtFirPsiTypeProvider( is FirExpression -> fir.typeRef.coneType.asPsiType(mode, expression) is FirNamedReference -> fir.getReferencedElementType().asPsiType(mode, expression) is FirStatement -> PsiType.VOID - else -> error("Unexpected ${fir::class}") + else -> throwUnexpectedFirElementError(fir, expression) } } @@ -47,7 +48,7 @@ internal class KtFirPsiTypeProvider( when (val fir = ktTypeReference.getOrBuildFir(firResolveState)) { // NB: [FirErrorTypeRef] is a subtype of [FirResolvedTypeRef], and the error type in it will be properly handled by [asPsiType]. is FirResolvedTypeRef -> fir.coneType.asPsiType(mode, ktTypeReference) - else -> error("Unexpected ${fir::class}") + else -> throwUnexpectedFirElementError(fir, ktTypeReference) } } @@ -61,7 +62,7 @@ internal class KtFirPsiTypeProvider( fir.typeRef.coneType.getReceiverOfReflectionType()?.asPsiType(mode, receiver) is FirCallableReferenceAccess -> fir.typeRef.coneType.getReceiverOfReflectionType()?.asPsiType(mode, receiver) - else -> error("Unexpected ${fir::class}") + else -> throwUnexpectedFirElementError(fir, ktDoubleColonExpression) } }