FIR IDE: handle importing scopes in completion in HL API
Co-authored-by: Roman Golyshev <roman.golyshev@jetbrains.com>
This commit is contained in:
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* that can be found in the license/LICENSE.txt file.
|
* 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.fir.scopes.impl
|
package org.jetbrains.kotlin.fir.scopes.impl
|
||||||
@@ -26,7 +26,7 @@ abstract class FirAbstractImportingScope(
|
|||||||
) : FirAbstractProviderBasedScope(session, lookupInFir) {
|
) : FirAbstractProviderBasedScope(session, lookupInFir) {
|
||||||
|
|
||||||
// TODO: Rewrite somehow?
|
// TODO: Rewrite somehow?
|
||||||
private fun getStaticsScope(classId: ClassId): FirScope? {
|
fun getStaticsScope(classId: ClassId): FirScope? {
|
||||||
val symbol = provider.getClassLikeSymbolByFqName(classId) ?: return null
|
val symbol = provider.getClassLikeSymbolByFqName(classId) ?: return null
|
||||||
if (symbol is FirTypeAliasSymbol) {
|
if (symbol is FirTypeAliasSymbol) {
|
||||||
val expansionSymbol = symbol.fir.expandedConeType?.lookupTag?.toSymbol(session)
|
val expansionSymbol = symbol.fir.expandedConeType?.lookupTag?.toSymbol(session)
|
||||||
|
|||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
interface KtImportingScope : KtScope {
|
||||||
|
val imports: List<Import>
|
||||||
|
val isDefaultImportingScope: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KtStarImportingScope : KtImportingScope {
|
||||||
|
override val imports: List<StarImport>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KtNonStarImportingScope : KtImportingScope {
|
||||||
|
override val imports: List<NonStarImport>
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class Import {
|
||||||
|
abstract val packageFqName: FqName
|
||||||
|
abstract val relativeClassName: FqName?
|
||||||
|
abstract val resolvedClassId: ClassId?
|
||||||
|
}
|
||||||
|
|
||||||
|
class NonStarImport(
|
||||||
|
override val packageFqName: FqName,
|
||||||
|
override val relativeClassName: FqName?,
|
||||||
|
override val resolvedClassId: ClassId?,
|
||||||
|
val callableName: Name?,
|
||||||
|
) : Import()
|
||||||
|
|
||||||
|
class StarImport(
|
||||||
|
override val packageFqName: FqName,
|
||||||
|
override val relativeClassName: FqName?,
|
||||||
|
override val resolvedClassId: ClassId?,
|
||||||
|
) : Import()
|
||||||
@@ -10,6 +10,8 @@ import org.jetbrains.kotlin.idea.frontend.api.symbols.*
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
interface KtScope : ValidityOwner {
|
interface KtScope : ValidityOwner {
|
||||||
|
// TODO check that names are accessible
|
||||||
|
// maybe return some kind of lazy set
|
||||||
fun getAllNames(): Set<Name>
|
fun getAllNames(): Set<Name>
|
||||||
fun getCallableNames(): Set<Name>
|
fun getCallableNames(): Set<Name>
|
||||||
fun getClassLikeSymbolNames(): Set<Name>
|
fun getClassLikeSymbolNames(): Set<Name>
|
||||||
|
|||||||
+6
-4
@@ -200,7 +200,8 @@ private fun FirScope.collectCallableSymbols(packageIndexHelper: PackageIndexHelp
|
|||||||
return allCallableSymbols
|
return allCallableSymbols
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PackageIndexHelper(private val project: Project) {
|
class PackageIndexHelper(private val project: Project) {
|
||||||
|
//todo use more concrete scope
|
||||||
private val searchScope = GlobalSearchScope.allScope(project)
|
private val searchScope = GlobalSearchScope.allScope(project)
|
||||||
|
|
||||||
private val functionByPackageIndex = KotlinTopLevelFunctionByPackageIndex.getInstance()
|
private val functionByPackageIndex = KotlinTopLevelFunctionByPackageIndex.getInstance()
|
||||||
@@ -210,9 +211,10 @@ private class PackageIndexHelper(private val project: Project) {
|
|||||||
return getTopLevelCallables(packageFqName).mapTo(mutableSetOf()) { it.nameAsSafeName }
|
return getTopLevelCallables(packageFqName).mapTo(mutableSetOf()) { it.nameAsSafeName }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTopLevelCallables(packageFqName: FqName): Sequence<KtCallableDeclaration> = sequence {
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
yieldAll(functionByPackageIndex.get(packageFqName.asString(), project, searchScope))
|
private fun getTopLevelCallables(packageFqName: FqName): List<KtCallableDeclaration> = buildList {
|
||||||
yieldAll(propertyByPackageIndex.get(packageFqName.asString(), project, searchScope))
|
addAll(functionByPackageIndex.get(packageFqName.asString(), project, searchScope))
|
||||||
|
addAll(propertyByPackageIndex.get(packageFqName.asString(), project, searchScope))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -44,6 +44,7 @@ constructor(
|
|||||||
resolveState: FirModuleResolveState
|
resolveState: FirModuleResolveState
|
||||||
) : KtAnalysisSession(element.project) {
|
) : KtAnalysisSession(element.project) {
|
||||||
internal val token get() = validityToken
|
internal val token get() = validityToken
|
||||||
|
private val project = element.project
|
||||||
|
|
||||||
internal val firResolveState = resolveState
|
internal val firResolveState = resolveState
|
||||||
|
|
||||||
@@ -58,7 +59,7 @@ constructor(
|
|||||||
internal val firSymbolBuilder = KtSymbolByFirBuilder(
|
internal val firSymbolBuilder = KtSymbolByFirBuilder(
|
||||||
firSession.firSymbolProvider,
|
firSession.firSymbolProvider,
|
||||||
typeCheckerContext,
|
typeCheckerContext,
|
||||||
element.project,
|
project,
|
||||||
validityToken
|
validityToken
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@ constructor(
|
|||||||
firSymbolBuilder
|
firSymbolBuilder
|
||||||
)
|
)
|
||||||
|
|
||||||
override val scopeProvider: KtScopeProvider = KtFirScopeProvider(token, firSymbolBuilder, firSession, firResolveState)
|
override val scopeProvider: KtScopeProvider = KtFirScopeProvider(token, firSymbolBuilder, project, firSession, firResolveState)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
assertIsValid()
|
assertIsValid()
|
||||||
|
|||||||
+3
-3
@@ -29,7 +29,7 @@ internal abstract class KtFirDelegatingScope(private val builder: KtSymbolByFirB
|
|||||||
|
|
||||||
override fun getAllNames(): Set<Name> = withValidityAssertion {
|
override fun getAllNames(): Set<Name> = withValidityAssertion {
|
||||||
if (allNamesCached == null) {
|
if (allNamesCached == null) {
|
||||||
allNamesCached = firScope.getCallableNames() + firScope.getClassifierNames()
|
allNamesCached = getCallableNames() + getClassLikeSymbolNames()
|
||||||
}
|
}
|
||||||
allNamesCached!!
|
allNamesCached!!
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,7 @@ internal abstract class KtFirDelegatingScope(private val builder: KtSymbolByFirB
|
|||||||
|
|
||||||
override fun getCallableSymbols(): Sequence<KtCallableSymbol> = withValidityAssertion {
|
override fun getCallableSymbols(): Sequence<KtCallableSymbol> = withValidityAssertion {
|
||||||
sequence {
|
sequence {
|
||||||
firScope.getCallableNames().forEach { name ->
|
getCallableNames().forEach { name ->
|
||||||
val callables = mutableListOf<KtCallableSymbol>()
|
val callables = mutableListOf<KtCallableSymbol>()
|
||||||
firScope.processFunctionsByName(name) { firSymbol ->
|
firScope.processFunctionsByName(name) { firSymbol ->
|
||||||
(firSymbol.fir as? FirSimpleFunction)?.let { fir ->
|
(firSymbol.fir as? FirSimpleFunction)?.let { fir ->
|
||||||
@@ -74,7 +74,7 @@ internal abstract class KtFirDelegatingScope(private val builder: KtSymbolByFirB
|
|||||||
|
|
||||||
override fun getClassClassLikeSymbols(): Sequence<KtClassLikeSymbol> = withValidityAssertion {
|
override fun getClassClassLikeSymbols(): Sequence<KtClassLikeSymbol> = withValidityAssertion {
|
||||||
sequence {
|
sequence {
|
||||||
firScope.getClassifierNames().forEach { name ->
|
getClassLikeSymbolNames().forEach { name ->
|
||||||
val classLikeSymbols = mutableListOf<KtClassLikeSymbol>()
|
val classLikeSymbols = mutableListOf<KtClassLikeSymbol>()
|
||||||
firScope.processClassifiersByName(name) { firSymbol ->
|
firScope.processClassifiersByName(name) { firSymbol ->
|
||||||
(firSymbol.fir as? FirClassLikeDeclaration<*>)?.let {
|
(firSymbol.fir as? FirClassLikeDeclaration<*>)?.let {
|
||||||
|
|||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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.impl.FirAbstractSimpleImportingScope
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.impl.FirDefaultSimpleImportingScope
|
||||||
|
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.utils.cached
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtNonStarImportingScope
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.scopes.NonStarImport
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
internal class KtFirNonStarImportingScope(
|
||||||
|
firScope: FirAbstractSimpleImportingScope,
|
||||||
|
builder: KtSymbolByFirBuilder,
|
||||||
|
override val token: ValidityOwner
|
||||||
|
) : KtFirDelegatingScope(builder), KtNonStarImportingScope, ValidityOwnerByValidityToken {
|
||||||
|
override val firScope: FirAbstractSimpleImportingScope = firScope
|
||||||
|
|
||||||
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
|
override val imports: List<NonStarImport> by cached {
|
||||||
|
buildList {
|
||||||
|
firScope.simpleImports.values.forEach { imports ->
|
||||||
|
imports.forEach { import ->
|
||||||
|
NonStarImport(
|
||||||
|
import.packageFqName,
|
||||||
|
import.relativeClassName,
|
||||||
|
import.resolvedClassId,
|
||||||
|
import.importedName
|
||||||
|
).let(::add)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun getCallableNames(): Set<Name> = withValidityAssertion {
|
||||||
|
imports.mapNotNullTo(hashSetOf()) { it.callableName }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getClassLikeSymbolNames(): Set<Name> = withValidityAssertion {
|
||||||
|
imports.mapNotNullTo((hashSetOf())) { it.relativeClassName?.shortName() }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override val isDefaultImportingScope: Boolean = withValidityAssertion { firScope is FirDefaultSimpleImportingScope }
|
||||||
|
}
|
||||||
+19
-3
@@ -5,11 +5,14 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.frontend.api.fir.scopes
|
package org.jetbrains.kotlin.idea.frontend.api.fir.scopes
|
||||||
|
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||||
import org.jetbrains.kotlin.fir.resolve.scope
|
import org.jetbrains.kotlin.fir.resolve.scope
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractSimpleImportingScope
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractStarImportingScope
|
||||||
import org.jetbrains.kotlin.idea.fir.getOrBuildFirOfType
|
import org.jetbrains.kotlin.idea.fir.getOrBuildFirOfType
|
||||||
import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveState
|
import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveState
|
||||||
import org.jetbrains.kotlin.idea.fir.low.level.api.LowLevelFirApiFacade
|
import org.jetbrains.kotlin.idea.fir.low.level.api.LowLevelFirApiFacade
|
||||||
@@ -35,6 +38,7 @@ import java.util.*
|
|||||||
internal class KtFirScopeProvider(
|
internal class KtFirScopeProvider(
|
||||||
override val token: ValidityOwner,
|
override val token: ValidityOwner,
|
||||||
private val builder: KtSymbolByFirBuilder,
|
private val builder: KtSymbolByFirBuilder,
|
||||||
|
private val project: Project,
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
val firResolveState: FirModuleResolveState
|
val firResolveState: FirModuleResolveState
|
||||||
) : KtScopeProvider(), ValidityOwnerByValidityToken {
|
) : KtScopeProvider(), ValidityOwnerByValidityToken {
|
||||||
@@ -96,15 +100,27 @@ internal class KtFirScopeProvider(
|
|||||||
val nonLocalScopes = towerDataContext.nonLocalTowerDataElements.mapNotNull { it.scope }
|
val nonLocalScopes = towerDataContext.nonLocalTowerDataElements.mapNotNull { it.scope }
|
||||||
val firLocalScopes = towerDataContext.localScopes
|
val firLocalScopes = towerDataContext.localScopes
|
||||||
|
|
||||||
val allKtScopes = (implicitReceiverScopes + nonLocalScopes + firLocalScopes).map { convertToKtScope(it) }
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
|
val allKtScopes = buildList {
|
||||||
|
implicitReceiverScopes.mapTo(this, ::convertToKtScope)
|
||||||
|
nonLocalScopes.mapTo(this, ::convertToKtScope)
|
||||||
|
firLocalScopes.mapTo(this, ::convertToKtScope)
|
||||||
|
}
|
||||||
|
|
||||||
KtScopeContext(getCompositeScope(allKtScopes), implicitReceiversTypes)
|
KtScopeContext(getCompositeScope(allKtScopes), implicitReceiversTypes)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun convertToKtScope(firScope: FirScope): KtScope = KtFirDelegatingScopeImpl(firScope, builder, token)
|
private fun convertToKtScope(firScope: FirScope): KtScope = when (firScope) {
|
||||||
|
is FirAbstractSimpleImportingScope -> KtFirNonStarImportingScope(firScope, builder, token)
|
||||||
|
is FirAbstractStarImportingScope -> KtFirStarImportingScope(firScope, builder, project, token)
|
||||||
|
else -> {
|
||||||
|
// todo create concrete KtScope here instead of a generic one
|
||||||
|
KtFirDelegatingScopeImpl(firScope, builder, token)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class KtFirDelegatingScopeImpl(firScope: FirScope, builder: KtSymbolByFirBuilder, override val token: ValidityOwner) :
|
private class KtFirDelegatingScopeImpl(firScope: FirScope, builder: KtSymbolByFirBuilder, override val token: ValidityOwner) :
|
||||||
KtFirDelegatingScope(builder), ValidityOwnerByValidityToken {
|
KtFirDelegatingScope(builder), ValidityOwnerByValidityToken {
|
||||||
override val firScope: FirScope by weakRef(firScope)
|
override val firScope: FirScope = firScope
|
||||||
}
|
}
|
||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.intellij.openapi.project.Project
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractStarImportingScope
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.impl.FirDefaultStarImportingScope
|
||||||
|
import org.jetbrains.kotlin.idea.completion.PackageIndexHelper
|
||||||
|
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.utils.cached
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.scopes.Import
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtStarImportingScope
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.scopes.StarImport
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
internal class KtFirStarImportingScope(
|
||||||
|
firScope: FirAbstractStarImportingScope,
|
||||||
|
builder: KtSymbolByFirBuilder,
|
||||||
|
project: Project,
|
||||||
|
override val token: ValidityOwner,
|
||||||
|
) : KtFirDelegatingScope(builder), KtStarImportingScope, ValidityOwnerByValidityToken {
|
||||||
|
override val firScope: FirAbstractStarImportingScope = firScope
|
||||||
|
override val isDefaultImportingScope: Boolean = withValidityAssertion { firScope is FirDefaultStarImportingScope }
|
||||||
|
private val packageHelper = PackageIndexHelper(project)
|
||||||
|
|
||||||
|
override val imports: List<StarImport> by cached {
|
||||||
|
firScope.starImports.map { import ->
|
||||||
|
StarImport(
|
||||||
|
import.packageFqName,
|
||||||
|
import.relativeClassName,
|
||||||
|
import.resolvedClassId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo cache?
|
||||||
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
|
override fun getCallableNames(): Set<Name> = withValidityAssertion {
|
||||||
|
imports.flatMapTo(hashSetOf()) { import: Import ->
|
||||||
|
if (import.relativeClassName == null) { // top level callable
|
||||||
|
packageHelper.getPackageTopLevelNames(import.packageFqName)
|
||||||
|
} else { //member
|
||||||
|
val classId = import.resolvedClassId ?: error("Class id should not be null as relativeClassName is not null")
|
||||||
|
firScope.getStaticsScope(classId)?.getCallableNames().orEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getClassLikeSymbolNames(): Set<Name> = withValidityAssertion {
|
||||||
|
//TODO
|
||||||
|
setOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user