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 ebb72a99e21..86af0d6f027 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 @@ -26,6 +26,8 @@ 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.utils.printer.parentOfType import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol @@ -67,6 +69,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.errorWithAttachment internal class KtFirCallResolver( override val analysisSession: KtFirAnalysisSession, @@ -1162,4 +1165,11 @@ internal class KtFirCallResolver( else -> realPsi as? KtExpression } } + + 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) } + } + } } 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 f9b0d0a6578..229ddde1b2d 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 @@ -12,7 +12,7 @@ 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.low.level.api.fir.util.withPsiAttachment +import org.jetbrains.kotlin.analysis.utils.errors.withPsiAttachment import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass import org.jetbrains.kotlin.fir.render 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 7586f229274..81173cb2bbd 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 @@ -9,7 +9,7 @@ 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.low.level.api.fir.util.withPsiAttachment +import org.jetbrains.kotlin.analysis.utils.errors.withPsiAttachment import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments import org.jetbrains.kotlin.utils.withAttachmentDetailed 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 6aa064cb6c3..0a0c8c8d47a 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,16 +8,23 @@ 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.printer.getElementTextInContext +import org.jetbrains.kotlin.analysis.utils.errors.withPsiAttachment 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.KotlinExceptionWithAttachments +import org.jetbrains.kotlin.utils.errorWithAttachment public abstract class KtCallResolver : KtAnalysisSessionComponent() { public abstract fun resolveCall(psi: KtElement): KtCallInfo? + 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) + } + } } public interface KtCallResolverMixIn : KtAnalysisSessionMixIn { @@ -27,18 +34,18 @@ public interface KtCallResolverMixIn : KtAnalysisSessionMixIn { public fun KtCallElement.resolveCall(): KtCallInfo = withValidityAssertion { analysisSession.callResolver.resolveCall(this) - ?: unresolvedKtCallError(this) + ?: analysisSession.callResolver.unresolvedKtCallError(this) } public fun KtUnaryExpression.resolveCall(): KtCallInfo = withValidityAssertion { analysisSession.callResolver.resolveCall(this) - ?: unresolvedKtCallError(this) + ?: analysisSession.callResolver.unresolvedKtCallError(this) } public fun KtArrayAccessExpression.resolveCall(): KtCallInfo = withValidityAssertion { analysisSession.callResolver.resolveCall(this) - ?: unresolvedKtCallError(this) + ?: analysisSession.callResolver.unresolvedKtCallError(this) } /** @@ -51,8 +58,3 @@ public interface KtCallResolverMixIn : KtAnalysisSessionMixIn { public fun KtElement.collectCallCandidates(): List = withValidityAssertion { analysisSession.callResolver.collectCallCandidates(this) } } - -private inline fun unresolvedKtCallError(element: PSI): Nothing { - throw KotlinExceptionWithAttachments("${PSI::class.simpleName}(${element::class.simpleName}) should always resolve to a KtCallInfo") - .withAttachment("elementText", element.getElementTextInContext()) -} 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 index b8b100fc8c0..f18c30dda8f 100644 --- 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 @@ -5,7 +5,12 @@ 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 }}") { @@ -15,4 +20,14 @@ public fun unexpectedElementError(elementName: String, element: Any?): Nothing { 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/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 2ac667be495..849f5df2450 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 @@ -21,8 +21,8 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirResolvableS 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.originalDeclaration -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withPsiAttachment 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 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 447da96b9ef..afb09e62d64 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 @@ -9,7 +9,7 @@ import com.intellij.psi.PsiClass import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiTypeParameter import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withPsiAttachment +import org.jetbrains.kotlin.analysis.utils.errors.withPsiAttachment import org.jetbrains.kotlin.asJava.KtLightClassMarker import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSessionComponent 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 ae5a16ca019..eb40ba3a592 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 @@ -18,10 +18,10 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionProv import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirDeclarationForCompiledElementSearcher import org.jetbrains.kotlin.analysis.low.level.api.fir.util.findSourceNonLocalFirDeclaration import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalDeclaration -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withPsiAttachment 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 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 2d4cb194f73..8794f9dbe84 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 @@ -6,17 +6,21 @@ 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.fir.declarations.* import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredConstructors import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredFunctionSymbols import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredPropertySymbols +import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol 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. @@ -37,10 +41,7 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid private fun findNonLocalEnumEntry(declaration: KtEnumEntry): FirEnumEntry { require(!declaration.isLocal) val classId = declaration.containingClassOrObject?.getClassId() - ?: firErrorWithAttachment( - "Non-local class should have classId. The class is ${declaration.getElementTextInContext()}", - psi = declaration - ) + ?: firErrorWithAttachment("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) @@ -56,10 +57,7 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid val classCandidate = symbolProvider.getClassLikeSymbolByClassId(classId) ?: firErrorWithAttachment("We should be able to find a symbol for $classId", psi = declaration) { - withAttachment( - "classId", - classId.asString() - ) + withAttachment("classId", classId.asString()) } return classCandidate.fir @@ -84,21 +82,27 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid private fun findNonLocalFunction(declaration: KtNamedFunction): FirFunction { require(!declaration.isLocal) + val candidates = symbolProvider.findFunctionCandidates(declaration) val functionCandidate = - symbolProvider.findFunctionCandidates(declaration) + candidates .singleOrNull { KtDeclarationAndFirDeclarationEqualityChecker.representsTheSameDeclaration(declaration, it.fir) } - ?: firErrorWithAttachment("We should be able to find a symbol for function", psi = declaration) + ?: firErrorWithAttachment("We should be able to find a symbol for function", psi = declaration) { + withCandidates(candidates) + } return functionCandidate.fir } + private fun findNonLocalProperty(declaration: KtProperty): FirProperty { require(!declaration.isLocal) + val candidates = symbolProvider.findPropertyCandidates(declaration) val propertyCandidate = - symbolProvider.findPropertyCandidates(declaration) - .singleOrNull { KtDeclarationAndFirDeclarationEqualityChecker.representsTheSameDeclaration(declaration, it.fir) } - ?: firErrorWithAttachment("We should be able to find a symbol for property", psi = declaration) + candidates.singleOrNull { KtDeclarationAndFirDeclarationEqualityChecker.representsTheSameDeclaration(declaration, it.fir) } + ?: firErrorWithAttachment("We should be able to find a symbol for property", psi = declaration) { + withCandidates(candidates) + } return propertyCandidate.fir } @@ -133,3 +137,17 @@ 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() + } + } +} 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 6769941f003..8c4dc426cd0 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,6 +6,7 @@ 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.fir.FirElement import org.jetbrains.kotlin.fir.psi @@ -40,15 +41,7 @@ fun KotlinExceptionWithAttachments.withConeTypeAttachment(name: String, coneType return this } -fun KotlinExceptionWithAttachments.withPsiAttachment(name: String, psi: PsiElement?): KotlinExceptionWithAttachments { - withAttachmentDetailed(name, psi) { psiElement -> - when (psiElement) { - is KtElement -> psiElement.getElementTextInContext() - else -> psiElement.text - } - } - return this -} + fun firErrorWithAttachment( @@ -76,5 +69,5 @@ fun firErrorWithAttachment( } -private val debugFirRenderer = +val debugFirRenderer = FirRenderer(resolvePhaseRenderer = FirResolvePhaseRenderer(), declarationRenderer = FirDeclarationRendererWithAttributes()) diff --git a/compiler/util/src/org/jetbrains/kotlin/utils/KotlinExceptionWithAttachments.kt b/compiler/util/src/org/jetbrains/kotlin/utils/KotlinExceptionWithAttachments.kt index d903d9e054f..5e7cd9f5c4f 100644 --- a/compiler/util/src/org/jetbrains/kotlin/utils/KotlinExceptionWithAttachments.kt +++ b/compiler/util/src/org/jetbrains/kotlin/utils/KotlinExceptionWithAttachments.kt @@ -38,6 +38,11 @@ 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?,