[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
@@ -9,13 +9,16 @@ import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.analysis.api.fir.utils.withSymbolAttachment
import org.jetbrains.kotlin.analysis.api.impl.base.CachingKtAnalysisSessionProvider import org.jetbrains.kotlin.analysis.api.impl.base.CachingKtAnalysisSessionProvider
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken 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.LLFirResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getFirResolveSession 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.analysis.project.structure.KtModule
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.utils.errorWithAttachment
@OptIn(KtAnalysisApiInternals::class) @OptIn(KtAnalysisApiInternals::class)
class KtFirAnalysisSessionProvider(project: Project) : CachingKtAnalysisSessionProvider<LLFirResolveSession>(project) { class KtFirAnalysisSessionProvider(project: Project) : CachingKtAnalysisSessionProvider<LLFirResolveSession>(project) {
@@ -26,7 +29,9 @@ class KtFirAnalysisSessionProvider(project: Project) : CachingKtAnalysisSessionP
override fun getFirResolveSession(contextSymbol: KtSymbol): LLFirResolveSession { override fun getFirResolveSession(contextSymbol: KtSymbol): LLFirResolveSession {
return when (contextSymbol) { return when (contextSymbol) {
is KtFirSymbol<*> -> contextSymbol.firResolveSession is KtFirSymbol<*> -> contextSymbol.firResolveSession
else -> error("Invalid symbol ${contextSymbol::class}") else -> errorWithAttachment("Invalid symbol") {
withSymbolAttachment("symbol", contextSymbol)
}
} }
} }
@@ -20,6 +20,10 @@ import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor
import org.jetbrains.kotlin.analysis.api.types.KtType 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.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.providers.createPackageProvider import org.jetbrains.kotlin.analysis.providers.createPackageProvider
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
@@ -49,6 +53,7 @@ import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.errorWithAttachment
import kotlin.contracts.ExperimentalContracts import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract import kotlin.contracts.contract
@@ -203,7 +208,10 @@ internal class KtSymbolByFirBuilder constructor(
return buildFunctionSymbol(it.symbol) return buildFunctionSymbol(it.symbol)
} }
if (firSymbol.dispatchReceiverType?.contains { it is ConeStubType } == true) { if (firSymbol.dispatchReceiverType?.contains { it is ConeStubType } == true) {
return buildFunctionSymbol(firSymbol.originalIfFakeOverride() ?: error("Stub type in real declaration")) return buildFunctionSymbol(
firSymbol.originalIfFakeOverride()
?: firErrorWithAttachment("Stub type in real declaration", fir = firSymbol.fir)
)
} }
check(firSymbol.origin != FirDeclarationOrigin.SamConstructor) check(firSymbol.origin != FirDeclarationOrigin.SamConstructor)
@@ -579,8 +587,22 @@ internal class KtSymbolByFirBuilder constructor(
} }
companion object { companion object {
private fun throwUnexpectedElementError(element: Any): Nothing { private fun throwUnexpectedElementError(element: FirBasedSymbol<*>): Nothing {
error("Unexpected ${element::class.simpleName}") errorWithAttachment("Unexpected ${element::class.simpleName}") {
withFirSymbolAttachment("firSymbol", element)
}
}
private fun throwUnexpectedElementError(element: FirElement): Nothing {
errorWithAttachment("Unexpected ${element::class.simpleName}") {
withFirAttachment("firElement", element)
}
}
private fun throwUnexpectedElementError(element: ConeKotlinType): Nothing {
errorWithAttachment("Unexpected ${element::class.simpleName}") {
withConeTypeAttachment("coneType", element)
}
} }
@OptIn(ExperimentalContracts::class) @OptIn(ExperimentalContracts::class)
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor
import org.jetbrains.kotlin.analysis.api.types.KtType 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.api.getOrBuildFir
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.AllCandidatesResolver 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.utils.printer.parentOfType import org.jetbrains.kotlin.analysis.utils.printer.parentOfType
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
@@ -151,7 +152,7 @@ internal class KtFirCallResolver(
when (val calleeReference = calleeReference) { when (val calleeReference = calleeReference) {
is FirResolvedNamedReference -> { is FirResolvedNamedReference -> {
val call = createKtCall(psi, this, null, resolveFragmentOfCall) val call = createKtCall(psi, this, null, resolveFragmentOfCall)
?: error("expect `createKtCall` to succeed for resolvable case") ?: firErrorWithAttachment("expect `createKtCall` to succeed for resolvable case", fir = this, psi = psi)
KtSuccessCallInfo(call) KtSuccessCallInfo(call)
} }
is FirErrorNamedReference -> { is FirErrorNamedReference -> {
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirReceiverParameterSymbo
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirTypeParameterSymbol import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirTypeParameterSymbol
import org.jetbrains.kotlin.analysis.api.fir.utils.getContainingKtModule import org.jetbrains.kotlin.analysis.api.fir.utils.getContainingKtModule
import org.jetbrains.kotlin.analysis.api.fir.utils.withSymbolAttachment
import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithKind import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithKind
@@ -22,6 +23,7 @@ import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.utils.printer.parentOfType import org.jetbrains.kotlin.analysis.utils.printer.parentOfType
import org.jetbrains.kotlin.psi import org.jetbrains.kotlin.psi
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.utils.errorWithAttachment
internal class KtFirSymbolContainingDeclarationProvider( internal class KtFirSymbolContainingDeclarationProvider(
override val analysisSession: KtFirAnalysisSession, override val analysisSession: KtFirAnalysisSession,
@@ -85,21 +87,33 @@ internal class KtFirSymbolContainingDeclarationProvider(
private fun getContainingPsi(symbol: KtFirSymbol<*>): KtDeclaration { private fun getContainingPsi(symbol: KtFirSymbol<*>): KtDeclaration {
val source = symbol.firSymbol.source val source = symbol.firSymbol.source
val thisSource = when (source?.kind) { val thisSource = when (source?.kind) {
null -> error("PSI should present for declaration built by Kotlin code") null -> errorWithAttachment("PSI should present for declaration built by Kotlin code") {
withSymbolAttachment("symbolForContainingPsi", symbol)
}
KtFakeSourceElementKind.ImplicitConstructor -> KtFakeSourceElementKind.ImplicitConstructor ->
return source.psi as KtDeclaration return source.psi as KtDeclaration
KtFakeSourceElementKind.PropertyFromParameter -> return source.psi?.parentOfType<KtPrimaryConstructor>()!! KtFakeSourceElementKind.PropertyFromParameter -> return source.psi?.parentOfType<KtPrimaryConstructor>()!!
KtFakeSourceElementKind.DefaultAccessor -> return source.psi as KtProperty KtFakeSourceElementKind.DefaultAccessor -> return source.psi as KtProperty
KtFakeSourceElementKind.ItLambdaParameter -> return source.psi as KtFunctionLiteral KtFakeSourceElementKind.ItLambdaParameter -> return source.psi as KtFunctionLiteral
KtRealSourceElementKind -> source.psi!! KtRealSourceElementKind -> source.psi!!
else -> error("Unexpected FirSourceElement: kind=${source.kind} element=${source.psi!!::class.simpleName}") else ->
errorWithAttachment("errorWithAttachment FirSourceElement: kind=${source.kind} element=${source.psi!!::class.simpleName}") {
withSymbolAttachment("symbolForContainingPsi", symbol)
}
} }
return when (symbol.origin) { return when (symbol.origin) {
KtSymbolOrigin.SOURCE -> thisSource.getContainingKtDeclaration() KtSymbolOrigin.SOURCE -> thisSource.getContainingKtDeclaration()
?: error("Containing declaration should present for non-toplevel declaration") ?: errorWithAttachment("Containing declaration should present for non-toplevel declaration") {
withSymbolAttachment("symbolForContainingPsi", symbol)
}
KtSymbolOrigin.SOURCE_MEMBER_GENERATED -> thisSource as KtDeclaration KtSymbolOrigin.SOURCE_MEMBER_GENERATED -> thisSource as KtDeclaration
else -> error("Unsupported declaration origin ${symbol.origin}") else -> errorWithAttachment("Unsupported declaration origin ${symbol.origin}") {
withSymbolAttachment("symbolForContainingPsi", symbol)
}
} }
} }
@@ -113,21 +127,31 @@ internal class KtFirSymbolContainingDeclarationProvider(
require(symbol.origin == KtSymbolOrigin.LIBRARY || symbol.origin == KtSymbolOrigin.JAVA) require(symbol.origin == KtSymbolOrigin.LIBRARY || symbol.origin == KtSymbolOrigin.JAVA)
check(symbol.symbolKind == KtSymbolKind.CLASS_MEMBER) check(symbol.symbolKind == KtSymbolKind.CLASS_MEMBER)
fun error(message: String): Nothing {
errorWithAttachment(message) {
withSymbolAttachment("symbolToGetContaining", symbol)
}
}
val containingClassId = when (symbol) { val containingClassId = when (symbol) {
is KtClassLikeSymbol -> { is KtClassLikeSymbol -> {
val classId = symbol.classIdIfNonLocal ?: error("classId should not be null for non-local declaration") val classId = symbol.classIdIfNonLocal
?: error("classId should not be null for non-local declaration")
classId.outerClassId classId.outerClassId
} }
is KtFunctionSymbol -> { is KtFunctionSymbol -> {
val fqName = symbol.callableIdIfNonLocal ?: error("callableIdIfNonLocal should not be null for non-local declaration") val fqName = symbol.callableIdIfNonLocal
?: error("callableIdIfNonLocal should not be null for non-local declaration")
fqName.classId fqName.classId
} }
is KtEnumEntrySymbol -> { is KtEnumEntrySymbol -> {
val classId = symbol.containingEnumClassIdIfNonLocal ?: error("fqName should not be null for non-local declaration") val classId = symbol.containingEnumClassIdIfNonLocal
?: error("fqName should not be null for non-local declaration")
classId.outerClassId classId.outerClassId
} }
is KtPropertySymbol -> { is KtPropertySymbol -> {
val fqName = symbol.callableIdIfNonLocal ?: error("fqName should not be null for non-local declaration") val fqName = symbol.callableIdIfNonLocal
?: error("fqName should not be null for non-local declaration")
fqName.classId fqName.classId
} }
is KtConstructorSymbol -> { is KtConstructorSymbol -> {
@@ -137,6 +161,6 @@ internal class KtFirSymbolContainingDeclarationProvider(
else -> error("We should not have a ${symbol::class} from a library") else -> error("We should not have a ${symbol::class} from a library")
} ?: error("outerClassId should not be null for member declaration") } ?: error("outerClassId should not be null for member declaration")
val containingClass = containingClassId.getCorrespondingToplevelClassOrObjectSymbol() val containingClass = containingClassId.getCorrespondingToplevelClassOrObjectSymbol()
return containingClass ?: error("Class with id $containingClassId should exists") return containingClass ?: error("Class by class id should exists")
} }
} }
@@ -11,17 +11,18 @@ import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin 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.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.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor
import org.jetbrains.kotlin.fir.originalIfFakeOverride
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.scopes.impl.importedFromObjectData import org.jetbrains.kotlin.fir.scopes.impl.importedFromObjectData
import org.jetbrains.kotlin.fir.scopes.impl.originalForWrappedIntegerOperator import org.jetbrains.kotlin.fir.scopes.impl.originalForWrappedIntegerOperator
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.utils.errorWithAttachment
internal interface KtFirSymbol<out S : FirBasedSymbol<*>> : KtSymbol, KtLifetimeOwner { internal interface KtFirSymbol<out S : FirBasedSymbol<*>> : KtSymbol, KtLifetimeOwner {
val firSymbol: S val firSymbol: S
@@ -49,6 +50,7 @@ internal tailrec fun FirDeclaration.ktSymbolOrigin(): KtSymbolOrigin = when (ori
else -> KtSymbolOrigin.SOURCE else -> KtSymbolOrigin.SOURCE
} }
} }
FirDeclarationOrigin.Precompiled -> KtSymbolOrigin.SOURCE FirDeclarationOrigin.Precompiled -> KtSymbolOrigin.SOURCE
FirDeclarationOrigin.Library, FirDeclarationOrigin.BuiltIns -> KtSymbolOrigin.LIBRARY FirDeclarationOrigin.Library, FirDeclarationOrigin.BuiltIns -> KtSymbolOrigin.LIBRARY
is FirDeclarationOrigin.Java -> KtSymbolOrigin.JAVA is FirDeclarationOrigin.Java -> KtSymbolOrigin.JAVA
@@ -60,26 +62,36 @@ internal tailrec fun FirDeclaration.ktSymbolOrigin(): KtSymbolOrigin = when (ori
when (this) { when (this) {
is FirSyntheticProperty, is FirSyntheticProperty,
is FirSyntheticPropertyAccessor -> KtSymbolOrigin.JAVA_SYNTHETIC_PROPERTY is FirSyntheticPropertyAccessor -> KtSymbolOrigin.JAVA_SYNTHETIC_PROPERTY
else -> throw InvalidFirDeclarationOriginForSymbol(this)
else -> errorWithAttachment("Invalid FirDeclarationOrigin ${origin::class.simpleName}") {
withFirAttachment("firToGetOrigin", this@ktSymbolOrigin)
}
} }
} }
FirDeclarationOrigin.ImportedFromObject -> { FirDeclarationOrigin.ImportedFromObject -> {
val importedFromObjectData = (this as FirCallableDeclaration).importedFromObjectData val importedFromObjectData = (this as FirCallableDeclaration).importedFromObjectData
?: error("Declaration has ImportedFromObject origin, but no importedFromObjectData present") ?: errorWithAttachment("Declaration has ImportedFromObject origin, but no importedFromObjectData present") {
withFirAttachment("firToGetOrigin", this@ktSymbolOrigin)
}
importedFromObjectData.original.ktSymbolOrigin() importedFromObjectData.original.ktSymbolOrigin()
} }
FirDeclarationOrigin.WrappedIntegerOperator -> { FirDeclarationOrigin.WrappedIntegerOperator -> {
val original = (this as FirSimpleFunction).originalForWrappedIntegerOperator?.fir val original = (this as FirSimpleFunction).originalForWrappedIntegerOperator?.fir
?: error("Declaration has WrappedIntegerOperator origin, but no originalForWrappedIntegerOperator present") ?: firErrorWithAttachment(
"Declaration has WrappedIntegerOperator origin, but no originalForWrappedIntegerOperator present",
fir = this
)
original.ktSymbolOrigin() original.ktSymbolOrigin()
} }
is FirDeclarationOrigin.Plugin -> KtSymbolOrigin.PLUGIN is FirDeclarationOrigin.Plugin -> KtSymbolOrigin.PLUGIN
FirDeclarationOrigin.RenamedForOverride -> KtSymbolOrigin.JAVA FirDeclarationOrigin.RenamedForOverride -> KtSymbolOrigin.JAVA
FirDeclarationOrigin.SubstitutionOverride -> KtSymbolOrigin.SUBSTITUTION_OVERRIDE FirDeclarationOrigin.SubstitutionOverride -> KtSymbolOrigin.SUBSTITUTION_OVERRIDE
FirDeclarationOrigin.DynamicScope -> throw InvalidFirDeclarationOriginForSymbol(this) FirDeclarationOrigin.DynamicScope -> errorWithAttachment("Invalid FirDeclarationOrigin ${origin::class.simpleName}") {
withFirAttachment("firToGetOrigin", this@ktSymbolOrigin)
}
} }
class InvalidFirDeclarationOriginForSymbol(declaration: FirDeclaration) :
IllegalStateException("Invalid FirDeclarationOrigin ${declaration.origin::class.simpleName} for ${declaration.render()}")
@@ -10,6 +10,9 @@ import org.jetbrains.kotlin.analysis.api.fir.components.KtFirAnalysisSessionComp
import org.jetbrains.kotlin.analysis.api.symbols.* 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.getOrBuildFirFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.resolveToFirSymbolOfType 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.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass
import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.render
@@ -20,6 +23,7 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.utils.errorWithAttachment
internal class KtFirSymbolProvider( internal class KtFirSymbolProvider(
override val analysisSession: KtFirAnalysisSession, override val analysisSession: KtFirAnalysisSession,
@@ -28,8 +32,9 @@ internal class KtFirSymbolProvider(
override fun getParameterSymbol(psi: KtParameter): KtVariableLikeSymbol { override fun getParameterSymbol(psi: KtParameter): KtVariableLikeSymbol {
return when { return when {
psi.isFunctionTypeParameter -> error( psi.isFunctionTypeParameter -> firErrorWithAttachment(
"Creating KtValueParameterSymbol for function type parameter is not possible. Please see the KDoc of getParameterSymbol" "Creating KtValueParameterSymbol for function type parameter is not possible. Please see the KDoc of getParameterSymbol",
psi = psi,
) )
psi.isLoopParameter -> { psi.isLoopParameter -> {
@@ -63,7 +68,10 @@ internal class KtFirSymbolProvider(
} }
is FirAnonymousFunctionSymbol -> firSymbolBuilder.functionLikeBuilder.buildAnonymousFunctionSymbol(firSymbol) is FirAnonymousFunctionSymbol -> firSymbolBuilder.functionLikeBuilder.buildAnonymousFunctionSymbol(firSymbol)
else -> error("Unexpected ${firSymbol.fir.renderWithType()}") else -> errorWithAttachment("Unexpected ${firSymbol::class}") {
withFirSymbolAttachment("firSymbol", firSymbol)
withPsiAttachment("function", psi)
}
} }
} }
@@ -117,7 +125,10 @@ internal class KtFirSymbolProvider(
val firClass = val firClass =
when (val firClassLike = psi.resolveToFirSymbolOfType<FirClassLikeSymbol<*>>(firResolveSession)) { when (val firClassLike = psi.resolveToFirSymbolOfType<FirClassLikeSymbol<*>>(firResolveSession)) {
is FirTypeAliasSymbol -> firClassLike.fullyExpandedClass(firResolveSession.useSiteFirSession) is FirTypeAliasSymbol -> firClassLike.fullyExpandedClass(firResolveSession.useSiteFirSession)
?: error("${firClassLike.fir.render()} should be expanded to the expected type alias") ?: errorWithAttachment("${firClassLike.fir::class} should be expanded to the expected type alias") {
withFirSymbolAttachment("firClassLikeSymbol", firClassLike)
withPsiAttachment("ktClassOrObject", psi)
}
is FirAnonymousObjectSymbol -> firClassLike is FirAnonymousObjectSymbol -> firClassLike
is FirRegularClassSymbol -> firClassLike is FirRegularClassSymbol -> firClassLike
} }
@@ -17,6 +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.KtFunctionalType
import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.firErrorWithAttachment
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.isExtensionFunctionType import org.jetbrains.kotlin.fir.types.isExtensionFunctionType
import org.jetbrains.kotlin.fir.types.isSuspendFunctionType import org.jetbrains.kotlin.fir.types.isSuspendFunctionType
@@ -32,7 +33,7 @@ internal class KtFirFunctionalType(
override val classId: ClassId get() = withValidityAssertion { coneType.lookupTag.classId } override val classId: ClassId get() = withValidityAssertion { coneType.lookupTag.classId }
override val classSymbol: KtClassLikeSymbol by cached { override val classSymbol: KtClassLikeSymbol by cached {
builder.classifierBuilder.buildClassLikeSymbolByLookupTag(coneType.lookupTag) builder.classifierBuilder.buildClassLikeSymbolByLookupTag(coneType.lookupTag)
?: error("Class ${coneType.lookupTag} was not found") ?: firErrorWithAttachment("Class was not found", coneType = coneType)
} }
override val typeArguments: List<KtTypeArgument> by cached { override val typeArguments: List<KtTypeArgument> by cached {
coneType.typeArguments.map { typeArgument -> coneType.typeArguments.map { typeArgument ->
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
import org.jetbrains.kotlin.analysis.api.symbols.KtTypeParameterSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtTypeParameterSymbol
import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability
import org.jetbrains.kotlin.analysis.api.types.KtTypeParameterType import org.jetbrains.kotlin.analysis.api.types.KtTypeParameterType
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.firErrorWithAttachment
import org.jetbrains.kotlin.fir.types.ConeTypeParameterType import org.jetbrains.kotlin.fir.types.ConeTypeParameterType
import org.jetbrains.kotlin.fir.types.renderForDebugging import org.jetbrains.kotlin.fir.types.renderForDebugging
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -26,7 +27,7 @@ internal class KtFirTypeParameterType(
override val name: Name get() = withValidityAssertion { coneType.lookupTag.name } override val name: Name get() = withValidityAssertion { coneType.lookupTag.name }
override val symbol: KtTypeParameterSymbol by cached { override val symbol: KtTypeParameterSymbol by cached {
builder.classifierBuilder.buildTypeParameterSymbolByLookupTag(coneType.lookupTag) builder.classifierBuilder.buildTypeParameterSymbolByLookupTag(coneType.lookupTag)
?: error("Type parameter ${coneType.lookupTag} was not found") ?: firErrorWithAttachment("Type parameter was not found", coneType = coneType)
} }
override val annotationsList: KtAnnotationsList by cached { override val annotationsList: KtAnnotationsList by cached {
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol
import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability
import org.jetbrains.kotlin.analysis.api.types.KtUsualClassType import org.jetbrains.kotlin.analysis.api.types.KtUsualClassType
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.firErrorWithAttachment
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.renderForDebugging import org.jetbrains.kotlin.fir.types.renderForDebugging
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
@@ -27,7 +28,7 @@ internal class KtFirUsualClassType(
override val classId: ClassId get() = withValidityAssertion { coneType.lookupTag.classId } override val classId: ClassId get() = withValidityAssertion { coneType.lookupTag.classId }
override val classSymbol: KtClassLikeSymbol by cached { override val classSymbol: KtClassLikeSymbol by cached {
builder.classifierBuilder.buildClassLikeSymbolByLookupTag(coneType.lookupTag) builder.classifierBuilder.buildClassLikeSymbolByLookupTag(coneType.lookupTag)
?: error("Class ${coneType.lookupTag} was not found") ?: firErrorWithAttachment("Class was not found", coneType = coneType)
} }
override val typeArguments: List<KtTypeArgument> by cached { override val typeArguments: List<KtTypeArgument> by cached {
coneType.typeArguments.map { typeArgument -> coneType.typeArguments.map { typeArgument ->
@@ -0,0 +1,26 @@
/*
* 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.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.low.level.api.fir.util.withPsiAttachment
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)
if (symbol is KtFirSymbol<*>) {
val symbolFir = symbol.firSymbol.fir
withFirAttachment("${name}Fir", symbolFir)
}
return this
}
@@ -5,8 +5,12 @@
package org.jetbrains.kotlin.analysis.utils.errors package org.jetbrains.kotlin.analysis.utils.errors
import org.jetbrains.kotlin.utils.errorWithAttachment
public fun unexpectedElementError(elementName: String, element: Any?): Nothing { public fun unexpectedElementError(elementName: String, element: Any?): Nothing {
error("Unexpected $elementName ${element?.let { it::class.simpleName }}") errorWithAttachment("Unexpected $elementName ${element?.let { it::class.simpleName }}") {
withAttachment("element", element)
}
} }
public inline fun <reified ELEMENT> unexpectedElementError(element: Any?): Nothing { public inline fun <reified ELEMENT> unexpectedElementError(element: Any?): Nothing {
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir
import org.jetbrains.kotlin.fir.declarations.FirDeclaration 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.api.FirDeclarationDesignation
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.firErrorWithAttachment
abstract class ContextByDesignationCollector<C : Any>(private val designation: FirDeclarationDesignation) { abstract class ContextByDesignationCollector<C : Any>(private val designation: FirDeclarationDesignation) {
private var context: C? = null private var context: C? = null
@@ -56,7 +57,7 @@ private class FirDesignationState(val designation: FirDeclarationDesignation) {
val currentDeclaration: FirDeclaration val currentDeclaration: FirDeclaration
get() = currentDeclarationIfPresent get() = currentDeclarationIfPresent
?: error("Went inside target declaration") ?: firErrorWithAttachment("Went inside target declaration")
fun goNext() { fun goNext() {
if (canGoNext()) { 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.LLFirNotUnderContentRootResolvableResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableResolveSession 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.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.project.structure.*
import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker
import org.jetbrains.kotlin.analysis.utils.caches.strongCachedValue import org.jetbrains.kotlin.analysis.utils.caches.strongCachedValue
@@ -86,7 +87,9 @@ internal class LLFirResolveSessionService(project: Project) {
} }
else -> { 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 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.getContainingFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirAttachment
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.containingClass import org.jetbrains.kotlin.fir.containingClass
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.classId import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.declarations.utils.isLocal 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.renderWithType
import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.resolve.toFirRegularClass import org.jetbrains.kotlin.fir.resolve.toFirRegularClass
import org.jetbrains.kotlin.fir.symbols.impl.LookupTagInternals import org.jetbrains.kotlin.fir.symbols.impl.LookupTagInternals
import org.jetbrains.kotlin.utils.checkWithAttachment
import org.jetbrains.kotlin.utils.errorWithAttachment
class FirDeclarationDesignationWithFile( class FirDeclarationDesignationWithFile(
path: List<FirDeclaration>, path: List<FirDeclaration>,
@@ -77,21 +80,28 @@ private fun collectDesignationPath(declaration: FirDeclaration): List<FirDeclara
else -> return null else -> return null
} ?: return emptyList() } ?: return emptyList()
require(containingClass is FirRegularClass) { checkWithAttachment(containingClass is FirRegularClass, { "FirRegularClass as containing declaration expected" }) {
"FirRegularClass as containing declaration expected but found ${containingClass.renderWithType()}" it.withFirAttachment("containingClassFir", containingClass)
} }
return if (!containingClass.isLocal) containingClass.collectForNonLocal().asReversed() else null return if (!containingClass.isLocal) containingClass.collectForNonLocal().asReversed() else null
} }
fun FirDeclaration.collectDesignation(firFile: FirFile): FirDeclarationDesignationWithFile = 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 = 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 = fun FirDeclaration.collectDesignationWithFile(): FirDeclarationDesignationWithFile =
tryCollectDesignationWithFile() 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? = fun FirDeclaration.tryCollectDesignation(firFile: FirFile): FirDeclarationDesignationWithFile? =
collectDesignationPath(this)?.let { collectDesignationPath(this)?.let {
@@ -5,16 +5,33 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.api 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.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.psi.KtElement
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
import org.jetbrains.kotlin.utils.withAttachmentDetailed
import java.util.* import java.util.*
import kotlin.reflect.KClass import kotlin.reflect.KClass
class InvalidFirElementTypeException( class InvalidFirElementTypeException(
actualFirClass: KClass<*>?, actualFirElement: Any?,
ktElement: KtElement?, ktElement: KtElement?,
expectedFirClasses: List<KClass<*>>, 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 { override val message: String = buildString {
if (ktElement != null) { if (ktElement != null) {
append("For $ktElement with text `${ktElement.text}`, ") append("For $ktElement with text `${ktElement.text}`, ")
@@ -25,8 +42,8 @@ class InvalidFirElementTypeException(
else -> "One of [${expectedFirClasses.joinToString()}] element types expected, but" else -> "One of [${expectedFirClasses.joinToString()}] element types expected, but"
} }
append(if (ktElement == null) message else message.replaceFirstChar { it.lowercase(Locale.getDefault()) }) append(if (ktElement == null) message else message.replaceFirstChar { it.lowercase(Locale.getDefault()) })
if (actualFirClass != null) { if (actualFirElement != null) {
append(" ${actualFirClass.simpleName} found") append(" ${actualFirElement::class.simpleName} found")
} else { } else {
append(" no element found") append(" no element found")
} }
@@ -39,5 +56,5 @@ fun throwUnexpectedFirElementError(
ktElement: KtElement? = null, ktElement: KtElement? = null,
vararg expectedFirClasses: KClass<*> vararg expectedFirClasses: KClass<*>
): Nothing { ): 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.annotations.TestOnly
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.createEmptySession 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.builtins.StandardNames
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.builder.BodyBuildingMode 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) { return if (isVararg) {
rendered.asArrayType() rendered.asArrayType()
@@ -165,7 +166,7 @@ object KtDeclarationAndFirDeclarationEqualityChecker {
} }
append(typeRef.renderTypeAsKotlinType()) append(typeRef.renderTypeAsKotlinType())
} }
else -> error("Invalid type projection $this") else -> firErrorWithAttachment("Invalid type reference", fir = this)
} }
private fun isTheSameTypes( private fun isTheSameTypes(
@@ -200,7 +201,7 @@ object KtDeclarationAndFirDeclarationEqualityChecker {
// Can be present as return type // Can be present as return type
"${lowerBound.renderTypeAsKotlinType()}..${upperBound.renderTypeAsKotlinType()}" "${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('/', '.') }.replace('/', '.')
return rendered + nullability.suffix 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.lazy.resolve.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirResolvableModuleSession 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.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.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.project.structure.getKtModule
import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext
import org.jetbrains.kotlin.analysis.utils.printer.parentOfType 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.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.isAncestor import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import org.jetbrains.kotlin.utils.errorWithAttachment
object LowLevelFirApiFacadeForResolveOnAir { object LowLevelFirApiFacadeForResolveOnAir {
@@ -87,7 +91,10 @@ object LowLevelFirApiFacadeForResolveOnAir {
} }
declaration.accept(expressionLocator) 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( fun onAirGetTowerContextProvider(
@@ -152,7 +159,10 @@ object LowLevelFirApiFacadeForResolveOnAir {
val sameDeclarationInOriginalFile = PsiTreeUtil.findSameElementInCopy(dependencyNonLocalDeclaration, originalKtFile) 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( recordOriginalDeclaration(
targetDeclaration = dependencyNonLocalDeclaration, targetDeclaration = dependencyNonLocalDeclaration,
@@ -183,7 +193,10 @@ object LowLevelFirApiFacadeForResolveOnAir {
fileAnnotation = annotationEntry, fileAnnotation = annotationEntry,
replacement = replacement 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 val declarationResolver = llFirResolvableSession.moduleComponents.lazyFirDeclarationsResolver
declarationResolver.resolveFileAnnotations( declarationResolver.resolveFileAnnotations(
@@ -9,6 +9,7 @@ import com.intellij.psi.PsiClass
import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiJavaFile
import com.intellij.psi.PsiTypeParameter 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.sessions.LLFirSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withPsiAttachment
import org.jetbrains.kotlin.asJava.KtLightClassMarker import org.jetbrains.kotlin.asJava.KtLightClassMarker
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent 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.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.utils.errorWithAttachment
class LLFirFirClassByPsiClassProvider(private val session: LLFirSession) : FirSessionComponent { class LLFirFirClassByPsiClassProvider(private val session: LLFirSession) : FirSessionComponent {
fun getFirClass(psiClass: PsiClass): FirRegularClassSymbol? { fun getFirClass(psiClass: PsiClass): FirRegularClassSymbol? {
@@ -42,8 +44,11 @@ class LLFirFirClassByPsiClassProvider(private val session: LLFirSession) : FirSe
val classId = psiClass.classIdIfNonLocal val classId = psiClass.classIdIfNonLocal
?: error("No classId for non-local class") ?: error("No classId for non-local class")
val provider = session.nullableJavaSymbolProvider ?: session.symbolProvider val provider = session.nullableJavaSymbolProvider ?: session.symbolProvider
val symbol = (provider.getClassLikeSymbolByClassId(classId) val symbol = provider.getClassLikeSymbolByClassId(classId)
?: error("No classifier found with $classId")) ?: errorWithAttachment("No classifier found") {
withPsiAttachment("psiClass", psiClass)
withAttachment("classId", classId.asString())
}
return symbol as FirRegularClassSymbol 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.FirTowerContextProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLocalContainingOrThisDeclaration 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.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.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.FirDeclarationForCompiledElementSearcher
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.findSourceNonLocalFirDeclaration 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.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.KtModule
import org.jetbrains.kotlin.analysis.project.structure.getKtModule import org.jetbrains.kotlin.analysis.project.structure.getKtModule
import org.jetbrains.kotlin.analysis.utils.errors.requireIsInstance 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.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.utils.errorWithAttachment
import org.jetbrains.kotlin.utils.withAttachmentDetailed
internal abstract class LLFirResolvableResolveSession( internal abstract class LLFirResolvableResolveSession(
private val sessionProvider: LLFirSessionProvider, private val sessionProvider: LLFirSessionProvider,
@@ -98,7 +103,10 @@ internal abstract class LLFirResolvableResolveSession(
"Declaration should be resolvable module, instead it had ${module::class}" "Declaration should be resolvable module, instead it had ${module::class}"
} }
val nonLocalNamedDeclaration = ktDeclaration.getNonLocalContainingOrThisDeclaration() 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) { if (ktDeclaration == nonLocalNamedDeclaration) {
val session = sessionProvider.getResolvableSession(module) val session = sessionProvider.getResolvableSession(module)
@@ -30,17 +30,20 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid
is KtNamedFunction -> findNonLocalFunction(ktDeclaration) is KtNamedFunction -> findNonLocalFunction(ktDeclaration)
is KtProperty -> findNonLocalProperty(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 { private fun findNonLocalEnumEntry(declaration: KtEnumEntry): FirEnumEntry {
require(!declaration.isLocal) require(!declaration.isLocal)
val classId = declaration.containingClassOrObject?.getClassId() 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) 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 { return (classCandidate.fir as? FirRegularClass)?.declarations?.first {
it is FirEnumEntry && it.name == declaration.nameAsName it is FirEnumEntry && it.name == declaration.nameAsName
@@ -49,26 +52,31 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid
private fun findNonLocalClassLikeDeclaration(declaration: KtClassLikeDeclaration): FirClassLikeDeclaration { private fun findNonLocalClassLikeDeclaration(declaration: KtClassLikeDeclaration): FirClassLikeDeclaration {
val classId = declaration.getClassId() 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) 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 return classCandidate.fir
} }
private fun findConstructorOfNonLocalClass(declaration: KtConstructor<*>): FirConstructor { private fun findConstructorOfNonLocalClass(declaration: KtConstructor<*>): FirConstructor {
val containingClass = declaration.containingClassOrObject val containingClass = declaration.containingClassOrObject
?: error("Constructor must have outer class: ${declaration.getElementTextInContext()}") ?: firErrorWithAttachment("Constructor must have outer class", psi = declaration)
require(!containingClass.isLocal) require(!containingClass.isLocal)
val classId = containingClass.getClassId() 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 = val constructorCandidate =
symbolProvider.getClassDeclaredConstructors(classId) symbolProvider.getClassDeclaredConstructors(classId)
.singleOrNull { representSameConstructor(declaration, it.fir) } .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 return constructorCandidate.fir
} }
@@ -79,7 +87,7 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid
val functionCandidate = val functionCandidate =
symbolProvider.findFunctionCandidates(declaration) symbolProvider.findFunctionCandidates(declaration)
.singleOrNull { KtDeclarationAndFirDeclarationEqualityChecker.representsTheSameDeclaration(declaration, it.fir) } .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 return functionCandidate.fir
} }
@@ -90,7 +98,7 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid
val propertyCandidate = val propertyCandidate =
symbolProvider.findPropertyCandidates(declaration) symbolProvider.findPropertyCandidates(declaration)
.singleOrNull { KtDeclarationAndFirDeclarationEqualityChecker.representsTheSameDeclaration(declaration, it.fir) } .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 return propertyCandidate.fir
} }
@@ -112,7 +120,7 @@ private fun FirSymbolProvider.findCallableCandidates(
} }
val containerClassId = declaration.containingClassOrObject?.getClassId() 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) + return getClassDeclaredFunctionSymbols(containerClassId, declaration.nameAsSafeName) +
getClassDeclaredPropertySymbols(containerClassId, declaration.nameAsSafeName) getClassDeclaredPropertySymbols(containerClassId, declaration.nameAsSafeName)
@@ -17,6 +17,6 @@ fun FirDeclaration.getContainingFile(): FirFile? {
is FirFile -> this is FirFile -> this
is FirCallableDeclaration -> provider.getFirCallableContainerFile(symbol) is FirCallableDeclaration -> provider.getFirCallableContainerFile(symbol)
is FirClassLikeDeclaration -> provider.getFirClassifierContainerFile(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 //TODO test what way faster
findSourceNonLocalFirDeclarationByProvider(firFileBuilder, provider, containerFirFile)?.let { return it } findSourceNonLocalFirDeclarationByProvider(firFileBuilder, provider, containerFirFile)?.let { return it }
findSourceOfNonLocalFirDeclarationByTraversingWholeTree(firFileBuilder, 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( internal fun KtDeclaration.findFirDeclarationForAnyFirSourceDeclaration(
@@ -45,7 +45,7 @@ internal fun KtDeclaration.findFirDeclarationForAnyFirSourceDeclaration(
firDeclaration.psi == this || firDeclaration.psi == originalDeclaration firDeclaration.psi == this || firDeclaration.psi == originalDeclaration
} }
return fir 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( internal inline fun <reified F : FirDeclaration> KtDeclaration.findFirDeclarationForAnyFirSourceDeclarationOfType(
@@ -95,12 +95,12 @@ private fun KtDeclaration.findSourceNonLocalFirDeclarationByProvider(
} }
this is KtConstructor<*> -> { this is KtConstructor<*> -> {
val containingClass = containingClassOrObject 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 val containerClassFir = containingClass.findFir(provider) as? FirRegularClass ?: return null
containerClassFir.declarations.firstOrNull { it.psi === this } containerClassFir.declarations.firstOrNull { it.psi === this }
} }
this is KtTypeAlias -> findFir(provider) 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 } 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 internal val FirDeclaration.ktDeclaration: KtDeclaration
get() { get() {
val psi = psi val psi = psi
?: error("PSI element was not found for${render()}") ?: firErrorWithAttachment("PSI element was not found", fir = this)
return when (psi) { return when (psi) {
is KtDeclaration -> psi is KtDeclaration -> psi
is KtObjectLiteralExpression -> psi.objectDeclaration is KtObjectLiteralExpression -> psi.objectDeclaration
else -> error( else -> firErrorWithAttachment(
""" "FirDeclaration.psi (${this::class.simpleName}) should be KtDeclaration but was ${psi::class.simpleName}",
FirDeclaration.psi (${this::class.simpleName}) should be KtDeclaration but was ${psi::class.simpleName} fir = this,
${(psi as? KtElement)?.getElementTextInContext() ?: psi.text} psi = psi,
${render()}
""".trimIndent()
) )
} }
} }
@@ -29,9 +29,19 @@ open class KotlinExceptionWithAttachments : RuntimeException, ExceptionWithAttac
} }
} }
fun <T> 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) @OptIn(ExperimentalContracts::class)
inline fun checkWithAttachment(value: Boolean, lazyMessage: () -> String, attachments: (KotlinExceptionWithAttachments) -> Unit = {}) { inline fun checkWithAttachment(value: Boolean, lazyMessage: () -> String, attachments: (KotlinExceptionWithAttachments) -> Unit = {}) {
contract { returns() implies(value) } contract { returns() implies (value) }
if (!value) { if (!value) {
val e = KotlinExceptionWithAttachments(lazyMessage()) val e = KotlinExceptionWithAttachments(lazyMessage())
@@ -39,3 +49,14 @@ inline fun checkWithAttachment(value: Boolean, lazyMessage: () -> String, attach
throw e throw e
} }
} }
inline fun errorWithAttachment(
message: String,
cause: Throwable? = null,
attachments: KotlinExceptionWithAttachments.() -> Unit = {}
): Nothing {
val exception = KotlinExceptionWithAttachments(message, cause)
attachments(exception)
throw exception
}