[Analysis API FIR] add more info to some exceptions

This commit is contained in:
Ilya Kirillov
2022-07-23 19:50:08 +02:00
parent 5a5e6ad8cd
commit 76f1744868
11 changed files with 81 additions and 38 deletions
@@ -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) }
}
}
}
@@ -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
@@ -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
@@ -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<KtCallCandidateInfo>
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<KtCallCandidateInfo> =
withValidityAssertion { analysisSession.callResolver.collectCallCandidates(this) }
}
private inline fun <reified PSI : KtElement> unresolvedKtCallError(element: PSI): Nothing {
throw KotlinExceptionWithAttachments("${PSI::class.simpleName}(${element::class.simpleName}) should always resolve to a KtCallInfo")
.withAttachment("elementText", element.getElementTextInContext())
}
@@ -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 <reified ELEMENT> 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
}
@@ -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
@@ -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
@@ -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
@@ -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<FirBasedSymbol<*>>) {
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()
}
}
}
@@ -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())
@@ -38,6 +38,11 @@ open class KotlinExceptionWithAttachments : RuntimeException, ExceptionWithAttac
}
}
fun KotlinExceptionWithAttachments.withAttachmentBuilder(name: String, buildContent: StringBuilder.() -> Unit): KotlinExceptionWithAttachments {
return withAttachment(name, buildString { buildContent() })
}
fun <T> KotlinExceptionWithAttachments.withAttachmentDetailed(
name: String,
content: T?,