[Analysis API FIR, LL FIR] use exceptionWithAttachment to not leak user data

This commit is contained in:
Ilya Kirillov
2022-07-23 15:59:30 +02:00
parent b701c1c6f6
commit 827c262f68
25 changed files with 351 additions and 79 deletions
@@ -7,6 +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
abstract class ContextByDesignationCollector<C : Any>(private val designation: FirDeclarationDesignation) {
private var context: C? = null
@@ -56,7 +57,7 @@ private class FirDesignationState(val designation: FirDeclarationDesignation) {
val currentDeclaration: FirDeclaration
get() = currentDeclarationIfPresent
?: error("Went inside target declaration")
?: firErrorWithAttachment("Went inside target declaration")
fun goNext() {
if (canGoNext()) {
@@ -16,6 +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.project.structure.*
import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker
import org.jetbrains.kotlin.analysis.utils.caches.strongCachedValue
@@ -86,7 +87,9 @@ internal class LLFirResolveSessionService(project: Project) {
}
else -> {
error("Unexpected $useSiteKtModule")
firErrorWithAttachment("Unexpected ${useSiteKtModule::class.java}") {
withAttachment("module", useSiteKtModule.moduleDescription)
}
}
}
@@ -5,17 +5,20 @@
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.descriptors.Visibilities
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.render
import org.jetbrains.kotlin.fir.renderWithType
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.resolve.toFirRegularClass
import org.jetbrains.kotlin.fir.symbols.impl.LookupTagInternals
import org.jetbrains.kotlin.utils.checkWithAttachment
import org.jetbrains.kotlin.utils.errorWithAttachment
class FirDeclarationDesignationWithFile(
path: List<FirDeclaration>,
@@ -77,21 +80,28 @@ private fun collectDesignationPath(declaration: FirDeclaration): List<FirDeclara
else -> return null
} ?: return emptyList()
require(containingClass is FirRegularClass) {
"FirRegularClass as containing declaration expected but found ${containingClass.renderWithType()}"
checkWithAttachment(containingClass is FirRegularClass, { "FirRegularClass as containing declaration expected" }) {
it.withFirAttachment("containingClassFir", containingClass)
}
return if (!containingClass.isLocal) containingClass.collectForNonLocal().asReversed() else null
}
fun FirDeclaration.collectDesignation(firFile: FirFile): FirDeclarationDesignationWithFile =
tryCollectDesignation(firFile) ?: error("No designation of local declaration ${this.render()}")
tryCollectDesignation(firFile) ?: errorWithAttachment("No designation of local declaration") {
withFirAttachment("firFile", firFile)
}
fun FirDeclaration.collectDesignation(): FirDeclarationDesignation =
tryCollectDesignation() ?: error("No designation of local declaration ${this.render()}")
tryCollectDesignation()
?: errorWithAttachment("No designation of local declaration") {
withFirAttachment("FirDeclaration", this@collectDesignation)
}
fun FirDeclaration.collectDesignationWithFile(): FirDeclarationDesignationWithFile =
tryCollectDesignationWithFile()
?: error("No designation of local declaration ${this.render()}")
?: errorWithAttachment("No designation of local declaration") {
withFirAttachment("FirDeclaration", this@collectDesignationWithFile)
}
fun FirDeclaration.tryCollectDesignation(firFile: FirFile): FirDeclarationDesignationWithFile? =
collectDesignationPath(this)?.let {
@@ -5,16 +5,33 @@
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.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 java.util.*
import kotlin.reflect.KClass
class InvalidFirElementTypeException(
actualFirClass: KClass<*>?,
actualFirElement: Any?,
ktElement: KtElement?,
expectedFirClasses: List<KClass<*>>,
) : IllegalStateException() {
) : 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() }
}
}
override val message: String = buildString {
if (ktElement != null) {
append("For $ktElement with text `${ktElement.text}`, ")
@@ -25,8 +42,8 @@ class InvalidFirElementTypeException(
else -> "One of [${expectedFirClasses.joinToString()}] element types expected, but"
}
append(if (ktElement == null) message else message.replaceFirstChar { it.lowercase(Locale.getDefault()) })
if (actualFirClass != null) {
append(" ${actualFirClass.simpleName} found")
if (actualFirElement != null) {
append(" ${actualFirElement::class.simpleName} found")
} else {
append(" no element found")
}
@@ -39,5 +56,5 @@ fun throwUnexpectedFirElementError(
ktElement: KtElement? = null,
vararg expectedFirClasses: KClass<*>
): Nothing {
throw InvalidFirElementTypeException(firElement?.let { it::class }, ktElement, expectedFirClasses.toList())
throw InvalidFirElementTypeException(firElement, ktElement, expectedFirClasses.toList())
}
@@ -7,6 +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.builtins.StandardNames
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.builder.BodyBuildingMode
@@ -132,7 +133,7 @@ object KtDeclarationAndFirDeclarationEqualityChecker {
}
}
}
else -> error("Invalid type reference $this")
else -> firErrorWithAttachment("Invalid type reference", fir = this)
}
return if (isVararg) {
rendered.asArrayType()
@@ -165,7 +166,7 @@ object KtDeclarationAndFirDeclarationEqualityChecker {
}
append(typeRef.renderTypeAsKotlinType())
}
else -> error("Invalid type projection $this")
else -> firErrorWithAttachment("Invalid type reference", fir = this)
}
private fun isTheSameTypes(
@@ -200,7 +201,7 @@ object KtDeclarationAndFirDeclarationEqualityChecker {
// Can be present as return type
"${lowerBound.renderTypeAsKotlinType()}..${upperBound.renderTypeAsKotlinType()}"
}
else -> error("Type $this should not be present in Kotlin declaration")
else -> firErrorWithAttachment("Type should not be present in Kotlin declaration", coneType = this)
}.replace('/', '.')
return rendered + nullability.suffix
}
@@ -18,7 +18,10 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.KtToFirMap
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.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.printer.getElementTextInContext
import org.jetbrains.kotlin.analysis.utils.printer.parentOfType
@@ -37,6 +40,7 @@ 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
object LowLevelFirApiFacadeForResolveOnAir {
@@ -87,7 +91,10 @@ object LowLevelFirApiFacadeForResolveOnAir {
}
declaration.accept(expressionLocator)
return expressionLocator.result ?: error("Resolved on-air element was not found in containing declaration")
return expressionLocator.result ?: firErrorWithAttachment("Resolved on-air element was not found in containing declaration") {
withPsiAttachment("place", place)
withPsiAttachment("elementToResolve", elementToResolve)
}
}
fun onAirGetTowerContextProvider(
@@ -152,7 +159,10 @@ object LowLevelFirApiFacadeForResolveOnAir {
val sameDeclarationInOriginalFile = PsiTreeUtil.findSameElementInCopy(dependencyNonLocalDeclaration, originalKtFile)
?: error("Cannot find original function matching to ${dependencyNonLocalDeclaration.getElementTextInContext()} in $originalKtFile")
?: firErrorWithAttachment("Cannot find original function matching") {
withPsiAttachment("matchingPsi", dependencyNonLocalDeclaration)
withPsiAttachment("originalFile", originalKtFile)
}
recordOriginalDeclaration(
targetDeclaration = dependencyNonLocalDeclaration,
@@ -183,7 +193,10 @@ object LowLevelFirApiFacadeForResolveOnAir {
fileAnnotation = annotationEntry,
replacement = replacement
)
val llFirResolvableSession = firFile.llFirResolvableSession ?: error("FirFile session expected to be a resolvable session")
val llFirResolvableSession = firFile.llFirResolvableSession
?: errorWithAttachment("FirFile session expected to be a resolvable session but was ${firFile.llFirSession::class.java}") {
withAttachment("firSession", firFile.llFirSession)
}
val declarationResolver = llFirResolvableSession.moduleComponents.lazyFirDeclarationsResolver
declarationResolver.resolveFileAnnotations(
@@ -9,6 +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.asJava.KtLightClassMarker
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent
@@ -18,6 +19,7 @@ import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.utils.errorWithAttachment
class LLFirFirClassByPsiClassProvider(private val session: LLFirSession) : FirSessionComponent {
fun getFirClass(psiClass: PsiClass): FirRegularClassSymbol? {
@@ -42,8 +44,11 @@ class LLFirFirClassByPsiClassProvider(private val session: LLFirSession) : FirSe
val classId = psiClass.classIdIfNonLocal
?: error("No classId for non-local class")
val provider = session.nullableJavaSymbolProvider ?: session.symbolProvider
val symbol = (provider.getClassLikeSymbolByClassId(classId)
?: error("No classifier found with $classId"))
val symbol = provider.getClassLikeSymbolByClassId(classId)
?: errorWithAttachment("No classifier found") {
withPsiAttachment("psiClass", psiClass)
withAttachment("classId", classId.asString())
}
return symbol as FirRegularClassSymbol
}
}
@@ -11,11 +11,14 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLocalContainingOrThisDeclaration
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.firModuleData
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirLibrarySession
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirResolvableModuleSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionProvider
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
@@ -32,6 +35,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
internal abstract class LLFirResolvableResolveSession(
private val sessionProvider: LLFirSessionProvider,
@@ -98,7 +103,10 @@ internal abstract class LLFirResolvableResolveSession(
"Declaration should be resolvable module, instead it had ${module::class}"
}
val nonLocalNamedDeclaration = ktDeclaration.getNonLocalContainingOrThisDeclaration()
?: error("Declaration should have non-local container${ktDeclaration.getElementTextInContext()}")
?: errorWithAttachment("Declaration should have non-local container") {
withPsiAttachment("ktDeclaration", ktDeclaration)
withAttachmentDetailed("module", module) { it.moduleDescription }
}
if (ktDeclaration == nonLocalNamedDeclaration) {
val session = sessionProvider.getResolvableSession(module)
@@ -30,17 +30,20 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid
is KtNamedFunction -> findNonLocalFunction(ktDeclaration)
is KtProperty -> findNonLocalProperty(ktDeclaration)
else -> error("Unsupported compiled declaration of type ${ktDeclaration::class}: ${ktDeclaration.getElementTextInContext()}")
else -> firErrorWithAttachment("Unsupported compiled declaration of type", psi = ktDeclaration)
}
}
private fun findNonLocalEnumEntry(declaration: KtEnumEntry): FirEnumEntry {
require(!declaration.isLocal)
val classId = declaration.containingClassOrObject?.getClassId()
?: error("Non-local class should have classId. The class is ${declaration.getElementTextInContext()}")
?: firErrorWithAttachment(
"Non-local class should have classId. The class is ${declaration.getElementTextInContext()}",
psi = declaration
)
val classCandidate = symbolProvider.getClassLikeSymbolByClassId(classId)
?: error("We should be able to find a symbol for $classId")
?: firErrorWithAttachment("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
@@ -49,26 +52,31 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid
private fun findNonLocalClassLikeDeclaration(declaration: KtClassLikeDeclaration): FirClassLikeDeclaration {
val classId = declaration.getClassId()
?: error("Non-local class should have classId. The class is ${declaration.getElementTextInContext()}")
?: firErrorWithAttachment("Non-local class should have classId", psi = declaration)
val classCandidate = symbolProvider.getClassLikeSymbolByClassId(classId)
?: error("We should be able to find a symbol for $classId")
?: firErrorWithAttachment("We should be able to find a symbol for $classId", psi = declaration) {
withAttachment(
"classId",
classId.asString()
)
}
return classCandidate.fir
}
private fun findConstructorOfNonLocalClass(declaration: KtConstructor<*>): FirConstructor {
val containingClass = declaration.containingClassOrObject
?: error("Constructor must have outer class: ${declaration.getElementTextInContext()}")
?: firErrorWithAttachment("Constructor must have outer class", psi = declaration)
require(!containingClass.isLocal)
val classId = containingClass.getClassId()
?: error("Non-local class should have classId. The class is ${containingClass.getElementTextInContext()}")
?: firErrorWithAttachment("Non-local class should have classId", psi = declaration)
val constructorCandidate =
symbolProvider.getClassDeclaredConstructors(classId)
.singleOrNull { representSameConstructor(declaration, it.fir) }
?: error("We should be able to find a constructor: ${declaration.getElementTextInContext()}")
?: firErrorWithAttachment("We should be able to find a constructor", psi = declaration)
return constructorCandidate.fir
}
@@ -79,7 +87,7 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid
val functionCandidate =
symbolProvider.findFunctionCandidates(declaration)
.singleOrNull { KtDeclarationAndFirDeclarationEqualityChecker.representsTheSameDeclaration(declaration, it.fir) }
?: error("We should be able to find a symbol for function ${declaration.name}: ${declaration.getElementTextInContext()}")
?: firErrorWithAttachment("We should be able to find a symbol for function", psi = declaration)
return functionCandidate.fir
}
@@ -90,7 +98,7 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid
val propertyCandidate =
symbolProvider.findPropertyCandidates(declaration)
.singleOrNull { KtDeclarationAndFirDeclarationEqualityChecker.representsTheSameDeclaration(declaration, it.fir) }
?: error("We should be able to find a symbol for property ${declaration.name}: ${declaration.getElementTextInContext()}")
?: firErrorWithAttachment("We should be able to find a symbol for property", psi = declaration)
return propertyCandidate.fir
}
@@ -112,7 +120,7 @@ private fun FirSymbolProvider.findCallableCandidates(
}
val containerClassId = declaration.containingClassOrObject?.getClassId()
?: error("No containing non-local declaration found for ${declaration.getElementTextInContext()}")
?: firErrorWithAttachment("No containing non-local declaration found for", psi = declaration)
return getClassDeclaredFunctionSymbols(containerClassId, declaration.nameAsSafeName) +
getClassDeclaredPropertySymbols(containerClassId, declaration.nameAsSafeName)
@@ -17,6 +17,6 @@ fun FirDeclaration.getContainingFile(): FirFile? {
is FirFile -> this
is FirCallableDeclaration -> provider.getFirCallableContainerFile(symbol)
is FirClassLikeDeclaration -> provider.getFirClassifierContainerFile(symbol)
else -> error("Unsupported declaration ${this::class.java}")
else -> firErrorWithAttachment("Unsupported declaration ${this::class.java}", fir = this)
}
}
@@ -30,7 +30,7 @@ internal fun KtDeclaration.findSourceNonLocalFirDeclaration(
//TODO test what way faster
findSourceNonLocalFirDeclarationByProvider(firFileBuilder, provider, containerFirFile)?.let { return it }
findSourceOfNonLocalFirDeclarationByTraversingWholeTree(firFileBuilder, containerFirFile)?.let { return it }
error("No fir element was found for\n${getElementTextInContext()}")
firErrorWithAttachment("No fir element was found for", psi = this)
}
internal fun KtDeclaration.findFirDeclarationForAnyFirSourceDeclaration(
@@ -45,7 +45,7 @@ internal fun KtDeclaration.findFirDeclarationForAnyFirSourceDeclaration(
firDeclaration.psi == this || firDeclaration.psi == originalDeclaration
}
return fir
?: error("FirDeclaration was not found for\n${getElementTextInContext()}")
?: firErrorWithAttachment("FirDeclaration was not found", psi = this)
}
internal inline fun <reified F : FirDeclaration> KtDeclaration.findFirDeclarationForAnyFirSourceDeclarationOfType(
@@ -95,12 +95,12 @@ private fun KtDeclaration.findSourceNonLocalFirDeclarationByProvider(
}
this is KtConstructor<*> -> {
val containingClass = containingClassOrObject
?: error("Container class should be not null for KtConstructor")
?: firErrorWithAttachment("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 -> error("Invalid container ${this::class}\n${getElementTextInContext()}")
else -> firErrorWithAttachment("Invalid container", psi = this)
}
return candidate?.takeIf { it.realPsi == this }
}
@@ -0,0 +1,80 @@
/*
* 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.low.level.api.fir.util
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.renderer.ConeTypeRendererForDebugging
import org.jetbrains.kotlin.fir.renderer.FirDeclarationRendererWithAttributes
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 KotlinExceptionWithAttachments.withFirSymbolAttachment(name: String, symbol: FirBasedSymbol<*>): KotlinExceptionWithAttachments {
withAttachment("${name}Class", symbol::class.java.name)
withFirAttachment("${name}Fir", symbol.fir)
return this
}
fun KotlinExceptionWithAttachments.withConeTypeAttachment(name: String, coneType: ConeKotlinType): KotlinExceptionWithAttachments {
withAttachmentDetailed(name, coneType) {
buildString { ConeTypeRendererForDebugging(this).render(it) }
}
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(
message: String,
cause: Throwable? = null,
fir: FirElement? = null,
coneType: ConeKotlinType? = null,
psi: PsiElement? = null,
attachments: KotlinExceptionWithAttachments.() -> Unit = {}
): Nothing {
errorWithAttachment(message, cause) {
if (fir != null) {
withFirAttachment("fir", fir)
}
if (psi != null) {
withPsiAttachment("psi", psi)
}
if (coneType != null) {
withConeTypeAttachment("coneType", coneType)
}
attachments ()
}
}
private val debugFirRenderer =
FirRenderer(resolvePhaseRenderer = FirResolvePhaseRenderer(), declarationRenderer = FirDeclarationRendererWithAttributes())
@@ -54,17 +54,14 @@ internal val FirElement.isErrorElement
internal val FirDeclaration.ktDeclaration: KtDeclaration
get() {
val psi = psi
?: error("PSI element was not found for${render()}")
?: firErrorWithAttachment("PSI element was not found", fir = this)
return when (psi) {
is KtDeclaration -> psi
is KtObjectLiteralExpression -> psi.objectDeclaration
else -> error(
"""
FirDeclaration.psi (${this::class.simpleName}) should be KtDeclaration but was ${psi::class.simpleName}
${(psi as? KtElement)?.getElementTextInContext() ?: psi.text}
${render()}
""".trimIndent()
else -> firErrorWithAttachment(
"FirDeclaration.psi (${this::class.simpleName}) should be KtDeclaration but was ${psi::class.simpleName}",
fir = this,
psi = psi,
)
}
}