[LL FIR] fix user code leak from exceptions in :analysis:analysis-api-fir

Also, add more info to some exceptions
This commit is contained in:
Ilya Kirillov
2023-07-24 17:51:15 +02:00
committed by Space Team
parent e3d2bccb33
commit 7606aab0dd
12 changed files with 80 additions and 31 deletions
@@ -623,7 +623,9 @@ private class BuilderCache<From, To : KtSymbol> {
inline fun <reified S : To> cache(key: From, calculation: () -> S): S {
val value = cache.getOrPut(key, calculation)
return value as? S
?: error("Cannot cast ${value::class} to ${S::class}\n${value}")
?: errorWithAttachment("Cannot cast ${value::class} to ${S::class}") {
withEntry("value", value.toString())
}
}
}
@@ -71,6 +71,7 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.util.OperatorNameConventions.EQUALS
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
internal class KtFirCallResolver(
override val analysisSession: KtFirAnalysisSession,
@@ -403,8 +404,13 @@ internal class KtFirCallResolver(
val explicitReceiverPsi = when (psi) {
is KtQualifiedExpression -> (psi.selectorExpression as KtCallExpression).calleeExpression
is KtCallExpression -> psi.calleeExpression
else -> error("unexpected PSI $psi for FirImplicitInvokeCall")
} ?: error("missing calleeExpression in PSI $psi for FirImplicitInvokeCall")
else -> errorWithAttachment("unexpected PSI ${psi::class} for FirImplicitInvokeCall") {
withPsiEntry("psi", psi, analysisSession::getModule)
}
}
?: errorWithAttachment("missing calleeExpression in PSI ${psi::class} for FirImplicitInvokeCall") {
withPsiEntry("psi", psi, analysisSession::getModule)
}
// Specially handle @ExtensionFunctionType
if (dispatchReceiver.typeRef.coneTypeSafe<ConeKotlinType>()?.isExtensionFunctionType == true) {
@@ -31,6 +31,8 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtSafeQualifiedExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForReceiver
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.utils.exceptions.withPsiEntry
internal class KtFirCompletionCandidateChecker(
override val analysisSession: KtFirAnalysisSession,
@@ -90,7 +92,9 @@ internal class KtFirCompletionCandidateChecker(
): Sequence<ImplicitReceiverValue<*>?> {
val towerDataContext = analysisSession.firResolveSession.getTowerContextProvider(originalFile)
.getClosestAvailableParentContext(fakeNameExpression)
?: error("Cannot find enclosing declaration for ${fakeNameExpression.getElementTextWithContext()}")
?: errorWithAttachment("Cannot find enclosing declaration for ${fakeNameExpression::class}") {
withPsiEntry("fakeNameExpression", fakeNameExpression)
}
return sequence {
yield(null) // otherwise explicit receiver won't be checked when there are no implicit receivers in completion position
@@ -23,6 +23,8 @@ import org.jetbrains.kotlin.fir.resolve.transformers.FirWhenExhaustivenessTransf
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.unwrapParenthesesLabelsAndAnnotations
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.utils.exceptions.withPsiEntry
internal class KtFirExpressionInfoProvider(
override val analysisSession: KtFirAnalysisSession,
@@ -172,8 +174,9 @@ internal class KtFirExpressionInfoProvider(
false
!is KtExpression ->
error("Unhandled Non-KtExpression parent of KtExpression: ${parent::class}")
errorWithAttachment("Unhandled Non-KtExpression parent of KtExpression: ${parent::class}") {
withPsiEntry("parent", parent)
}
/**
* EXPRESSIONS
*/
@@ -351,7 +354,9 @@ internal class KtFirExpressionInfoProvider(
false
else ->
error("Unhandled KtElement subtype: ${parent::class}")
errorWithAttachment("Unhandled KtElement subtype: ${parent::class}") {
withPsiEntry("parent", parent)
}
}
}
}
@@ -42,6 +42,8 @@ import org.jetbrains.kotlin.psi.psiUtil.unwrapNullability
import org.jetbrains.kotlin.resolve.ImportPath
import org.jetbrains.kotlin.resolve.calls.util.getCalleeExpressionIfAny
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.utils.exceptions.withPsiEntry
internal class KtFirImportOptimizer(
override val token: KtLifetimeToken,
@@ -444,7 +446,9 @@ private sealed interface TypeQualifier {
}
qualifier.getCalleeExpressionIfAny() as? KtNameReferenceExpression
?: error("Cannot get referenced name from '${qualifier.text}'")
?: errorWithAttachment("Cannot get referenced name from '${qualifier::class}'") {
withPsiEntry("qualifier", qualifier)
}
}
override val referencedByName: Name
@@ -469,7 +473,9 @@ private sealed interface TypeQualifier {
override val referencedByName: Name
get() = qualifier.referenceExpression?.getReferencedNameAsName()
?: error("Cannot get referenced name from '${qualifier.text}'")
?: errorWithAttachment("Cannot get referenced name from '${qualifier::class}'") {
withPsiEntry("qualifier", qualifier)
}
override val isQualified: Boolean
get() = qualifier.qualifier != null
@@ -66,6 +66,7 @@ import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
internal class KtFirReferenceShortener(
override val analysisSession: KtFirAnalysisSession,
@@ -520,7 +521,9 @@ private class ElementsToShortenCollector(
is FirNestedClassifierScope -> klass.classId
is FirNestedClassifierScopeWithSubstitution -> originalScope.correspondingClassIdIfExists()
is FirClassUseSiteMemberScope -> classId
else -> error("FirScope `$this` is expected to be one of FirNestedClassifierScope and FirClassUseSiteMemberScope to get ClassId")
else -> errorWithAttachment("FirScope ${this::class}` is expected to be one of FirNestedClassifierScope and FirClassUseSiteMemberScope to get ClassId") {
withEntry("firScope", this@correspondingClassIdIfExists) { it.toString() }
}
}
private fun ClassId.idWithoutCompanion() = if (shortClassName == SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT) outerClassId else this
@@ -1095,7 +1098,9 @@ private class ElementsToShortenCollector(
val distinctCandidates = candidates.distinctBy { it.callableId }
return distinctCandidates.singleOrNull()
?: error("Expected all candidates to have same callableId, but got: ${distinctCandidates.map { it.callableId }}")
?: errorWithAttachment("Expected all candidates to have same callableId but some of them but was different") {
withEntry("callableIds", distinctCandidates.map { it.callableId.asSingleFqName() }.joinToString())
}
}
private fun findFakePackageToShorten(wholeQualifiedExpression: KtDotQualifiedExpression): ShortenQualifier? {
@@ -51,6 +51,8 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.utils.addToStdlib.applyIf
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.utils.exceptions.withPsiEntry
internal class KtFirScopeProvider(
override val analysisSession: KtFirAnalysisSession,
@@ -194,7 +196,9 @@ internal class KtFirScopeProvider(
): KtScopeContext {
val towerDataContext =
analysisSession.firResolveSession.getTowerContextProvider(originalFile).getClosestAvailableParentContext(positionInFakeFile)
?: error("Cannot find enclosing declaration for ${positionInFakeFile.getElementTextWithContext()}")
?: errorWithAttachment("Cannot find enclosing declaration for ${positionInFakeFile::class}") {
withPsiEntry("positionInFakeFile", positionInFakeFile)
}
val towerDataElementsIndexed = towerDataContext.towerDataElements.asReversed().withIndex()
val implicitReceivers = towerDataElementsIndexed.flatMap { (index, towerDataElement) ->
@@ -17,6 +17,8 @@ import org.jetbrains.kotlin.fir.contracts.description.*
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
internal fun KtEffectDeclaration<ConeKotlinType, ConeDiagnostic>.coneEffectDeclarationToAnalysisApi(
builder: KtSymbolByFirBuilder,
@@ -51,12 +53,16 @@ private class ConeContractDescriptionElementToAnalysisApi(
when (value) {
ConeContractConstantValues.TRUE -> KtContractConstantType.TRUE
ConeContractConstantValues.FALSE -> KtContractConstantType.FALSE
else -> error("Can't convert $value to the Analysis API")
else -> errorWithAttachment("Can't convert ${value::class} to the Analysis API") {
withEntry("value", value) { value.toString() }
}
},
builder.token
)
)
else -> error("Can't convert $returnsEffect to the Analysis API")
else -> errorWithAttachment("Can't convert ${returnsEffect::class} to the Analysis API") {
withEntry("value", value) { value.toString() }
}
}
override fun visitCallsEffectDeclaration(callsEffect: KtCallsEffectDeclaration<ConeKotlinType, ConeDiagnostic>, data: Unit): KtContractCallsInPlaceContractEffectDeclaration =
@@ -116,7 +122,9 @@ private class ConeContractDescriptionElementToAnalysisApi(
constructor: (KtParameterSymbol) -> T
): T = constructor(
if (valueParameterReference.parameterIndex == -1) firFunctionSymbol.receiverParameter
?: error("$firFunctionSymbol should contain a receiver")
?: errorWithAttachment("${firFunctionSymbol::class} should contain a receiver") {
withFirEntry("fir", firFunctionSymbol.firSymbol.fir)
}
else firFunctionSymbol.valueParameters[valueParameterReference.parameterIndex]
)
@@ -22,6 +22,9 @@ import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.utils.exceptions.requireWithAttachment
internal class KtFirReceiverParameterSymbol(
val firSymbol: FirCallableSymbol<*>,
@@ -31,11 +34,16 @@ internal class KtFirReceiverParameterSymbol(
override val psi: PsiElement? = withValidityAssertion{ firSymbol.fir.receiverParameter?.typeRef?.psi }
init {
require(firSymbol.fir.receiverParameter != null) { "$firSymbol doesn't have an extension receiver." }
requireWithAttachment(firSymbol.fir.receiverParameter != null, { "${firSymbol::class} doesn't have an extension receiver." }) {
withFirEntry("callable", firSymbol.fir)
}
}
override val type: KtType by cached {
firSymbol.receiverType(analysisSession.firSymbolBuilder) ?: error("$firSymbol doesn't have an extension receiver.")
firSymbol.receiverType(analysisSession.firSymbolBuilder)
?: errorWithAttachment("${firSymbol::class} doesn't have an extension receiver") {
withFirEntry("callable", firSymbol.fir)
}
}
override val owningCallableSymbol: KtCallableSymbol by cached { analysisSession.firSymbolBuilder.callableBuilder.buildCallableSymbol(firSymbol) }
@@ -25,7 +25,9 @@ import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.renderWithType
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
import org.jetbrains.kotlin.fir.types.arrayElementType
import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
internal class KtFirValueParameterSymbol(
override val firSymbol: FirValueParameterSymbol,
@@ -51,7 +53,9 @@ internal class KtFirValueParameterSymbol(
return@cached if (firSymbol.isVararg) {
// There SHOULD always be an array element type (even if it is an error type, e.g., unresolved).
val arrayElementType = returnType.arrayElementType()
?: error("No array element type for vararg value parameter: ${firSymbol.fir.renderWithType()}")
?: errorWithAttachment("No array element type for vararg value parameter") {
withFirEntry("fir", firSymbol.fir)
}
builder.typeBuilder.buildKtType(arrayElementType)
} else {
builder.typeBuilder.buildKtType(returnType)
@@ -16,31 +16,24 @@ import org.jetbrains.kotlin.analysis.api.impl.base.KtContextReceiverImpl
import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.references.impl.FirPropertyFromParameterResolvedNamedReference
import org.jetbrains.kotlin.fir.renderer.FirRenderer
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
internal fun FirCallableSymbol<*>.invalidModalityError(): Nothing {
val rendered = FirRenderer.withResolvePhase().renderElementWithTypeAsString(fir)
error(
"""|Symbol modality should not be null, looks like the FIR symbol was not properly resolved
|
|$rendered
|
|${(fir.psi as? KtDeclaration)?.getElementTextWithContext()}""".trimMargin()
)
errorWithAttachment("Symbol modality should not be null, looks like the FIR symbol was not properly resolved") {
withFirEntry("fir", this@invalidModalityError.fir)
}
}
internal fun FirFunctionSymbol<*>.createKtValueParameters(builder: KtSymbolByFirBuilder): List<KtValueParameterSymbol> {
@@ -21,6 +21,8 @@ import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.LookupTagInternals
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.utils.exceptions.withPsiEntry
internal object UsualClassTypeQualifierBuilder {
fun buildQualifiers(
@@ -104,7 +106,9 @@ internal object UsualClassTypeQualifierBuilder {
is FirAnonymousObject -> listOf(declaration)
is FirRegularClass -> declaration.collectForLocal()
is FirTypeAlias -> listOf(declaration) // TODO: handle type aliases
else -> error("Invalid declaration ${declaration.renderWithType()}")
else -> errorWithAttachment("Invalid declaration ${declaration::class}") {
withFirEntry("declaration", declaration)
}
}
}
}