FIR IDE: introduce scopes for HL API

This commit is contained in:
Ilya Kirillov
2020-06-29 23:59:07 +03:00
parent 6596dc359b
commit f709e6acf3
12 changed files with 290 additions and 15 deletions
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.frontend.api
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScopeProvider
import org.jetbrains.kotlin.idea.frontend.api.symbols.*
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.name.ClassId
@@ -18,6 +19,7 @@ abstract class KtAnalysisSession(project: Project) : ValidityOwner {
override fun invalidationReason(): String = validityToken.invalidationReason()
abstract val symbolProvider: KtSymbolProvider
abstract val scopeProvider: KtScopeProvider
abstract fun getSmartCastedToTypes(expression: KtExpression): Collection<KtType>?
@@ -0,0 +1,41 @@
/*
* 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.scopes
import org.jetbrains.kotlin.idea.frontend.api.ValidityOwner
import org.jetbrains.kotlin.idea.frontend.api.symbols.*
import org.jetbrains.kotlin.name.Name
interface KtScope : ValidityOwner {
fun getAllNames(): Set<Name>
fun getCallableNames(): Set<Name>
fun getClassLikeSymbolNames(): Set<Name>
fun getAllSymbols(): Sequence<KtSymbol>
fun getCallableSymbols(): Sequence<KtSymbol>
fun getClassClassLikeSymbols(): Sequence<KtClassLikeSymbol>
fun containsName(name: Name): Boolean
}
interface KtMemberScope : KtScope {
val owner: KtClassOrObjectSymbol
}
interface KtDeclaredMemberScope : KtScope {
val owner: KtClassOrObjectSymbol
}
interface KtPackageScope : KtScope, KtSubstitutedScope<KtPackageScope> {
val owner: KtPackageSymbol
}
interface KtUnsubstitutedScope<S : KtScope> : KtScope {
fun substitute(/*substitution*/): KtSubstitutedScope<S> = TODO()
}
interface KtSubstitutedScope<S> : KtScope
@@ -0,0 +1,16 @@
/*
* 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.scopes
import org.jetbrains.kotlin.idea.frontend.api.ValidityOwner
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPackageSymbol
abstract class KtScopeProvider : ValidityOwner {
abstract fun getMemberScope(classSymbol: KtClassOrObjectSymbol): KtMemberScope
abstract fun getDeclaredMemberScope(classSymbol: KtClassOrObjectSymbol): KtDeclaredMemberScope
abstract fun getPackageScope(packageSymbol: KtPackageSymbol): KtPackageScope
}
@@ -21,7 +21,9 @@ import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.idea.fir.*
import org.jetbrains.kotlin.idea.fir.low.level.api.LowLevelFirApiFacade
import org.jetbrains.kotlin.idea.frontend.api.*
import org.jetbrains.kotlin.idea.frontend.api.fir.scopes.KtFirScopeProvider
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbolProvider
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScopeProvider
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbolProvider
@@ -59,6 +61,8 @@ constructor(
firSymbolBuilder
)
override val scopeProvider: KtScopeProvider = KtFirScopeProvider(token, firSymbolBuilder, firSession)
init {
assertIsValid()
}
@@ -39,7 +39,6 @@ import org.jetbrains.kotlin.idea.frontend.api.symbols.KtTypeParameterSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtVariableSymbol
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil
/**
* Maps FirElement to KtSymbol & ConeType to KtType, thread safe
@@ -0,0 +1,28 @@
/*
* 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.scopes
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
import org.jetbrains.kotlin.idea.frontend.api.ValidityOwner
import org.jetbrains.kotlin.idea.frontend.api.ValidityOwnerByValidityToken
import org.jetbrains.kotlin.idea.frontend.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirClassOrObjectSymbol
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtDeclaredMemberScope
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtUnsubstitutedScope
internal class KtFirDeclaredMemberScope(
override val owner: KtFirClassOrObjectSymbol,
override val token: ValidityOwner,
builder: KtSymbolByFirBuilder
) : KtFirDelegatingScope(builder),
KtDeclaredMemberScope,
KtUnsubstitutedScope<KtFirDelegatingScope>,
ValidityOwnerByValidityToken {
override val firScope: FirScope by weakRef(declaredMemberScope(owner.fir))
}
@@ -0,0 +1,82 @@
/*
* 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.scopes
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.processClassifiersByName
import org.jetbrains.kotlin.idea.frontend.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScope
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
import org.jetbrains.kotlin.psi.KtClass
internal abstract class KtFirDelegatingScope(private val builder: KtSymbolByFirBuilder) : KtScope {
abstract val firScope: FirScope
private var allNamesCached: Set<Name>? = null
override fun getAllNames(): Set<Name> = withValidityAssertion {
if (allNamesCached == null) {
allNamesCached = firScope.getCallableNames() + firScope.getClassifierNames()
}
allNamesCached!!
}
override fun getCallableNames(): Set<Name> = withValidityAssertion {
firScope.getCallableNames()
}
override fun getClassLikeSymbolNames(): Set<Name> = withValidityAssertion {
firScope.getClassifierNames()
}
override fun getAllSymbols(): Sequence<KtSymbol> = withValidityAssertion {
sequence {
yieldAll(getCallableSymbols())
yieldAll(getClassClassLikeSymbols())
}
}
override fun getCallableSymbols(): Sequence<KtSymbol> = withValidityAssertion {
sequence {
firScope.getCallableNames().forEach { name ->
val callables = mutableListOf<KtSymbol>()
firScope.processFunctionsByName(name) { firSymbol ->
(firSymbol.fir as? FirSimpleFunction)?.let { fir ->
callables.add(builder.buildFunctionSymbol(fir))
}
}
firScope.processPropertiesByName(name) { firSymbol ->
callables.add(builder.buildSymbol(firSymbol.fir))
}
yieldAll(callables)
}
}
}
override fun getClassClassLikeSymbols(): Sequence<KtClassLikeSymbol> = withValidityAssertion {
sequence {
firScope.getClassifierNames().forEach { name ->
val classLikeSymbols = mutableListOf<KtClassLikeSymbol>()
firScope.processClassifiersByName(name) { firSymbol ->
(firSymbol.fir as? FirClassLikeDeclaration<*>)?.let {
classLikeSymbols.add(builder.buildClassLikeSymbol(it))
}
}
yieldAll(classLikeSymbols)
}
}
}
override fun containsName(name: Name): Boolean = withValidityAssertion {
name in getAllNames()
}
}
@@ -0,0 +1,28 @@
/*
* 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.scopes
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.buildUseSiteMemberScope
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.idea.frontend.api.ValidityOwner
import org.jetbrains.kotlin.idea.frontend.api.ValidityOwnerByValidityToken
import org.jetbrains.kotlin.idea.frontend.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirClassOrObjectSymbol
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtMemberScope
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtUnsubstitutedScope
internal class KtFirMemberScope(
override val owner: KtFirClassOrObjectSymbol,
override val token: ValidityOwner,
builder: KtSymbolByFirBuilder
) : KtFirDelegatingScope(builder), KtMemberScope, KtUnsubstitutedScope<KtMemberScope>, ValidityOwnerByValidityToken {
override val firScope: FirScope by weakRef {
owner.fir.buildUseSiteMemberScope(owner.fir.session, ScopeSession())
}
}
@@ -0,0 +1,28 @@
/*
* 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.scopes
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
import org.jetbrains.kotlin.idea.frontend.api.ValidityOwner
import org.jetbrains.kotlin.idea.frontend.api.ValidityOwnerByValidityToken
import org.jetbrains.kotlin.idea.frontend.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirPackageSymbol
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtPackageScope
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPackageSymbol
internal class KtFirPackageScope(
override val owner: KtFirPackageSymbol,
override val token: ValidityOwner,
builder: KtSymbolByFirBuilder,
session: FirSession,
) : KtPackageScope, KtFirDelegatingScope(builder), ValidityOwnerByValidityToken {
override val firScope: FirScope by weakRef {
FirPackageMemberScope(owner.fqName, session)
}
}
@@ -0,0 +1,55 @@
/*
* 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.scopes
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.idea.frontend.api.ValidityOwner
import org.jetbrains.kotlin.idea.frontend.api.ValidityOwnerByValidityToken
import org.jetbrains.kotlin.idea.frontend.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirClassOrObjectSymbol
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirPackageSymbol
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtDeclaredMemberScope
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtMemberScope
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtPackageScope
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScopeProvider
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPackageSymbol
import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion
import java.util.*
internal class KtFirScopeProvider(
override val token: ValidityOwner,
private val builder: KtSymbolByFirBuilder,
session: FirSession
) : KtScopeProvider(), ValidityOwnerByValidityToken {
private val session by weakRef(session)
private val memberScopeCache = IdentityHashMap<KtClassOrObjectSymbol, KtMemberScope>()
private val declaredMemberScopeCache = IdentityHashMap<KtClassOrObjectSymbol, KtDeclaredMemberScope>()
private val packageMemberScopeCache = IdentityHashMap<KtPackageSymbol, KtPackageScope>()
override fun getMemberScope(classSymbol: KtClassOrObjectSymbol): KtMemberScope = withValidityAssertion {
memberScopeCache.getOrPut(classSymbol) {
check(classSymbol is KtFirClassOrObjectSymbol)
KtFirMemberScope(classSymbol, token, builder)
}
}
override fun getDeclaredMemberScope(classSymbol: KtClassOrObjectSymbol): KtDeclaredMemberScope = withValidityAssertion {
declaredMemberScopeCache.getOrPut(classSymbol) {
check(classSymbol is KtFirClassOrObjectSymbol)
KtFirDeclaredMemberScope(classSymbol, token, builder)
}
}
override fun getPackageScope(packageSymbol: KtPackageSymbol): KtPackageScope = withValidityAssertion {
packageMemberScopeCache.getOrPut(packageSymbol) {
check(packageSymbol is KtFirPackageSymbol)
KtFirPackageScope(packageSymbol, token, builder, session)
}
}
}
@@ -24,8 +24,8 @@ class KtFirPackageSymbol(
private val project: Project,
override val token: ValidityOwner
) : KtPackageSymbol(), ValidityOwnerByValidityToken {
override val psi: PsiElement by cached {
KtPackage(PsiManager.getInstance(project), fqName, GlobalSearchScope.allScope(project))
override val psi: PsiElement? by cached {
PsiPackageImpl(PsiManager.getInstance(project), fqName.asString().replace('/', '.'))
}
override val origin: KtSymbolOrigin
@@ -35,14 +35,4 @@ class KtFirPackageSymbol(
check(session is KtFirAnalysisSession)
session.firSymbolBuilder.createPackageSymbolIfOneExists(fqName)
}
}
class KtPackage(
manager: PsiManager,
private val fqName: FqName,
private val scope: GlobalSearchScope
) : PsiPackageImpl(manager, fqName.asString()) {
override fun copy() = KtPackage(manager, fqName, scope)
override fun isValid(): Boolean = PackageIndexUtil.packageExists(fqName, scope, project)
}
}
@@ -22,4 +22,6 @@ class ReadOnlyWeakRef<V : Any>(value: V, val validityOwner: ValidityOwner) {
}
@Suppress("NOTHING_TO_INLINE")
internal inline fun <V : Any> ValidityOwner.weakRef(value: V) = ReadOnlyWeakRef(value, this)
internal inline fun <V : Any> ValidityOwner.weakRef(value: V) = ReadOnlyWeakRef(value, this)
internal inline fun <V : Any> ValidityOwner.weakRef(value: () -> V) = ReadOnlyWeakRef(value(), this)