From 7606aab0dd21ee27f02093a11830b46bab31f006 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Mon, 24 Jul 2023 17:51:15 +0200 Subject: [PATCH] [LL FIR] fix user code leak from exceptions in `:analysis:analysis-api-fir` Also, add more info to some exceptions --- .../analysis/api/fir/KtSymbolByFirBuilder.kt | 4 +++- .../api/fir/components/KtFirCallResolver.kt | 10 ++++++++-- .../KtFirCompletionCandidateChecker.kt | 6 +++++- .../components/KtFirExpressionInfoProvider.kt | 11 ++++++++--- .../api/fir/components/KtFirImportOptimizer.kt | 10 ++++++++-- .../fir/components/KtFirReferenceShortener.kt | 9 +++++++-- .../api/fir/components/KtFirScopeProvider.kt | 6 +++++- .../api/fir/contracts/firContractUtils.kt | 14 +++++++++++--- .../fir/symbols/KtFirReceiverParameterSymbol.kt | 12 ++++++++++-- .../fir/symbols/KtFirValueParameterSymbol.kt | 6 +++++- .../analysis/api/fir/symbols/firSymbolUtils.kt | 17 +++++------------ .../UsualClassTypeQualifierBuilder.kt | 6 +++++- 12 files changed, 80 insertions(+), 31 deletions(-) diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt index 91832088cf3..47835ac504b 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt @@ -623,7 +623,9 @@ private class BuilderCache { inline fun 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()) + } } } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCallResolver.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCallResolver.kt index d50ee7562fa..5c21b5ea823 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCallResolver.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCallResolver.kt @@ -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()?.isExtensionFunctionType == true) { diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompletionCandidateChecker.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompletionCandidateChecker.kt index 4f044675450..1fa692c1586 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompletionCandidateChecker.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompletionCandidateChecker.kt @@ -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?> { 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 diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirExpressionInfoProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirExpressionInfoProvider.kt index 9f7d8bc8f8a..7abb07c3062 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirExpressionInfoProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirExpressionInfoProvider.kt @@ -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) + } } } } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirImportOptimizer.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirImportOptimizer.kt index fc271ca5963..74f0027e8bc 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirImportOptimizer.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirImportOptimizer.kt @@ -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 diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt index 31b4e053626..5d77634d4f7 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt @@ -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? { diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt index e51a6780a2d..d24691ecfa3 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt @@ -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) -> diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/contracts/firContractUtils.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/contracts/firContractUtils.kt index ab7d7f4b69f..bc8cbfe9cba 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/contracts/firContractUtils.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/contracts/firContractUtils.kt @@ -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.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, 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] ) diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirReceiverParameterSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirReceiverParameterSymbol.kt index 3d34753ffeb..db0cd3ca675 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirReceiverParameterSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirReceiverParameterSymbol.kt @@ -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) } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirValueParameterSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirValueParameterSymbol.kt index 624f24533da..2cfca827b34 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirValueParameterSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirValueParameterSymbol.kt @@ -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) diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/firSymbolUtils.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/firSymbolUtils.kt index 66b4b3436af..3a04baa3417 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/firSymbolUtils.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/firSymbolUtils.kt @@ -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 { diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/qualifiers/UsualClassTypeQualifierBuilder.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/qualifiers/UsualClassTypeQualifierBuilder.kt index 7ed9f81fc7d..806c9df2f3f 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/qualifiers/UsualClassTypeQualifierBuilder.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/qualifiers/UsualClassTypeQualifierBuilder.kt @@ -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) + } } } } \ No newline at end of file