Use index to get symbols from importing scopes
This commit is contained in:
committed by
Ilya Kirillov
parent
cefecdef25
commit
2eb439899e
+2
-1
@@ -21,7 +21,8 @@ abstract class FirAbstractSimpleImportingScope(
|
|||||||
scopeSession: ScopeSession
|
scopeSession: ScopeSession
|
||||||
) : FirAbstractImportingScope(session, scopeSession, lookupInFir = true) {
|
) : FirAbstractImportingScope(session, scopeSession, lookupInFir = true) {
|
||||||
|
|
||||||
protected abstract val simpleImports: Map<Name, List<FirResolvedImport>>
|
// TODO try to hide this
|
||||||
|
abstract val simpleImports: Map<Name, List<FirResolvedImport>>
|
||||||
|
|
||||||
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
|
||||||
val imports = simpleImports[name] ?: return
|
val imports = simpleImports[name] ?: return
|
||||||
|
|||||||
+2
-1
@@ -21,7 +21,8 @@ abstract class FirAbstractStarImportingScope(
|
|||||||
lookupInFir: Boolean = true
|
lookupInFir: Boolean = true
|
||||||
) : FirAbstractImportingScope(session, scopeSession, lookupInFir) {
|
) : FirAbstractImportingScope(session, scopeSession, lookupInFir) {
|
||||||
|
|
||||||
protected abstract val starImports: List<FirResolvedImport>
|
// TODO try to hide this
|
||||||
|
abstract val starImports: List<FirResolvedImport>
|
||||||
|
|
||||||
private val absentClassifierNames = mutableSetOf<Name>()
|
private val absentClassifierNames = mutableSetOf<Name>()
|
||||||
|
|
||||||
|
|||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
fun usage() {
|
||||||
|
val a = <caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXIST: listOf
|
||||||
|
// EXIST: setOf
|
||||||
Vendored
+6
@@ -0,0 +1,6 @@
|
|||||||
|
fun test(a: Int, b: Int) {
|
||||||
|
<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXIST: a
|
||||||
|
// EXIST: b
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
fun usage() {
|
||||||
|
val a = "10".toIntOrNull()
|
||||||
|
|
||||||
|
a?.<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXIST: toString
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
fun usage() {
|
||||||
|
"".<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXIST: length
|
||||||
|
// EXIST: get
|
||||||
+20
@@ -2252,6 +2252,11 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
|||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/classFieldsAndFunctionsFromInnerClassExplicitReceiver.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/classFieldsAndFunctionsFromInnerClassExplicitReceiver.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("defaultKotlinImports.kt")
|
||||||
|
public void testDefaultKotlinImports() throws Exception {
|
||||||
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/defaultKotlinImports.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("explicitReceiverCompletion.kt")
|
@TestMetadata("explicitReceiverCompletion.kt")
|
||||||
public void testExplicitReceiverCompletion() throws Exception {
|
public void testExplicitReceiverCompletion() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/explicitReceiverCompletion.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/explicitReceiverCompletion.kt");
|
||||||
@@ -2282,6 +2287,11 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
|||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/implicitReceiverFromExtensionMethod.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/implicitReceiverFromExtensionMethod.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("insideFunctionWithParameters.kt")
|
||||||
|
public void testInsideFunctionWithParameters() throws Exception {
|
||||||
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/insideFunctionWithParameters.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("localVariablesAndFunctions.kt")
|
@TestMetadata("localVariablesAndFunctions.kt")
|
||||||
public void testLocalVariablesAndFunctions() throws Exception {
|
public void testLocalVariablesAndFunctions() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctions.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctions.kt");
|
||||||
@@ -2292,11 +2302,21 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
|||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctionsFromNestedScope.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctionsFromNestedScope.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nullableCompletion.kt")
|
||||||
|
public void testNullableCompletion() throws Exception {
|
||||||
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/nullableCompletion.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("smartCast.kt")
|
@TestMetadata("smartCast.kt")
|
||||||
public void testSmartCast() throws Exception {
|
public void testSmartCast() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/smartCast.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/smartCast.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("stringCompletion.kt")
|
||||||
|
public void testStringCompletion() throws Exception {
|
||||||
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/stringCompletion.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("topLevelVariablesAndFunctions.kt")
|
@TestMetadata("topLevelVariablesAndFunctions.kt")
|
||||||
public void testTopLevelVariablesAndFunctions() throws Exception {
|
public void testTopLevelVariablesAndFunctions() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/topLevelVariablesAndFunctions.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/topLevelVariablesAndFunctions.kt");
|
||||||
|
|||||||
+20
@@ -2252,6 +2252,11 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
|||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/classFieldsAndFunctionsFromInnerClassExplicitReceiver.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/classFieldsAndFunctionsFromInnerClassExplicitReceiver.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("defaultKotlinImports.kt")
|
||||||
|
public void testDefaultKotlinImports() throws Exception {
|
||||||
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/defaultKotlinImports.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("explicitReceiverCompletion.kt")
|
@TestMetadata("explicitReceiverCompletion.kt")
|
||||||
public void testExplicitReceiverCompletion() throws Exception {
|
public void testExplicitReceiverCompletion() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/explicitReceiverCompletion.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/explicitReceiverCompletion.kt");
|
||||||
@@ -2282,6 +2287,11 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
|||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/implicitReceiverFromExtensionMethod.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/implicitReceiverFromExtensionMethod.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("insideFunctionWithParameters.kt")
|
||||||
|
public void testInsideFunctionWithParameters() throws Exception {
|
||||||
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/insideFunctionWithParameters.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("localVariablesAndFunctions.kt")
|
@TestMetadata("localVariablesAndFunctions.kt")
|
||||||
public void testLocalVariablesAndFunctions() throws Exception {
|
public void testLocalVariablesAndFunctions() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctions.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctions.kt");
|
||||||
@@ -2292,11 +2302,21 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
|||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctionsFromNestedScope.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctionsFromNestedScope.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nullableCompletion.kt")
|
||||||
|
public void testNullableCompletion() throws Exception {
|
||||||
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/nullableCompletion.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("smartCast.kt")
|
@TestMetadata("smartCast.kt")
|
||||||
public void testSmartCast() throws Exception {
|
public void testSmartCast() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/smartCast.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/smartCast.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("stringCompletion.kt")
|
||||||
|
public void testStringCompletion() throws Exception {
|
||||||
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/stringCompletion.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("topLevelVariablesAndFunctions.kt")
|
@TestMetadata("topLevelVariablesAndFunctions.kt")
|
||||||
public void testTopLevelVariablesAndFunctions() throws Exception {
|
public void testTopLevelVariablesAndFunctions() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/topLevelVariablesAndFunctions.kt");
|
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/topLevelVariablesAndFunctions.kt");
|
||||||
|
|||||||
+44
-9
@@ -7,14 +7,19 @@ package org.jetbrains.kotlin.idea.completion
|
|||||||
|
|
||||||
import com.intellij.codeInsight.completion.*
|
import com.intellij.codeInsight.completion.*
|
||||||
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.patterns.PlatformPatterns
|
import com.intellij.patterns.PlatformPatterns
|
||||||
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.util.ProcessingContext
|
import com.intellij.util.ProcessingContext
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParametersOwner
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||||
|
import org.jetbrains.kotlin.fir.psi
|
||||||
|
import org.jetbrains.kotlin.fir.realPsi
|
||||||
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.fir.symbols.impl.FirCallableSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||||
import org.jetbrains.kotlin.fir.typeContext
|
import org.jetbrains.kotlin.fir.typeContext
|
||||||
@@ -24,6 +29,9 @@ import org.jetbrains.kotlin.idea.fir.getFirOfClosestParent
|
|||||||
import org.jetbrains.kotlin.idea.fir.getOrBuildFirSafe
|
import org.jetbrains.kotlin.idea.fir.getOrBuildFirSafe
|
||||||
import org.jetbrains.kotlin.idea.fir.low.level.api.LowLevelFirApiFacade
|
import org.jetbrains.kotlin.idea.fir.low.level.api.LowLevelFirApiFacade
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
|
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelFunctionByPackageIndex
|
||||||
|
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelPropertyByPackageIndex
|
||||||
|
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.psi.psiUtil.getNonStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
@@ -36,9 +44,6 @@ class KotlinFirCompletionContributor : CompletionContributor() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Collect all receivers for the expression (implicit and explicit)
|
|
||||||
*/
|
|
||||||
private object KotlinFirCompletionProvider : CompletionProvider<CompletionParameters>() {
|
private object KotlinFirCompletionProvider : CompletionProvider<CompletionParameters>() {
|
||||||
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {
|
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {
|
||||||
val originalFile = parameters.originalFile as? KtFile ?: return
|
val originalFile = parameters.originalFile as? KtFile ?: return
|
||||||
@@ -56,6 +61,8 @@ private object KotlinFirCompletionProvider : CompletionProvider<CompletionParame
|
|||||||
val towerDataContext = completionContext.getTowerDataContext(nameExpression)
|
val towerDataContext = completionContext.getTowerDataContext(nameExpression)
|
||||||
|
|
||||||
val symbols: Sequence<FirCallableSymbol<*>> = sequence {
|
val symbols: Sequence<FirCallableSymbol<*>> = sequence {
|
||||||
|
val packageIndexHelper = PackageIndexHelper(parameters.position.project)
|
||||||
|
|
||||||
val explicitReceiver = element.explicitReceiver
|
val explicitReceiver = element.explicitReceiver
|
||||||
val explicitReceiverType = explicitReceiver?.typeRef?.coneTypeUnsafe<ConeKotlinType>()
|
val explicitReceiverType = explicitReceiver?.typeRef?.coneTypeUnsafe<ConeKotlinType>()
|
||||||
val explicitReceiverScope = explicitReceiverType?.scope(completionContext.session, ScopeSession())
|
val explicitReceiverScope = explicitReceiverType?.scope(completionContext.session, ScopeSession())
|
||||||
@@ -72,16 +79,16 @@ private object KotlinFirCompletionProvider : CompletionProvider<CompletionParame
|
|||||||
val typeContext = completionContext.session.typeContext
|
val typeContext = completionContext.session.typeContext
|
||||||
|
|
||||||
if (explicitReceiverScope != null) {
|
if (explicitReceiverScope != null) {
|
||||||
yieldAll(explicitReceiverScope.collectCallableSymbols())
|
yieldAll(explicitReceiverScope.collectCallableSymbols(packageIndexHelper))
|
||||||
|
|
||||||
val allApplicableExtensions = allNonExplicitScopes
|
val allApplicableExtensions = allNonExplicitScopes
|
||||||
.flatMap { it.collectCallableSymbols() }
|
.flatMap { it.collectCallableSymbols(packageIndexHelper) }
|
||||||
.filter { it.isExtension && it.isExtensionThatCanBeCalledOnTypes(listOf(explicitReceiverType), typeContext) }
|
.filter { it.isExtension && it.isExtensionThatCanBeCalledOnTypes(listOf(explicitReceiverType), typeContext) }
|
||||||
|
|
||||||
yieldAll(allApplicableExtensions)
|
yieldAll(allApplicableExtensions)
|
||||||
} else {
|
} else {
|
||||||
val allAvailableSymbols = allNonExplicitScopes
|
val allAvailableSymbols = allNonExplicitScopes
|
||||||
.flatMap { it.collectCallableSymbols() }
|
.flatMap { it.collectCallableSymbols(packageIndexHelper) }
|
||||||
.filter { !it.isExtension || it.isExtensionThatCanBeCalledOnTypes(implicitReceiversTypes, typeContext) }
|
.filter { !it.isExtension || it.isExtensionThatCanBeCalledOnTypes(implicitReceiversTypes, typeContext) }
|
||||||
|
|
||||||
yieldAll(allAvailableSymbols)
|
yieldAll(allAvailableSymbols)
|
||||||
@@ -100,13 +107,25 @@ private object KotlinFirCompletionProvider : CompletionProvider<CompletionParame
|
|||||||
|
|
||||||
private val FirCallableSymbol<*>.isExtension get() = fir.receiverTypeRef != null
|
private val FirCallableSymbol<*>.isExtension get() = fir.receiverTypeRef != null
|
||||||
|
|
||||||
private fun FirScope.collectCallableSymbols(): MutableList<FirCallableSymbol<*>> {
|
|
||||||
|
private fun FirScope.getScopeNames(indexHelper: PackageIndexHelper): Set<Name> = when (this) {
|
||||||
|
is FirAbstractStarImportingScope -> {
|
||||||
|
this.starImports.flatMapTo(mutableSetOf()) { indexHelper.getPackageTopLevelNames(it.packageFqName) }
|
||||||
|
}
|
||||||
|
|
||||||
|
is FirAbstractSimpleImportingScope -> simpleImports.keys
|
||||||
|
|
||||||
|
else -> getCallableNames()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FirScope.collectCallableSymbols(packageIndexHelper: PackageIndexHelper): MutableList<FirCallableSymbol<*>> {
|
||||||
val allCallableSymbols = mutableListOf<FirCallableSymbol<*>>()
|
val allCallableSymbols = mutableListOf<FirCallableSymbol<*>>()
|
||||||
fun symbolsCollector(symbol: FirCallableSymbol<*>) {
|
fun symbolsCollector(symbol: FirCallableSymbol<*>) {
|
||||||
allCallableSymbols.add(symbol)
|
allCallableSymbols.add(symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name in getCallableNames()) {
|
val scopeNames = getScopeNames(packageIndexHelper)
|
||||||
|
for (name in scopeNames) {
|
||||||
processFunctionsByName(name, ::symbolsCollector)
|
processFunctionsByName(name, ::symbolsCollector)
|
||||||
processPropertiesByName(name, ::symbolsCollector)
|
processPropertiesByName(name, ::symbolsCollector)
|
||||||
}
|
}
|
||||||
@@ -114,6 +133,22 @@ private fun FirScope.collectCallableSymbols(): MutableList<FirCallableSymbol<*>>
|
|||||||
return allCallableSymbols
|
return allCallableSymbols
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class PackageIndexHelper(private val project: Project) {
|
||||||
|
private val searchScope = GlobalSearchScope.allScope(project)
|
||||||
|
|
||||||
|
private val functionByPackageIndex = KotlinTopLevelFunctionByPackageIndex.getInstance()
|
||||||
|
private val propertyByPackageIndex = KotlinTopLevelPropertyByPackageIndex.getInstance()
|
||||||
|
|
||||||
|
fun getPackageTopLevelNames(packageFqName: FqName): Set<Name> {
|
||||||
|
return getTopLevelCallables(packageFqName).mapTo(mutableSetOf()) { it.nameAsSafeName }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getTopLevelCallables(packageFqName: FqName): Sequence<KtCallableDeclaration> = sequence {
|
||||||
|
yieldAll(functionByPackageIndex.get(packageFqName.asString(), project, searchScope))
|
||||||
|
yieldAll(propertyByPackageIndex.get(packageFqName.asString(), project, searchScope))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun FirCallableSymbol<*>.isExtensionThatCanBeCalledOnTypes(
|
private fun FirCallableSymbol<*>.isExtensionThatCanBeCalledOnTypes(
|
||||||
receivers: List<ConeKotlinType>,
|
receivers: List<ConeKotlinType>,
|
||||||
session: TypeCheckerProviderContext
|
session: TypeCheckerProviderContext
|
||||||
|
|||||||
Reference in New Issue
Block a user