LL API: introduce helper function for throwing invalid FirElement exception

This commit is contained in:
Ilya Kirillov
2021-07-09 17:47:08 +02:00
committed by teamcityserver
parent c0eb669191
commit 4bca296dc6
6 changed files with 55 additions and 15 deletions
@@ -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<out FirElement>?,
ktElement: KtElement?,
expectedFirClasses: List<KClass<out FirElement>>,
) : 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<out FirElement>
): Nothing {
throw InvalidFirElementTypeException(firElement?.let { it::class }, ktElement, expectedFirClasses.toList())
}
@@ -93,7 +93,7 @@ inline fun <reified F : FirDeclaration, R> 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 <reified F : FirDeclaration, R> 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 <reified E : FirElement> 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 <reified E : FirElement> KtElement.getOrBuildFirOfType(
*/
fun KtFile.getOrBuildFirFile(resolveState: FirModuleResolveState): FirFile =
resolveState.getOrBuildFirFile(this)
class InvalidFirElementTypeException(
ktElement: KtElement,
expectedFirClass: KClass<out FirElement>,
actualFirClass: KClass<out FirElement>
) : IllegalStateException("For $ktElement with text `${ktElement.text}` the $expectedFirClass expected, but $actualFirClass found")
@@ -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 <reified F : FirDeclaration> 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
}
@@ -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)
}
}
}
@@ -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 }}")
}
}
@@ -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)
}
}