FIR IDE: always try to find symbol origin in overridden symbols

This commit is contained in:
Ilya Kirillov
2020-08-11 13:58:23 +03:00
parent a700d1fccb
commit 5f20910c79
4 changed files with 48 additions and 37 deletions
@@ -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<FirDeclaration, KtSymbol>,
private val typesCache: BuilderCache<ConeKotlinType, KtType>
) : 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)
@@ -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<S>(
}
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<Name>, builder: KtSymbolByFirBuilder) = sequence {
callableNames.forEach { name ->
val callables = mutableListOf<KtCallableSymbol>()
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)
}
@@ -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<F : FirDeclaration> : KtSymbol, ValidityTokenOwner {
val firRef: FirRef<F>
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) :
@@ -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
}