From f45f1ba3dcfce091c6a0cd439e4b5cc852dce1f9 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Wed, 3 Aug 2022 10:46:16 +0200 Subject: [PATCH] [Analysis API] do not create multiple attachments inside exceptions --- .../api/fir/KtFirAnalysisSessionProvider.kt | 5 +- .../analysis/api/fir/KtSymbolByFirBuilder.kt | 24 +++--- .../api/fir/components/KtFirCallResolver.kt | 16 ++-- ...tFirSymbolContainingDeclarationProvider.kt | 12 +-- .../analysis/api/fir/symbols/KtFirSymbol.kt | 20 ++--- .../api/fir/symbols/KtFirSymbolProvider.kt | 25 +++--- .../api/fir/types/KtFirFunctionalType.kt | 4 +- .../api/fir/types/KtFirTypeParameterType.kt | 4 +- .../api/fir/types/KtFirUsualClassType.kt | 4 +- .../analysis/api/fir/utils/errorUtils.kt | 15 ++-- .../analysis/api/components/KtCallResolver.kt | 8 +- .../errors/ExceptionAttachmentBuilder.kt | 83 +++++++++++++++++++ .../kotlin/analysis/utils/errors/errors.kt | 33 -------- .../exceptionWithAttachmentBuilderHelpers.kt | 24 ++++++ .../utils/errors/unexpectedElementError.kt | 17 ++++ .../low/level/api/fir/FirDesignationState.kt | 4 +- .../level/api/fir/LLFirResolveStateService.kt | 6 +- .../api/fir/api/FirDeclarationDesignation.kt | 24 +++--- .../fir/api/InvalidFirElementTypeException.kt | 22 ++--- ...arationAndFirDeclarationEqualityChecker.kt | 8 +- .../LowLevelFirApiFacadeForResolveOnAir.kt | 22 ++--- .../resolve/FirLazyDeclarationResolver.kt | 16 ++-- .../LLFirFirClassByPsiClassProvider.kt | 44 +++++----- .../state/LLFirResolvableResolveSession.kt | 11 ++- ...irDeclarationForCompiledElementSearcher.kt | 49 ++++++----- .../api/fir/util/contrainingFileUtils.kt | 2 +- .../level/api/fir/util/declarationUtils.kt | 9 +- .../low/level/api/fir/util/exceptionUtils.kt | 52 +++++------- .../analysis/low/level/api/fir/util/utils.kt | 6 +- .../utils/KotlinExceptionWithAttachments.kt | 28 ------- 30 files changed, 319 insertions(+), 278 deletions(-) create mode 100644 analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/ExceptionAttachmentBuilder.kt delete mode 100644 analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/errors.kt create mode 100644 analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/exceptionWithAttachmentBuilderHelpers.kt create mode 100644 analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/unexpectedElementError.kt diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtFirAnalysisSessionProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtFirAnalysisSessionProvider.kt index 5d54a6f9652..b266cb24555 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtFirAnalysisSessionProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtFirAnalysisSessionProvider.kt @@ -15,10 +15,9 @@ import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getFirResolveSession -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.firErrorWithAttachment import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.utils.errorWithAttachment +import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment @OptIn(KtAnalysisApiInternals::class) class KtFirAnalysisSessionProvider(project: Project) : CachingKtAnalysisSessionProvider(project) { @@ -29,7 +28,7 @@ class KtFirAnalysisSessionProvider(project: Project) : CachingKtAnalysisSessionP override fun getFirResolveSession(contextSymbol: KtSymbol): LLFirResolveSession { return when (contextSymbol) { is KtFirSymbol<*> -> contextSymbol.firResolveSession - else -> errorWithAttachment("Invalid symbol") { + else -> buildErrorWithAttachment("Invalid symbol") { withSymbolAttachment("symbol", contextSymbol) } } 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 438da8d85b7..28d390a4919 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 @@ -20,10 +20,10 @@ import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.firErrorWithAttachment -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withConeTypeAttachment -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirAttachment -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirSymbolAttachment +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withConeTypeEntry +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirEntry +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirSymbolEntry import org.jetbrains.kotlin.analysis.providers.createPackageProvider import org.jetbrains.kotlin.builtins.functions.FunctionClassKind import org.jetbrains.kotlin.fir.* @@ -53,7 +53,7 @@ import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.types.Variance -import org.jetbrains.kotlin.utils.errorWithAttachment +import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract @@ -210,7 +210,7 @@ internal class KtSymbolByFirBuilder constructor( if (firSymbol.dispatchReceiverType?.contains { it is ConeStubType } == true) { return buildFunctionSymbol( firSymbol.originalIfFakeOverride() - ?: firErrorWithAttachment("Stub type in real declaration", fir = firSymbol.fir) + ?: errorWithFirSpecificEntries("Stub type in real declaration", fir = firSymbol.fir) ) } @@ -588,20 +588,20 @@ internal class KtSymbolByFirBuilder constructor( companion object { private fun throwUnexpectedElementError(element: FirBasedSymbol<*>): Nothing { - errorWithAttachment("Unexpected ${element::class.simpleName}") { - withFirSymbolAttachment("firSymbol", element) + buildErrorWithAttachment("Unexpected ${element::class.simpleName}") { + withFirSymbolEntry("firSymbol", element) } } private fun throwUnexpectedElementError(element: FirElement): Nothing { - errorWithAttachment("Unexpected ${element::class.simpleName}") { - withFirAttachment("firElement", element) + buildErrorWithAttachment("Unexpected ${element::class.simpleName}") { + withFirEntry("firElement", element) } } private fun throwUnexpectedElementError(element: ConeKotlinType): Nothing { - errorWithAttachment("Unexpected ${element::class.simpleName}") { - withConeTypeAttachment("coneType", element) + buildErrorWithAttachment("Unexpected ${element::class.simpleName}") { + withConeTypeEntry("coneType", element) } } 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 86af0d6f027..dbda1b43848 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 @@ -25,9 +25,8 @@ import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.AllCandidatesResolver -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.firErrorWithAttachment -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirAttachment -import org.jetbrains.kotlin.analysis.utils.errors.withPsiAttachment +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirEntry import org.jetbrains.kotlin.analysis.utils.printer.parentOfType import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol @@ -69,7 +68,8 @@ 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.errorWithAttachment +import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment +import org.jetbrains.kotlin.analysis.utils.errors.withPsiEntry internal class KtFirCallResolver( override val analysisSession: KtFirAnalysisSession, @@ -155,7 +155,7 @@ internal class KtFirCallResolver( when (val calleeReference = calleeReference) { is FirResolvedNamedReference -> { val call = createKtCall(psi, this, null, resolveFragmentOfCall) - ?: firErrorWithAttachment("expect `createKtCall` to succeed for resolvable case", fir = this, psi = psi) + ?: errorWithFirSpecificEntries("expect `createKtCall` to succeed for resolvable case", fir = this, psi = psi) KtSuccessCallInfo(call) } is FirErrorNamedReference -> { @@ -1167,9 +1167,9 @@ internal class KtFirCallResolver( } override fun unresolvedKtCallError(psi: KtElement): Nothing { - errorWithAttachment("${psi::class.simpleName}(${psi::class.simpleName}) should always resolve to a KtCallInfo") { - withPsiAttachment("psi", psi) - psi.getOrBuildFir(firResolveSession)?.let { withFirAttachment("fir", it) } + buildErrorWithAttachment("${psi::class.simpleName}(${psi::class.simpleName}) should always resolve to a KtCallInfo") { + withPsiEntry("psi", psi) + psi.getOrBuildFir(firResolveSession)?.let { withFirEntry("fir", it) } } } } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirSymbolContainingDeclarationProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirSymbolContainingDeclarationProvider.kt index 1fb6571ca0b..7f4f0e2718b 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirSymbolContainingDeclarationProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirSymbolContainingDeclarationProvider.kt @@ -23,7 +23,7 @@ import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.utils.printer.parentOfType import org.jetbrains.kotlin.psi import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.utils.errorWithAttachment +import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment internal class KtFirSymbolContainingDeclarationProvider( override val analysisSession: KtFirAnalysisSession, @@ -87,7 +87,7 @@ internal class KtFirSymbolContainingDeclarationProvider( private fun getContainingPsi(symbol: KtFirSymbol<*>): KtDeclaration { val source = symbol.firSymbol.source val thisSource = when (source?.kind) { - null -> errorWithAttachment("PSI should present for declaration built by Kotlin code") { + null -> buildErrorWithAttachment("PSI should present for declaration built by Kotlin code") { withSymbolAttachment("symbolForContainingPsi", symbol) } @@ -99,19 +99,19 @@ internal class KtFirSymbolContainingDeclarationProvider( KtFakeSourceElementKind.ItLambdaParameter -> return source.psi as KtFunctionLiteral KtRealSourceElementKind -> source.psi!! else -> - errorWithAttachment("errorWithAttachment FirSourceElement: kind=${source.kind} element=${source.psi!!::class.simpleName}") { + buildErrorWithAttachment("errorWithAttachment FirSourceElement: kind=${source.kind} element=${source.psi!!::class.simpleName}") { withSymbolAttachment("symbolForContainingPsi", symbol) } } return when (symbol.origin) { KtSymbolOrigin.SOURCE -> thisSource.getContainingKtDeclaration() - ?: errorWithAttachment("Containing declaration should present for non-toplevel declaration") { + ?: buildErrorWithAttachment("Containing declaration should present for non-toplevel declaration") { withSymbolAttachment("symbolForContainingPsi", symbol) } KtSymbolOrigin.SOURCE_MEMBER_GENERATED -> thisSource as KtDeclaration - else -> errorWithAttachment("Unsupported declaration origin ${symbol.origin}") { + else -> buildErrorWithAttachment("Unsupported declaration origin ${symbol.origin}") { withSymbolAttachment("symbolForContainingPsi", symbol) } } @@ -128,7 +128,7 @@ internal class KtFirSymbolContainingDeclarationProvider( check(symbol.symbolKind == KtSymbolKind.CLASS_MEMBER) fun error(message: String): Nothing { - errorWithAttachment(message) { + buildErrorWithAttachment(message) { withSymbolAttachment("symbolToGetContaining", symbol) } } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSymbol.kt index f02acaa160b..e11343e82b7 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSymbol.kt @@ -11,8 +11,8 @@ import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.firErrorWithAttachment -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirAttachment +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirEntry import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAcces import org.jetbrains.kotlin.fir.scopes.impl.importedFromObjectData import org.jetbrains.kotlin.fir.scopes.impl.originalForWrappedIntegerOperator import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol -import org.jetbrains.kotlin.utils.errorWithAttachment +import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment internal interface KtFirSymbol> : KtSymbol, KtLifetimeOwner { val firSymbol: S @@ -63,16 +63,16 @@ internal tailrec fun FirDeclaration.ktSymbolOrigin(): KtSymbolOrigin = when (ori is FirSyntheticProperty, is FirSyntheticPropertyAccessor -> KtSymbolOrigin.JAVA_SYNTHETIC_PROPERTY - else -> errorWithAttachment("Invalid FirDeclarationOrigin ${origin::class.simpleName}") { - withFirAttachment("firToGetOrigin", this@ktSymbolOrigin) + else -> buildErrorWithAttachment("Invalid FirDeclarationOrigin ${origin::class.simpleName}") { + withFirEntry("firToGetOrigin", this@ktSymbolOrigin) } } } FirDeclarationOrigin.ImportedFromObject -> { val importedFromObjectData = (this as FirCallableDeclaration).importedFromObjectData - ?: errorWithAttachment("Declaration has ImportedFromObject origin, but no importedFromObjectData present") { - withFirAttachment("firToGetOrigin", this@ktSymbolOrigin) + ?: buildErrorWithAttachment("Declaration has ImportedFromObject origin, but no importedFromObjectData present") { + withFirEntry("firToGetOrigin", this@ktSymbolOrigin) } importedFromObjectData.original.ktSymbolOrigin() @@ -80,7 +80,7 @@ internal tailrec fun FirDeclaration.ktSymbolOrigin(): KtSymbolOrigin = when (ori FirDeclarationOrigin.WrappedIntegerOperator -> { val original = (this as FirSimpleFunction).originalForWrappedIntegerOperator?.fir - ?: firErrorWithAttachment( + ?: errorWithFirSpecificEntries( "Declaration has WrappedIntegerOperator origin, but no originalForWrappedIntegerOperator present", fir = this ) @@ -91,7 +91,7 @@ internal tailrec fun FirDeclaration.ktSymbolOrigin(): KtSymbolOrigin = when (ori is FirDeclarationOrigin.Plugin -> KtSymbolOrigin.PLUGIN FirDeclarationOrigin.RenamedForOverride -> KtSymbolOrigin.JAVA FirDeclarationOrigin.SubstitutionOverride -> KtSymbolOrigin.SUBSTITUTION_OVERRIDE - FirDeclarationOrigin.DynamicScope -> errorWithAttachment("Invalid FirDeclarationOrigin ${origin::class.simpleName}") { - withFirAttachment("firToGetOrigin", this@ktSymbolOrigin) + FirDeclarationOrigin.DynamicScope -> buildErrorWithAttachment("Invalid FirDeclarationOrigin ${origin::class.simpleName}") { + withFirEntry("firToGetOrigin", this@ktSymbolOrigin) } } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSymbolProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSymbolProvider.kt index a49b2f8b7e5..b2f25ed823c 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSymbolProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSymbolProvider.kt @@ -10,21 +10,18 @@ import org.jetbrains.kotlin.analysis.api.fir.components.KtFirAnalysisSessionComp import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile import org.jetbrains.kotlin.analysis.low.level.api.fir.api.resolveToFirSymbolOfType -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.firErrorWithAttachment -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirSymbolAttachment -import org.jetbrains.kotlin.analysis.utils.errors.withPsiAttachment -import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirSymbolEntry import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass -import org.jetbrains.kotlin.fir.render -import org.jetbrains.kotlin.fir.renderWithType import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.utils.errorWithAttachment +import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment +import org.jetbrains.kotlin.analysis.utils.errors.withPsiEntry internal class KtFirSymbolProvider( override val analysisSession: KtFirAnalysisSession, @@ -33,7 +30,7 @@ internal class KtFirSymbolProvider( override fun getParameterSymbol(psi: KtParameter): KtVariableLikeSymbol { return when { - psi.isFunctionTypeParameter -> firErrorWithAttachment( + psi.isFunctionTypeParameter -> errorWithFirSpecificEntries( "Creating KtValueParameterSymbol for function type parameter is not possible. Please see the KDoc of getParameterSymbol", psi = psi, ) @@ -69,9 +66,9 @@ internal class KtFirSymbolProvider( } is FirAnonymousFunctionSymbol -> firSymbolBuilder.functionLikeBuilder.buildAnonymousFunctionSymbol(firSymbol) - else -> errorWithAttachment("Unexpected ${firSymbol::class}") { - withFirSymbolAttachment("firSymbol", firSymbol) - withPsiAttachment("function", psi) + else -> buildErrorWithAttachment("Unexpected ${firSymbol::class}") { + withFirSymbolEntry("firSymbol", firSymbol) + withPsiEntry("function", psi) } } } @@ -137,9 +134,9 @@ internal class KtFirSymbolProvider( private fun KtClassOrObject.resolveToFirClassLikeSymbol(): FirClassSymbol<*> { return when (val firClassLike = resolveToFirSymbolOfType>(firResolveSession)) { is FirTypeAliasSymbol -> firClassLike.fullyExpandedClass(firResolveSession.useSiteFirSession) - ?: errorWithAttachment("${firClassLike.fir::class} should be expanded to the expected type alias") { - withFirSymbolAttachment("firClassLikeSymbol", firClassLike) - withPsiAttachment("ktClassOrObject", this@resolveToFirClassLikeSymbol) + ?: buildErrorWithAttachment("${firClassLike.fir::class} should be expanded to the expected type alias") { + withFirSymbolEntry("firClassLikeSymbol", firClassLike) + withPsiEntry("ktClassOrObject", this@resolveToFirClassLikeSymbol) } is FirAnonymousObjectSymbol -> firClassLike is FirRegularClassSymbol -> firClassLike diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirFunctionalType.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirFunctionalType.kt index a39c6f94b0b..b9f05659502 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirFunctionalType.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirFunctionalType.kt @@ -17,7 +17,7 @@ import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol import org.jetbrains.kotlin.analysis.api.types.KtFunctionalType import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.firErrorWithAttachment +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.fir.types.isExtensionFunctionType import org.jetbrains.kotlin.fir.types.isSuspendFunctionType @@ -33,7 +33,7 @@ internal class KtFirFunctionalType( override val classId: ClassId get() = withValidityAssertion { coneType.lookupTag.classId } override val classSymbol: KtClassLikeSymbol by cached { builder.classifierBuilder.buildClassLikeSymbolByLookupTag(coneType.lookupTag) - ?: firErrorWithAttachment("Class was not found", coneType = coneType) + ?: errorWithFirSpecificEntries("Class was not found", coneType = coneType) } override val typeArguments: List by cached { coneType.typeArguments.map { typeArgument -> diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirTypeParameterType.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirTypeParameterType.kt index 4c7936e1d07..8dbbf68f64d 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirTypeParameterType.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirTypeParameterType.kt @@ -14,7 +14,7 @@ import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.analysis.api.symbols.KtTypeParameterSymbol import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability import org.jetbrains.kotlin.analysis.api.types.KtTypeParameterType -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.firErrorWithAttachment +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries import org.jetbrains.kotlin.fir.types.ConeTypeParameterType import org.jetbrains.kotlin.fir.types.renderForDebugging import org.jetbrains.kotlin.name.Name @@ -27,7 +27,7 @@ internal class KtFirTypeParameterType( override val name: Name get() = withValidityAssertion { coneType.lookupTag.name } override val symbol: KtTypeParameterSymbol by cached { builder.classifierBuilder.buildTypeParameterSymbolByLookupTag(coneType.lookupTag) - ?: firErrorWithAttachment("Type parameter was not found", coneType = coneType) + ?: errorWithFirSpecificEntries("Type parameter was not found", coneType = coneType) } override val annotationsList: KtAnnotationsList by cached { diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirUsualClassType.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirUsualClassType.kt index 06ea3552c39..878998cebac 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirUsualClassType.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirUsualClassType.kt @@ -15,7 +15,7 @@ import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability import org.jetbrains.kotlin.analysis.api.types.KtUsualClassType -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.firErrorWithAttachment +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.fir.types.renderForDebugging import org.jetbrains.kotlin.name.ClassId @@ -28,7 +28,7 @@ internal class KtFirUsualClassType( override val classId: ClassId get() = withValidityAssertion { coneType.lookupTag.classId } override val classSymbol: KtClassLikeSymbol by cached { builder.classifierBuilder.buildClassLikeSymbolByLookupTag(coneType.lookupTag) - ?: firErrorWithAttachment("Class was not found", coneType = coneType) + ?: errorWithFirSpecificEntries("Class was not found", coneType = coneType) } override val typeArguments: List by cached { coneType.typeArguments.map { typeArgument -> diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/utils/errorUtils.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/utils/errorUtils.kt index 81173cb2bbd..797e0d57c51 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/utils/errorUtils.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/utils/errorUtils.kt @@ -8,19 +8,18 @@ package org.jetbrains.kotlin.analysis.api.fir.utils import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol import org.jetbrains.kotlin.analysis.api.symbols.DebugSymbolRenderer import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirAttachment -import org.jetbrains.kotlin.analysis.utils.errors.withPsiAttachment +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirEntry +import org.jetbrains.kotlin.analysis.utils.errors.ExceptionAttachmentBuilder +import org.jetbrains.kotlin.analysis.utils.errors.withPsiEntry import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments -import org.jetbrains.kotlin.utils.withAttachmentDetailed -fun KotlinExceptionWithAttachments.withSymbolAttachment(name: String, symbol: KtSymbol): KotlinExceptionWithAttachments { - withAttachmentDetailed(name, symbol, DebugSymbolRenderer::render) - withPsiAttachment("${name}Psi", symbol.psi) +fun ExceptionAttachmentBuilder.withSymbolAttachment(name: String, symbol: KtSymbol) { + withEntry(name, symbol, DebugSymbolRenderer::render) + withPsiEntry("${name}Psi", symbol.psi) if (symbol is KtFirSymbol<*>) { val symbolFir = symbol.firSymbol.fir - withFirAttachment("${name}Fir", symbolFir) + withFirEntry("${name}Fir", symbolFir) } - return this } \ No newline at end of file diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtCallResolver.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtCallResolver.kt index 0a0c8c8d47a..ba8d1d0be4d 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtCallResolver.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtCallResolver.kt @@ -8,12 +8,12 @@ package org.jetbrains.kotlin.analysis.api.components import org.jetbrains.kotlin.analysis.api.calls.KtCallCandidateInfo import org.jetbrains.kotlin.analysis.api.calls.KtCallInfo import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion -import org.jetbrains.kotlin.analysis.utils.errors.withPsiAttachment +import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment +import org.jetbrains.kotlin.analysis.utils.errors.withPsiEntry import org.jetbrains.kotlin.psi.KtArrayAccessExpression import org.jetbrains.kotlin.psi.KtCallElement import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtUnaryExpression -import org.jetbrains.kotlin.utils.errorWithAttachment public abstract class KtCallResolver : KtAnalysisSessionComponent() { public abstract fun resolveCall(psi: KtElement): KtCallInfo? @@ -21,8 +21,8 @@ public abstract class KtCallResolver : KtAnalysisSessionComponent() { public abstract fun collectCallCandidates(psi: KtElement): List public open fun unresolvedKtCallError(psi: KtElement): Nothing { - errorWithAttachment("${psi::class.simpleName}(${psi::class.simpleName}) should always resolve to a KtCallInfo") { - withPsiAttachment("psi", psi) + buildErrorWithAttachment("${psi::class.simpleName}(${psi::class.simpleName}) should always resolve to a KtCallInfo") { + withPsiEntry("psi", psi) } } } diff --git a/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/ExceptionAttachmentBuilder.kt b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/ExceptionAttachmentBuilder.kt new file mode 100644 index 00000000000..ba1c7f1722f --- /dev/null +++ b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/ExceptionAttachmentBuilder.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2010-2022 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.utils.errors + +import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter +import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint +import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +public class ExceptionAttachmentBuilder { + private val printer = PrettyPrinter() + + public fun withEntry(name: String, value: T, render: (T & Any) -> String) { + withEntry(name) { + appendLine("Class: ${value?.let { it::class.java.name }}") + appendLine("Value:") + withIndent { + appendLine(value?.let(render) ?: "null") + } + } + } + + public fun withEntry(name: String, value: String?) { + with(printer) { + appendLine("- $name:") + withIndent { + appendLine(value) + } + appendLine(separator) + } + } + + public fun withEntry(name: String, buildValue: PrettyPrinter.() -> Unit) { + withEntry(name, prettyPrint { buildValue() }) + } + + public fun withEntryGroup(groupName: String, build: ExceptionAttachmentBuilder.() -> Unit) { + val builder = ExceptionAttachmentBuilder().apply(build) + withEntry(groupName, builder) { it.buildString() } + } + + public fun buildString(): String = printer.toString() + + private companion object { + private const val separator = "========" + } +} + +public inline fun KotlinExceptionWithAttachments.buildAttachment( + name: String = "info.txt", + buildContent: ExceptionAttachmentBuilder.() -> Unit +): KotlinExceptionWithAttachments { + return withAttachment(name, ExceptionAttachmentBuilder().apply(buildContent).buildString()) +} + +public inline fun buildErrorWithAttachment( + message: String, + cause: Throwable? = null, + attachmentName: String = "info.txt", + buildAttachment: ExceptionAttachmentBuilder.() -> Unit = {} +): Nothing { + val exception = KotlinExceptionWithAttachments(message, cause) + exception.buildAttachment(attachmentName) { buildAttachment() } + throw exception +} + + +@OptIn(ExperimentalContracts::class) +public inline fun checkWithAttachmentBuilder( + value: Boolean, + lazyMessage: () -> String, + buildAttachment: ExceptionAttachmentBuilder.() -> Unit = {} +) { + contract { returns() implies (value) } + + if (!value) { + buildErrorWithAttachment(lazyMessage(), buildAttachment = buildAttachment) + } +} diff --git a/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/errors.kt b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/errors.kt deleted file mode 100644 index f18c30dda8f..00000000000 --- a/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/errors.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2010-2022 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.utils.errors - -import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments -import org.jetbrains.kotlin.utils.errorWithAttachment -import org.jetbrains.kotlin.utils.withAttachmentDetailed - -public fun unexpectedElementError(elementName: String, element: Any?): Nothing { - errorWithAttachment("Unexpected $elementName ${element?.let { it::class.simpleName }}") { - withAttachment("element", element) - } -} - -public inline fun unexpectedElementError(element: Any?): Nothing { - unexpectedElementError(ELEMENT::class.simpleName ?: ELEMENT::class.java.name, element) -} - -public fun KotlinExceptionWithAttachments.withPsiAttachment(name: String, psi: PsiElement?): KotlinExceptionWithAttachments { - withAttachmentDetailed(name, psi) { psiElement -> - when (psiElement) { - is KtElement -> psiElement.getElementTextInContext() - else -> psiElement.text - } - } - return this -} \ No newline at end of file diff --git a/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/exceptionWithAttachmentBuilderHelpers.kt b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/exceptionWithAttachmentBuilderHelpers.kt new file mode 100644 index 00000000000..a39cd0b4cc4 --- /dev/null +++ b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/exceptionWithAttachmentBuilderHelpers.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2010-2022 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.utils.errors + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext +import org.jetbrains.kotlin.psi.KtElement + +public fun ExceptionAttachmentBuilder.withPsiEntry(name: String, psi: PsiElement?) { + withEntry(name, psi) { psiElement -> + when (psiElement) { + is KtElement -> psiElement.getElementTextInContext() + else -> psiElement.text + } + } +} + + +public fun ExceptionAttachmentBuilder.withClassEntry(name: String, element: Any?) { + withEntry(name, element) { it::class.java.name } +} \ No newline at end of file diff --git a/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/unexpectedElementError.kt b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/unexpectedElementError.kt new file mode 100644 index 00000000000..36c6d57f201 --- /dev/null +++ b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/unexpectedElementError.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2010-2022 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.utils.errors + +public fun unexpectedElementError(elementName: String, element: Any?): Nothing { + buildErrorWithAttachment("Unexpected $elementName ${element?.let { it::class.simpleName }}") { + withEntry(elementName, element) { element.toString() } + } +} + +public inline fun unexpectedElementError(element: Any?): Nothing { + unexpectedElementError(ELEMENT::class.simpleName ?: ELEMENT::class.java.name, element) +} + diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirDesignationState.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirDesignationState.kt index ed65095c606..f2a4ee3ea8b 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirDesignationState.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirDesignationState.kt @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignation -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.firErrorWithAttachment +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries abstract class ContextByDesignationCollector(private val designation: FirDeclarationDesignation) { private var context: C? = null @@ -57,7 +57,7 @@ private class FirDesignationState(val designation: FirDeclarationDesignation) { val currentDeclaration: FirDeclaration get() = currentDeclarationIfPresent - ?: firErrorWithAttachment("Went inside target declaration") + ?: errorWithFirSpecificEntries("Went inside target declaration") fun goNext() { if (canGoNext()) { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveStateService.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveStateService.kt index 48e9b925380..c8c66a97b0e 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveStateService.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveStateService.kt @@ -16,7 +16,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirLibraryOrLibra import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirNotUnderContentRootResolvableResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirSourceResolveSession -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.firErrorWithAttachment +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries import org.jetbrains.kotlin.analysis.project.structure.* import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker import org.jetbrains.kotlin.analysis.utils.caches.strongCachedValue @@ -87,8 +87,8 @@ internal class LLFirResolveSessionService(project: Project) { } else -> { - firErrorWithAttachment("Unexpected ${useSiteKtModule::class.java}") { - withAttachment("module", useSiteKtModule.moduleDescription) + errorWithFirSpecificEntries("Unexpected ${useSiteKtModule::class.java}") { + withEntry("module", useSiteKtModule) { it.moduleDescription } } } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirDeclarationDesignation.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirDeclarationDesignation.kt index 2653577abea..657669f098b 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirDeclarationDesignation.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirDeclarationDesignation.kt @@ -5,21 +5,19 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.api -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.firErrorWithAttachment import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getContainingFile -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirAttachment +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirEntry import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.containingClass import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.classId import org.jetbrains.kotlin.fir.declarations.utils.isLocal -import org.jetbrains.kotlin.fir.renderWithType import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLookupTagWithFixedSymbol -import org.jetbrains.kotlin.utils.checkWithAttachment -import org.jetbrains.kotlin.utils.errorWithAttachment +import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment +import org.jetbrains.kotlin.analysis.utils.errors.checkWithAttachmentBuilder class FirDeclarationDesignationWithFile( path: List, @@ -80,8 +78,8 @@ private fun collectDesignationPath(declaration: FirDeclaration): List return null } ?: return emptyList() - checkWithAttachment(containingClass is FirRegularClass, { "FirRegularClass as containing declaration expected" }) { - it.withFirAttachment("containingClassFir", containingClass) + checkWithAttachmentBuilder(containingClass is FirRegularClass, { "FirRegularClass as containing declaration expected" }) { + withFirEntry("containingClassFir", containingClass) } return if (!containingClass.isLocal) containingClass.collectForNonLocal().asReversed() else null } @@ -92,20 +90,20 @@ private fun ConeClassLikeLookupTag.toFirRegularClassFromSameSession(useSiteSessi } fun FirDeclaration.collectDesignation(firFile: FirFile): FirDeclarationDesignationWithFile = - tryCollectDesignation(firFile) ?: errorWithAttachment("No designation of local declaration") { - withFirAttachment("firFile", firFile) + tryCollectDesignation(firFile) ?: buildErrorWithAttachment("No designation of local declaration") { + withFirEntry("firFile", firFile) } fun FirDeclaration.collectDesignation(): FirDeclarationDesignation = tryCollectDesignation() - ?: errorWithAttachment("No designation of local declaration") { - withFirAttachment("FirDeclaration", this@collectDesignation) + ?: buildErrorWithAttachment("No designation of local declaration") { + withFirEntry("FirDeclaration", this@collectDesignation) } fun FirDeclaration.collectDesignationWithFile(): FirDeclarationDesignationWithFile = tryCollectDesignationWithFile() - ?: errorWithAttachment("No designation of local declaration") { - withFirAttachment("FirDeclaration", this@collectDesignationWithFile) + ?: buildErrorWithAttachment("No designation of local declaration") { + withFirEntry("FirDeclaration", this@collectDesignationWithFile) } fun FirDeclaration.tryCollectDesignation(firFile: FirFile): FirDeclarationDesignationWithFile? = diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/InvalidFirElementTypeException.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/InvalidFirElementTypeException.kt index 68421bde361..0e7a9c27042 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/InvalidFirElementTypeException.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/InvalidFirElementTypeException.kt @@ -5,15 +5,15 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.api -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withConeTypeAttachment -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirAttachment -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirSymbolAttachment +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withConeTypeEntry +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirEntry +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirSymbolEntry import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments -import org.jetbrains.kotlin.utils.withAttachmentDetailed +import org.jetbrains.kotlin.analysis.utils.errors.* import java.util.* import kotlin.reflect.KClass @@ -23,12 +23,14 @@ class InvalidFirElementTypeException( expectedFirClasses: List>, ) : KotlinExceptionWithAttachments("") { init { - when (actualFirElement) { - is FirElement -> withFirAttachment("firElement", actualFirElement) - is FirBasedSymbol<*> -> withFirSymbolAttachment("firSymbol", actualFirElement) - is ConeKotlinType -> withConeTypeAttachment("coneType", actualFirElement) - null -> {} - else -> withAttachmentDetailed("element", actualFirElement) { it.toString() } + buildAttachment { + when (actualFirElement) { + is FirElement -> withFirEntry("firElement", actualFirElement) + is FirBasedSymbol<*> -> withFirSymbolEntry("firSymbol", actualFirElement) + is ConeKotlinType -> withConeTypeEntry("coneType", actualFirElement) + null -> {} + else -> withEntry("element", actualFirElement) { it.toString() } + } } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/KtDeclarationAndFirDeclarationEqualityChecker.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/KtDeclarationAndFirDeclarationEqualityChecker.kt index da9d7f2065e..17384fb4882 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/KtDeclarationAndFirDeclarationEqualityChecker.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/KtDeclarationAndFirDeclarationEqualityChecker.kt @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.api import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.createEmptySession -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.firErrorWithAttachment +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.builder.BodyBuildingMode @@ -133,7 +133,7 @@ object KtDeclarationAndFirDeclarationEqualityChecker { } } } - else -> firErrorWithAttachment("Invalid type reference", fir = this) + else -> errorWithFirSpecificEntries("Invalid type reference", fir = this) } return if (isVararg) { rendered.asArrayType() @@ -166,7 +166,7 @@ object KtDeclarationAndFirDeclarationEqualityChecker { } append(typeRef.renderTypeAsKotlinType()) } - else -> firErrorWithAttachment("Invalid type reference", fir = this) + else -> errorWithFirSpecificEntries("Invalid type reference", fir = this) } private fun isTheSameTypes( @@ -201,7 +201,7 @@ object KtDeclarationAndFirDeclarationEqualityChecker { // Can be present as return type "${lowerBound.renderTypeAsKotlinType()}..${upperBound.renderTypeAsKotlinType()}" } - else -> firErrorWithAttachment("Type should not be present in Kotlin declaration", coneType = this) + else -> errorWithFirSpecificEntries("Type should not be present in Kotlin declaration", coneType = this) }.replace('/', '.') return rendered + nullability.suffix } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacadeForResolveOnAir.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacadeForResolveOnAir.kt index 849f5df2450..0d177c7f271 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacadeForResolveOnAir.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacadeForResolveOnAir.kt @@ -19,10 +19,9 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.* import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirResolvableModuleSession import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirResolvableSession import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirSession -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.firErrorWithAttachment +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalDeclaration import org.jetbrains.kotlin.analysis.project.structure.getKtModule -import org.jetbrains.kotlin.analysis.utils.errors.withPsiAttachment import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext import org.jetbrains.kotlin.analysis.utils.printer.parentOfType import org.jetbrains.kotlin.analysis.utils.printer.parentsOfType @@ -40,7 +39,8 @@ import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.isAncestor -import org.jetbrains.kotlin.utils.errorWithAttachment +import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment +import org.jetbrains.kotlin.analysis.utils.errors.* object LowLevelFirApiFacadeForResolveOnAir { @@ -91,9 +91,9 @@ object LowLevelFirApiFacadeForResolveOnAir { } declaration.accept(expressionLocator) - return expressionLocator.result ?: firErrorWithAttachment("Resolved on-air element was not found in containing declaration") { - withPsiAttachment("place", place) - withPsiAttachment("elementToResolve", elementToResolve) + return expressionLocator.result ?: errorWithFirSpecificEntries("Resolved on-air element was not found in containing declaration") { + withPsiEntry("place", place) + withPsiEntry("elementToResolve", elementToResolve) } } @@ -159,9 +159,9 @@ object LowLevelFirApiFacadeForResolveOnAir { val sameDeclarationInOriginalFile = PsiTreeUtil.findSameElementInCopy(dependencyNonLocalDeclaration, originalKtFile) - ?: firErrorWithAttachment("Cannot find original function matching") { - withPsiAttachment("matchingPsi", dependencyNonLocalDeclaration) - withPsiAttachment("originalFile", originalKtFile) + ?: buildErrorWithAttachment("Cannot find original function matching") { + withPsiEntry("matchingPsi", dependencyNonLocalDeclaration) + withPsiEntry("originalFile", originalKtFile) } recordOriginalDeclaration( @@ -194,8 +194,8 @@ object LowLevelFirApiFacadeForResolveOnAir { replacement = replacement ) val llFirResolvableSession = firFile.llFirResolvableSession - ?: errorWithAttachment("FirFile session expected to be a resolvable session but was ${firFile.llFirSession::class.java}") { - withAttachment("firSession", firFile.llFirSession) + ?: buildErrorWithAttachment("FirFile session expected to be a resolvable session but was ${firFile.llFirSession::class.java}") { + withEntry("firSession", firFile.llFirSession) { it.toString() } } val declarationResolver = llFirResolvableSession.moduleComponents.lazyFirDeclarationsResolver diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyDeclarationResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyDeclarationResolver.kt index cfaf92a2232..48061dad70b 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyDeclarationResolver.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyDeclarationResolver.kt @@ -19,7 +19,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LLFirFirProv import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LazyTransformerFactory import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkCanceled import org.jetbrains.kotlin.analysis.low.level.api.fir.util.findSourceNonLocalFirDeclaration -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirAttachment +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirEntry import org.jetbrains.kotlin.analysis.utils.errors.shouldIjPlatformExceptionBeRethrown import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.declarations.* @@ -33,8 +33,8 @@ import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataCo import org.jetbrains.kotlin.psi.KtClassBody import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtEnumEntry -import org.jetbrains.kotlin.utils.errorWithAttachment -import org.jetbrains.kotlin.utils.withAttachmentDetailed +import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment +import org.jetbrains.kotlin.analysis.utils.errors.* internal class FirLazyDeclarationResolver(val moduleComponents: LLFirModuleResolveComponents) { /** @@ -430,7 +430,7 @@ private fun rethrowWithDetails( toPhase: FirResolvePhase? ): Nothing { if (shouldIjPlatformExceptionBeRethrown(e)) throw e - errorWithAttachment( + buildErrorWithAttachment( buildString { val moduleData = firDeclarationToResolve.llFirModuleData appendLine("Error while resolving ${firDeclarationToResolve::class.java.name} ") @@ -444,10 +444,10 @@ private fun rethrowWithDetails( }, cause = e, ) { - withAttachmentDetailed("KtModule", firDeclarationToResolve.llFirModuleData.ktModule) { it.moduleDescription } - withAttachmentDetailed("session", firDeclarationToResolve.llFirSession) { it.toString() } - withAttachmentDetailed("moduleData", firDeclarationToResolve.moduleData) { it.toString() } - withFirAttachment("firDeclarationToResolve", firDeclarationToResolve) + withEntry("KtModule", firDeclarationToResolve.llFirModuleData.ktModule) { it.moduleDescription } + withEntry("session", firDeclarationToResolve.llFirSession) { it.toString() } + withEntry("moduleData", firDeclarationToResolve.moduleData) { it.toString() } + withFirEntry("firDeclarationToResolve", firDeclarationToResolve) } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirFirClassByPsiClassProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirFirClassByPsiClassProvider.kt index 280af4f14e8..e21a080e04f 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirFirClassByPsiClassProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirFirClassByPsiClassProvider.kt @@ -7,11 +7,10 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.providers import com.intellij.psi.PsiClass import com.intellij.psi.PsiClassOwner -import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiTypeParameter import com.intellij.psi.impl.compiled.ClsElementImpl import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession -import org.jetbrains.kotlin.analysis.utils.errors.withPsiAttachment +import org.jetbrains.kotlin.analysis.utils.errors.* import org.jetbrains.kotlin.asJava.KtLightClassMarker import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSessionComponent @@ -22,9 +21,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.utils.checkWithAttachment -import org.jetbrains.kotlin.utils.errorWithAttachment -import org.jetbrains.kotlin.utils.withAttachmentBuilder class LLFirFirClassByPsiClassProvider(private val session: LLFirSession) : FirSessionComponent { fun getFirClass(psiClass: PsiClass): FirRegularClassSymbol? { @@ -36,16 +32,13 @@ class LLFirFirClassByPsiClassProvider(private val session: LLFirSession) : FirSe "${LLFirFirClassByPsiClassProvider::class.simpleName} can create only non-kotlin classes" } - checkWithAttachment( + checkWithAttachmentBuilder( psiClass !is ClsElementImpl || !psiClass.hasAnnotation(JvmAnnotationNames.METADATA_FQ_NAME.asString()), { "${LLFirFirClassByPsiClassProvider::class.simpleName} can create only non-kotlin classes, but got ${psiClass::class} with ${JvmAnnotationNames.METADATA_FQ_NAME.asString()} annotation" } ) { - it.withAttachmentBuilder("psiClass") { - appendLine("file: ${psiClass.containingFile?.virtualFile?.path}") - appendLine("PsiClass:") - appendLine(psiClass.text) - } + withEntry("virtualFilePath", psiClass.containingFile.virtualFile?.path) + withPsiEntry("psiClass", psiClass) } if (psiClass.qualifiedName == null) { @@ -53,18 +46,21 @@ class LLFirFirClassByPsiClassProvider(private val session: LLFirSession) : FirSe } val firClassSymbol = createFirClassFromFirProvider(psiClass) - checkWithAttachment( - firClassSymbol.fir.psi == psiClass, + val gotPsi = firClassSymbol.fir.psi + checkWithAttachmentBuilder( + gotPsi == psiClass, { "resulted FirClass.psi != requested PsiClass" } ) { - it.withAttachmentBuilder("info") { - appendLine("Requested ${psiClass::class.java.name}:") - appendLine("path: ${psiClass.containingFile?.virtualFile?.path}") - appendLine("modificationStamp: ${psiClass.containingFile.modificationStamp}") - appendLine() - appendLine("Got ${firClassSymbol.fir.psi!!::class.java.name}") - appendLine("path: ${firClassSymbol.fir.psi?.containingFile?.virtualFile?.path}") - appendLine("modificationStamp: ${firClassSymbol.fir.psi?.containingFile?.modificationStamp}") + withEntryGroup("Requested") { + withClassEntry("psiElementClass", psiClass) + withEntry("path", psiClass.containingFile?.virtualFile?.path) + withEntry("modificationStamp", psiClass.containingFile.modificationStamp.toString()) + } + + withEntryGroup("Got") { + withClassEntry("psiElementClass", gotPsi) + withEntry("path", gotPsi?.containingFile?.virtualFile?.path) + withEntry("modificationStamp", gotPsi?.containingFile?.modificationStamp.toString()) } } return firClassSymbol @@ -75,9 +71,9 @@ class LLFirFirClassByPsiClassProvider(private val session: LLFirSession) : FirSe ?: error("No classId for non-local class") val provider = session.nullableJavaSymbolProvider ?: session.symbolProvider val symbol = provider.getClassLikeSymbolByClassId(classId) - ?: errorWithAttachment("No classifier found") { - withPsiAttachment("psiClass", psiClass) - withAttachment("classId", classId.asString()) + ?: buildErrorWithAttachment("No classifier found") { + withPsiEntry("psiClass", psiClass) + withEntry("classId", classId) { it.asString() } } return symbol as FirRegularClassSymbol } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirResolvableResolveSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirResolvableResolveSession.kt index eb40ba3a592..f44193ea143 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirResolvableResolveSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirResolvableResolveSession.kt @@ -21,7 +21,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalDeclaration import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.getKtModule import org.jetbrains.kotlin.analysis.utils.errors.requireIsInstance -import org.jetbrains.kotlin.analysis.utils.errors.withPsiAttachment import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession @@ -35,8 +34,8 @@ import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.utils.errorWithAttachment -import org.jetbrains.kotlin.utils.withAttachmentDetailed +import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment +import org.jetbrains.kotlin.analysis.utils.errors.* internal abstract class LLFirResolvableResolveSession( private val sessionProvider: LLFirSessionProvider, @@ -103,9 +102,9 @@ internal abstract class LLFirResolvableResolveSession( "Declaration should be resolvable module, instead it had ${module::class}" } val nonLocalNamedDeclaration = ktDeclaration.getNonLocalContainingOrThisDeclaration() - ?: errorWithAttachment("Declaration should have non-local container") { - withPsiAttachment("ktDeclaration", ktDeclaration) - withAttachmentDetailed("module", module) { it.moduleDescription } + ?: buildErrorWithAttachment("Declaration should have non-local container") { + withPsiEntry("ktDeclaration", ktDeclaration) + withEntry("module", module) { it.moduleDescription } } if (ktDeclaration == nonLocalNamedDeclaration) { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/FirDeclarationForCompiledElementSearcher.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/FirDeclarationForCompiledElementSearcher.kt index 8794f9dbe84..0383c59cae9 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/FirDeclarationForCompiledElementSearcher.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/FirDeclarationForCompiledElementSearcher.kt @@ -7,7 +7,8 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.util import org.jetbrains.kotlin.analysis.low.level.api.fir.api.KtDeclarationAndFirDeclarationEqualityChecker import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirModuleData -import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext +import org.jetbrains.kotlin.analysis.utils.errors.ExceptionAttachmentBuilder +import org.jetbrains.kotlin.analysis.utils.errors.withClassEntry import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredConstructors @@ -19,8 +20,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject -import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments -import org.jetbrains.kotlin.utils.withAttachmentBuilder /** * Allows to search for FIR declarations by compiled [KtDeclaration]s. @@ -34,17 +33,17 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid is KtNamedFunction -> findNonLocalFunction(ktDeclaration) is KtProperty -> findNonLocalProperty(ktDeclaration) - else -> firErrorWithAttachment("Unsupported compiled declaration of type", psi = ktDeclaration) + else -> errorWithFirSpecificEntries("Unsupported compiled declaration of type", psi = ktDeclaration) } } private fun findNonLocalEnumEntry(declaration: KtEnumEntry): FirEnumEntry { require(!declaration.isLocal) val classId = declaration.containingClassOrObject?.getClassId() - ?: firErrorWithAttachment("Non-local class should have classId", psi = declaration) + ?: errorWithFirSpecificEntries("Non-local class should have classId", psi = declaration) val classCandidate = symbolProvider.getClassLikeSymbolByClassId(classId) - ?: firErrorWithAttachment("We should be able to find a symbol for $classId", psi = declaration) + ?: errorWithFirSpecificEntries("We should be able to find a symbol for $classId", psi = declaration) return (classCandidate.fir as? FirRegularClass)?.declarations?.first { it is FirEnumEntry && it.name == declaration.nameAsName @@ -53,11 +52,11 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid private fun findNonLocalClassLikeDeclaration(declaration: KtClassLikeDeclaration): FirClassLikeDeclaration { val classId = declaration.getClassId() - ?: firErrorWithAttachment("Non-local class should have classId", psi = declaration) + ?: errorWithFirSpecificEntries("Non-local class should have classId", psi = declaration) val classCandidate = symbolProvider.getClassLikeSymbolByClassId(classId) - ?: firErrorWithAttachment("We should be able to find a symbol for $classId", psi = declaration) { - withAttachment("classId", classId.asString()) + ?: errorWithFirSpecificEntries("We should be able to find a symbol for $classId", psi = declaration) { + withEntry("classId", classId) { it.asString() } } return classCandidate.fir @@ -65,16 +64,16 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid private fun findConstructorOfNonLocalClass(declaration: KtConstructor<*>): FirConstructor { val containingClass = declaration.containingClassOrObject - ?: firErrorWithAttachment("Constructor must have outer class", psi = declaration) + ?: errorWithFirSpecificEntries("Constructor must have outer class", psi = declaration) require(!containingClass.isLocal) val classId = containingClass.getClassId() - ?: firErrorWithAttachment("Non-local class should have classId", psi = declaration) + ?: errorWithFirSpecificEntries("Non-local class should have classId", psi = declaration) val constructorCandidate = symbolProvider.getClassDeclaredConstructors(classId) .singleOrNull { representSameConstructor(declaration, it.fir) } - ?: firErrorWithAttachment("We should be able to find a constructor", psi = declaration) + ?: errorWithFirSpecificEntries("We should be able to find a constructor", psi = declaration) return constructorCandidate.fir } @@ -86,7 +85,7 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid val functionCandidate = candidates .singleOrNull { KtDeclarationAndFirDeclarationEqualityChecker.representsTheSameDeclaration(declaration, it.fir) } - ?: firErrorWithAttachment("We should be able to find a symbol for function", psi = declaration) { + ?: errorWithFirSpecificEntries("We should be able to find a symbol for function", psi = declaration) { withCandidates(candidates) } @@ -100,7 +99,7 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid val candidates = symbolProvider.findPropertyCandidates(declaration) val propertyCandidate = candidates.singleOrNull { KtDeclarationAndFirDeclarationEqualityChecker.representsTheSameDeclaration(declaration, it.fir) } - ?: firErrorWithAttachment("We should be able to find a symbol for property", psi = declaration) { + ?: errorWithFirSpecificEntries("We should be able to find a symbol for property", psi = declaration) { withCandidates(candidates) } @@ -124,7 +123,7 @@ private fun FirSymbolProvider.findCallableCandidates( } val containerClassId = declaration.containingClassOrObject?.getClassId() - ?: firErrorWithAttachment("No containing non-local declaration found for", psi = declaration) + ?: errorWithFirSpecificEntries("No containing non-local declaration found for", psi = declaration) return getClassDeclaredFunctionSymbols(containerClassId, declaration.nameAsSafeName) + getClassDeclaredPropertySymbols(containerClassId, declaration.nameAsSafeName) @@ -138,16 +137,16 @@ private fun representSameConstructor(psiConstructor: KtConstructor<*>, firConstr return KtDeclarationAndFirDeclarationEqualityChecker.representsTheSameDeclaration(psiConstructor, firConstructor) } -private fun KotlinExceptionWithAttachments.withCandidates(candidates: List>) { - withAttachmentBuilder("candidates") { - appendLine("Candidates count ${candidates.size}") - for ((index, candidate) in candidates.withIndex()) { - appendLine("Candidate $index, ${candidate::class.java}") - val ktModule = candidate.llFirModuleData.ktModule - appendLine("From ${ktModule::class.java} ${ktModule.moduleDescription}") - appendLine("Origin ${candidate.origin}") - appendLine(debugFirRenderer.renderElementAsString(candidate.fir)) - appendLine() +private fun ExceptionAttachmentBuilder.withCandidates(candidates: List>) { + withEntry("Candidates count", candidates.size.toString()) + for ((index, candidate) in candidates.withIndex()) { + val ktModule = candidate.llFirModuleData.ktModule + withEntryGroup(index.toString()) { + withClassEntry("candidateClass", candidate) + withEntry("module", ktModule) { it.moduleDescription } + withEntry("origin", candidate.origin.toString()) + withFirEntry("candidateFir", candidate.fir) + } } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/contrainingFileUtils.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/contrainingFileUtils.kt index 77edf29ce30..751cb8fc8db 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/contrainingFileUtils.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/contrainingFileUtils.kt @@ -17,6 +17,6 @@ fun FirDeclaration.getContainingFile(): FirFile? { is FirFile -> this is FirCallableDeclaration -> provider.getFirCallableContainerFile(symbol) is FirClassLikeDeclaration -> provider.getFirClassifierContainerFile(symbol) - else -> firErrorWithAttachment("Unsupported declaration ${this::class.java}", fir = this) + else -> errorWithFirSpecificEntries("Unsupported declaration ${this::class.java}", fir = this) } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/declarationUtils.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/declarationUtils.kt index 6c49b9c0dc6..d17c585899b 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/declarationUtils.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/declarationUtils.kt @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.util import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLocalContainingOrThisDeclaration import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirFileBuilder -import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirFile @@ -30,7 +29,7 @@ internal fun KtDeclaration.findSourceNonLocalFirDeclaration( //TODO test what way faster findSourceNonLocalFirDeclarationByProvider(firFileBuilder, provider, containerFirFile)?.let { return it } findSourceOfNonLocalFirDeclarationByTraversingWholeTree(firFileBuilder, containerFirFile)?.let { return it } - firErrorWithAttachment("No fir element was found for", psi = this) + errorWithFirSpecificEntries("No fir element was found for", psi = this) } internal fun KtDeclaration.findFirDeclarationForAnyFirSourceDeclaration( @@ -45,7 +44,7 @@ internal fun KtDeclaration.findFirDeclarationForAnyFirSourceDeclaration( firDeclaration.psi == this || firDeclaration.psi == originalDeclaration } return fir - ?: firErrorWithAttachment("FirDeclaration was not found", psi = this) + ?: errorWithFirSpecificEntries("FirDeclaration was not found", psi = this) } internal inline fun KtDeclaration.findFirDeclarationForAnyFirSourceDeclarationOfType( @@ -95,12 +94,12 @@ private fun KtDeclaration.findSourceNonLocalFirDeclarationByProvider( } this is KtConstructor<*> -> { val containingClass = containingClassOrObject - ?: firErrorWithAttachment("Container class should be not null for KtConstructor", psi = this) + ?: errorWithFirSpecificEntries("Container class should be not null for KtConstructor", psi = this) val containerClassFir = containingClass.findFir(provider) as? FirRegularClass ?: return null containerClassFir.declarations.firstOrNull { it.psi === this } } this is KtTypeAlias -> findFir(provider) - else -> firErrorWithAttachment("Invalid container", psi = this) + else -> errorWithFirSpecificEntries("Invalid container", psi = this) } return candidate?.takeIf { it.realPsi == this } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/exceptionUtils.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/exceptionUtils.kt index 8c4dc426cd0..75ee4276e72 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/exceptionUtils.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/exceptionUtils.kt @@ -6,8 +6,9 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.util import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.analysis.utils.errors.withPsiAttachment -import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext +import org.jetbrains.kotlin.analysis.utils.errors.ExceptionAttachmentBuilder +import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment +import org.jetbrains.kotlin.analysis.utils.errors.withPsiEntry import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.renderer.ConeTypeRendererForDebugging @@ -16,58 +17,49 @@ import org.jetbrains.kotlin.fir.renderer.FirRenderer import org.jetbrains.kotlin.fir.renderer.FirResolvePhaseRenderer import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments -import org.jetbrains.kotlin.utils.errorWithAttachment -import org.jetbrains.kotlin.utils.withAttachmentDetailed -fun KotlinExceptionWithAttachments.withFirAttachment(name: String, fir: FirElement): KotlinExceptionWithAttachments { - withAttachmentDetailed(name, fir, debugFirRenderer::renderElementAsString) - withPsiAttachment("${name}Psi", fir.psi) - return this +fun ExceptionAttachmentBuilder.withFirEntry(name: String, fir: FirElement) { + withEntry(name, fir) { + FirRenderer( + resolvePhaseRenderer = FirResolvePhaseRenderer(), + declarationRenderer = FirDeclarationRendererWithAttributes() + ).renderElementAsString(it) + } + withPsiEntry("${name}Psi", fir.psi) } -fun KotlinExceptionWithAttachments.withFirSymbolAttachment(name: String, symbol: FirBasedSymbol<*>): KotlinExceptionWithAttachments { - withAttachment("${name}Class", symbol::class.java.name) - withFirAttachment("${name}Fir", symbol.fir) - return this +fun ExceptionAttachmentBuilder.withFirSymbolEntry(name: String, symbol: FirBasedSymbol<*>) { + withFirEntry("${name}Fir", symbol.fir) } -fun KotlinExceptionWithAttachments.withConeTypeAttachment(name: String, coneType: ConeKotlinType): KotlinExceptionWithAttachments { - withAttachmentDetailed(name, coneType) { +fun ExceptionAttachmentBuilder.withConeTypeEntry(name: String, coneType: ConeKotlinType) { + withEntry(name, coneType) { buildString { ConeTypeRendererForDebugging(this).render(it) } } - return this } - - -fun firErrorWithAttachment( +fun errorWithFirSpecificEntries( message: String, cause: Throwable? = null, fir: FirElement? = null, coneType: ConeKotlinType? = null, psi: PsiElement? = null, - attachments: KotlinExceptionWithAttachments.() -> Unit = {} + additionalInfos: ExceptionAttachmentBuilder.() -> Unit = {} ): Nothing { - errorWithAttachment(message, cause) { + buildErrorWithAttachment(message, cause) { if (fir != null) { - withFirAttachment("fir", fir) + withFirEntry("fir", fir) } if (psi != null) { - withPsiAttachment("psi", psi) + withPsiEntry("psi", psi) } if (coneType != null) { - withConeTypeAttachment("coneType", coneType) + withConeTypeEntry("coneType", coneType) } - attachments () + additionalInfos() } } - - -val debugFirRenderer = - FirRenderer(resolvePhaseRenderer = FirResolvePhaseRenderer(), declarationRenderer = FirDeclarationRendererWithAttributes()) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/utils.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/utils.kt index 913ebfc06ae..604916c3d73 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/utils.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/utils.kt @@ -7,12 +7,10 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.util import com.intellij.openapi.progress.ProgressManager import com.intellij.psi.util.* -import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.diagnostics.FirDiagnosticHolder import org.jetbrains.kotlin.fir.psi -import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral import java.util.concurrent.TimeUnit @@ -54,11 +52,11 @@ internal val FirElement.isErrorElement internal val FirDeclaration.ktDeclaration: KtDeclaration get() { val psi = psi - ?: firErrorWithAttachment("PSI element was not found", fir = this) + ?: errorWithFirSpecificEntries("PSI element was not found", fir = this) return when (psi) { is KtDeclaration -> psi is KtObjectLiteralExpression -> psi.objectDeclaration - else -> firErrorWithAttachment( + else -> errorWithFirSpecificEntries( "FirDeclaration.psi (${this::class.simpleName}) should be KtDeclaration but was ${psi::class.simpleName}", fir = this, psi = psi, diff --git a/compiler/util/src/org/jetbrains/kotlin/utils/KotlinExceptionWithAttachments.kt b/compiler/util/src/org/jetbrains/kotlin/utils/KotlinExceptionWithAttachments.kt index e2bc33f39be..9f4a0ea1a5a 100644 --- a/compiler/util/src/org/jetbrains/kotlin/utils/KotlinExceptionWithAttachments.kt +++ b/compiler/util/src/org/jetbrains/kotlin/utils/KotlinExceptionWithAttachments.kt @@ -41,23 +41,6 @@ open class KotlinExceptionWithAttachments : RuntimeException, ExceptionWithAttac } -fun KotlinExceptionWithAttachments.withAttachmentBuilder( - name: String, - buildContent: StringBuilder.() -> Unit -): KotlinExceptionWithAttachments { - return withAttachment(name, buildString { buildContent() }) -} - -fun KotlinExceptionWithAttachments.withAttachmentDetailed( - name: String, - content: T?, - render: (T) -> String -): KotlinExceptionWithAttachments { - withAttachment("${name}Class", content?.let { it::class.java.name }) - withAttachment(name, content?.let(render)) - return this -} - @OptIn(ExperimentalContracts::class) inline fun checkWithAttachment(value: Boolean, lazyMessage: () -> String, attachments: (KotlinExceptionWithAttachments) -> Unit = {}) { contract { returns() implies (value) } @@ -68,14 +51,3 @@ inline fun checkWithAttachment(value: Boolean, lazyMessage: () -> String, attach throw e } } - -inline fun errorWithAttachment( - message: String, - cause: Throwable? = null, - attachments: KotlinExceptionWithAttachments.() -> Unit = {} -): Nothing { - val exception = KotlinExceptionWithAttachments(message, cause) - attachments(exception) - throw exception -} -