From 5f20910c79388e6de5944b2d76c3d98f2554ef07 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Tue, 11 Aug 2020 13:58:23 +0300 Subject: [PATCH] FIR IDE: always try to find symbol origin in overridden symbols --- .../frontend/api/fir/KtSymbolByFirBuilder.kt | 37 +++++++++++-------- .../api/fir/scopes/KtFirDelegatingScope.kt | 14 +------ .../frontend/api/fir/symbols/KtFirSymbol.kt | 19 +++++----- .../idea/frontend/api/fir/utils/firUtils.kt | 15 ++++++++ 4 files changed, 48 insertions(+), 37 deletions(-) create mode 100644 idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/firUtils.kt diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtSymbolByFirBuilder.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtSymbolByFirBuilder.kt index 1b2031b3b20..eb38cd25ae1 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtSymbolByFirBuilder.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtSymbolByFirBuilder.kt @@ -9,9 +9,11 @@ import com.google.common.collect.MapMaker import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl -import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider +import org.jetbrains.kotlin.fir.resolve.firProvider +import org.jetbrains.kotlin.fir.resolve.firSymbolProvider import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol @@ -32,10 +34,12 @@ import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirFlexibleType import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirIntersectionType import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirTypeArgumentWithVariance import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirTypeParameterType +import org.jetbrains.kotlin.idea.frontend.api.fir.utils.threadLocal import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef import org.jetbrains.kotlin.idea.frontend.api.symbols.* import org.jetbrains.kotlin.idea.frontend.api.types.KtType import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil +import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import java.util.concurrent.ConcurrentMap @@ -43,8 +47,6 @@ import java.util.concurrent.ConcurrentMap * Maps FirElement to KtSymbol & ConeType to KtType, thread safe */ internal class KtSymbolByFirBuilder private constructor( - firProvider: FirSymbolProvider, - typeCheckerContext: ConeTypeCheckerContext, private val project: Project, resolveState: FirModuleResolveState, override val token: ValidityToken, @@ -52,16 +54,21 @@ internal class KtSymbolByFirBuilder private constructor( private val symbolsCache: BuilderCache, private val typesCache: BuilderCache ) : ValidityTokenOwner { + private val typeCheckerContext by threadLocal { + ConeTypeCheckerContext( + isErrorTypeEqualsToAnything = true, + isStubTypeEqualsToAnything = true, + resolveState.firIdeLibrariesSession + ) + } + + private val firProvider get() = resolveState.firIdeSourcesSession.firSymbolProvider constructor( - firProvider: FirSymbolProvider, - typeCheckerContext: ConeTypeCheckerContext, resolveState: FirModuleResolveState, project: Project, token: ValidityToken ) : this( - firProvider = firProvider, - typeCheckerContext = typeCheckerContext, project = project, token = token, resolveState = resolveState, @@ -70,15 +77,11 @@ internal class KtSymbolByFirBuilder private constructor( typesCache = BuilderCache() ) - private val firProvider by weakRef(firProvider) private val resolveState by weakRef(resolveState) - private val typeCheckerContext by weakRef(typeCheckerContext) fun createReadOnlyCopy(newResolveState: FirModuleResolveState): KtSymbolByFirBuilder { check(!withReadOnlyCaching) { "Cannot create readOnly KtSymbolByFirBuilder from a readonly one" } return KtSymbolByFirBuilder( - firProvider, - typeCheckerContext, project, token = token, resolveState = newResolveState, @@ -126,8 +129,8 @@ internal class KtSymbolByFirBuilder private constructor( fun buildFirConstructorParameter(fir: FirValueParameterImpl) = symbolsCache.cache(fir) { KtFirConstructorValueParameterSymbol(fir, resolveState, token, this) } - fun buildFunctionSymbol(fir: FirSimpleFunction, forcedOrigin: FirDeclarationOrigin? = null) = symbolsCache.cache(fir) { - KtFirFunctionSymbol(fir, resolveState, token, this, forcedOrigin) + fun buildFunctionSymbol(fir: FirSimpleFunction) = symbolsCache.cache(fir) { + KtFirFunctionSymbol(fir, resolveState, token, this) } fun buildConstructorSymbol(fir: FirConstructor) = symbolsCache.cache(fir) { KtFirConstructorSymbol(fir, resolveState, token, this) } @@ -139,10 +142,10 @@ internal class KtSymbolByFirBuilder private constructor( fun buildAnonymousFunctionSymbol(fir: FirAnonymousFunction) = symbolsCache.cache(fir) { KtFirAnonymousFunctionSymbol(fir, resolveState, token, this) } - fun buildVariableSymbol(fir: FirProperty, forcedOrigin: FirDeclarationOrigin? = null): KtVariableSymbol = symbolsCache.cache(fir) { + fun buildVariableSymbol(fir: FirProperty): KtVariableSymbol = symbolsCache.cache(fir) { when { fir.isLocal -> KtFirLocalVariableSymbol(fir, resolveState, token, this) - else -> KtFirPropertySymbol(fir, resolveState, token, this, forcedOrigin) + else -> KtFirPropertySymbol(fir, resolveState, token, this) } } @@ -154,6 +157,10 @@ internal class KtSymbolByFirBuilder private constructor( (firProvider.getSymbolByLookupTag(lookupTag) as? FirTypeParameterSymbol)?.fir?.let(::buildTypeParameterSymbol) } + fun buildClassLikeSymbolByClassId(classId: ClassId, firSession: FirSession): FirRegularClass? = withValidityAssertion { + firSession.firProvider.getClassLikeSymbolByFqName(classId)?.fir as? FirRegularClass + } + fun createPackageSymbolIfOneExists(packageFqName: FqName): KtFirPackageSymbol? { val exists = PackageIndexUtil.packageExists(packageFqName, GlobalSearchScope.allScope(project), project) diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/scopes/KtFirDelegatingScope.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/scopes/KtFirDelegatingScope.kt index a3793cb2c52..b0e0b56c66a 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/scopes/KtFirDelegatingScope.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/scopes/KtFirDelegatingScope.kt @@ -21,7 +21,6 @@ import org.jetbrains.kotlin.idea.frontend.api.fir.utils.cached import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScope import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassLikeSymbol -import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion import org.jetbrains.kotlin.name.Name @@ -60,27 +59,18 @@ internal abstract class KtFirDelegatingScope( } -private fun FirBasedSymbol<*>.realDeclarationOrigin(): FirDeclarationOrigin? { - if (this !is PossiblyFirFakeOverrideSymbol<*, *> || !isFakeOverride) return null - var current: FirBasedSymbol<*>? = this.overriddenSymbol - while (current is PossiblyFirFakeOverrideSymbol<*, *> && current.isFakeOverride) { - current = current.overriddenSymbol - } - return (current?.fir as? FirDeclaration)?.origin -} - internal fun FirScope.getCallableSymbols(callableNames: Collection, builder: KtSymbolByFirBuilder) = sequence { callableNames.forEach { name -> val callables = mutableListOf() processFunctionsByName(name) { firSymbol -> (firSymbol.fir as? FirSimpleFunction)?.let { fir -> - callables.add(builder.buildFunctionSymbol(fir, firSymbol.realDeclarationOrigin())) + callables.add(builder.buildFunctionSymbol(fir)) } } processPropertiesByName(name) { firSymbol -> val symbol = when { firSymbol is FirPropertySymbol && firSymbol.isFakeOverride -> { - builder.buildVariableSymbol(firSymbol.fir, firSymbol.realDeclarationOrigin()) + builder.buildVariableSymbol(firSymbol.fir) } else -> builder.buildCallableSymbol(firSymbol.fir) } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirSymbol.kt index a7bc8ace3e4..e38126e59c1 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirSymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirSymbol.kt @@ -7,30 +7,29 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.symbols import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin -import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.idea.frontend.api.ValidityTokenOwner import org.jetbrains.kotlin.idea.frontend.api.fir.utils.FirRef +import org.jetbrains.kotlin.idea.frontend.api.fir.utils.overriddenDeclaration import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbolOrigin -import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion internal interface KtFirSymbol : KtSymbol, ValidityTokenOwner { val firRef: FirRef - override val origin: KtSymbolOrigin get() = firRef.withFir { it.origin.asKtSymbolOrigin() } + override val origin: KtSymbolOrigin get() = firRef.withFir { it.ktSymbolOrigin() } } -internal fun FirDeclarationOrigin.asKtSymbolOrigin() = when (this) { + +private tailrec fun FirDeclaration.ktSymbolOrigin(): KtSymbolOrigin = when (origin) { FirDeclarationOrigin.Source -> KtSymbolOrigin.SOURCE FirDeclarationOrigin.Library -> KtSymbolOrigin.LIBRARY FirDeclarationOrigin.Java -> KtSymbolOrigin.JAVA FirDeclarationOrigin.SamConstructor -> KtSymbolOrigin.SAM_CONSTRUCTOR - FirDeclarationOrigin.Synthetic -> throw InvalidFirDeclarationOriginForSymbol(this) - FirDeclarationOrigin.FakeOverride -> throw InvalidFirDeclarationOriginForSymbol(this) - FirDeclarationOrigin.ImportedFromObject -> throw InvalidFirDeclarationOriginForSymbol(this) - FirDeclarationOrigin.IntersectionOverride -> throw InvalidFirDeclarationOriginForSymbol(this) - FirDeclarationOrigin.Enhancement -> KtSymbolOrigin.JAVA // TODO - is FirDeclarationOrigin.Plugin -> throw InvalidFirDeclarationOriginForSymbol(this) + FirDeclarationOrigin.Enhancement -> KtSymbolOrigin.JAVA + else -> { + val overridden = overriddenDeclaration ?: throw InvalidFirDeclarationOriginForSymbol(origin) + overridden.ktSymbolOrigin() + } } class InvalidFirDeclarationOriginForSymbol(origin: FirDeclarationOrigin) : diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/firUtils.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/firUtils.kt new file mode 100644 index 00000000000..3f3c7af4249 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/firUtils.kt @@ -0,0 +1,15 @@ +/* + * Copyright 2010-2020 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.idea.frontend.api.fir.utils + +import org.jetbrains.kotlin.fir.FirSymbolOwner +import org.jetbrains.kotlin.fir.declarations.FirDeclaration +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol + +internal inline val FirDeclaration.overriddenDeclaration: FirDeclaration? + get() { + val symbol = (this as? FirSymbolOwner<*>)?.symbol ?: return null + return (symbol as? FirCallableSymbol)?.overriddenSymbol?.fir as? FirDeclaration + } \ No newline at end of file