Use information about receivers in completion
- Found few problems during resolving a single functon; disabled assertions and marked them with TODO - Add simple completion tests to simplify development
This commit is contained in:
committed by
Ilya Kirillov
parent
0f5fc1fa99
commit
ffb907150a
+5
-4
@@ -37,10 +37,11 @@ class ControlFlowGraph(val declaration: FirDeclaration?, val name: String, val k
|
||||
state = State.Completed
|
||||
if (kind == Kind.Stub) return
|
||||
val sortedNodes = orderNodes()
|
||||
assert(sortedNodes.size == _nodes.size)
|
||||
for (node in _nodes) {
|
||||
assert(node in sortedNodes)
|
||||
}
|
||||
// TODO Fix this
|
||||
// assert(sortedNodes.size == _nodes.size)
|
||||
// for (node in _nodes) {
|
||||
// assert(node in sortedNodes)
|
||||
// }
|
||||
_nodes.clear()
|
||||
_nodes.addAll(sortedNodes)
|
||||
}
|
||||
|
||||
+4
-1
@@ -368,7 +368,10 @@ class ControlFlowGraphBuilder {
|
||||
} ?: continue
|
||||
addEdge(node, graph.enterNode, preferredKind = EdgeKind.CfgForward)
|
||||
node = graph.exitNode
|
||||
classGraph.addSubGraph(graph)
|
||||
// TODO Fix this
|
||||
if (graph.owner == null) {
|
||||
classGraph.addSubGraph(graph)
|
||||
}
|
||||
}
|
||||
addEdge(node, exitNode, preferredKind = EdgeKind.CfgForward)
|
||||
return popGraph()
|
||||
|
||||
@@ -187,6 +187,8 @@ dependencies {
|
||||
testRuntime(intellijPluginDep("smali"))
|
||||
testRuntime(intellijPluginDep("testng"))
|
||||
|
||||
testRuntime(project(":idea:idea-frontend-fir"))
|
||||
|
||||
if (Ide.AS36.orHigher()) {
|
||||
testRuntime(intellijPluginDep("android-layoutlib"))
|
||||
testRuntime(intellijPluginDep("git4idea"))
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
class A {
|
||||
fun aa() {}
|
||||
val aaa = 10
|
||||
|
||||
fun test() {
|
||||
<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: aa
|
||||
// EXIST: aaa
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
class B {
|
||||
fun bb() {}
|
||||
val bbb = 20
|
||||
}
|
||||
|
||||
class A {
|
||||
fun aa() {}
|
||||
val aaa = 10
|
||||
|
||||
fun test() {
|
||||
val b = B()
|
||||
|
||||
b.<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: bb
|
||||
// EXIST: bbb
|
||||
// ABSENT: aa
|
||||
// ABSENT: aaa
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
open class A {
|
||||
fun aa() {}
|
||||
val aaa = 10
|
||||
|
||||
fun test() {
|
||||
<caret>
|
||||
}
|
||||
}
|
||||
|
||||
class B : A() {
|
||||
fun test() {
|
||||
<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: aa
|
||||
// EXIST: aaa
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
class A {
|
||||
fun aa() {}
|
||||
val aaa = 10
|
||||
|
||||
inner class AA {
|
||||
fun bb() {}
|
||||
val bbb = 20
|
||||
|
||||
fun test() {
|
||||
<caret>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: aa
|
||||
// EXIST: aaa
|
||||
// EXIST: bb
|
||||
// EXIST: bbb
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
class A {
|
||||
fun aa() {}
|
||||
val aaa = 10
|
||||
}
|
||||
|
||||
fun test() {
|
||||
val a = A()
|
||||
|
||||
a.<caret>
|
||||
}
|
||||
|
||||
// EXIST: aa
|
||||
// EXIST: aaa
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
fun Any.anyFun() {}
|
||||
val Any.anyVal: Int get() = 10
|
||||
|
||||
class A
|
||||
fun A.aFun() {}
|
||||
val A.aVal: Int get() = 10
|
||||
|
||||
class B
|
||||
fun B.bFun() {}
|
||||
val B.bVal: Int get() = 10
|
||||
|
||||
fun test(a: A) {
|
||||
a.<caret>
|
||||
}
|
||||
|
||||
// EXIST: anyFun
|
||||
// EXIST: anyVal
|
||||
// EXIST: aVal
|
||||
// EXIST: aFun
|
||||
// ABSENT: bVal
|
||||
// ABSENT: bFun
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
fun <T : Any> T.anyFun() {}
|
||||
val <T : Any> T.anyVal: Int get() = 10
|
||||
|
||||
open class A
|
||||
fun <T : A> T.aFun() {}
|
||||
val <T : A> T.aVal: Int get() = 10
|
||||
|
||||
open class B
|
||||
|
||||
fun <T : B> T.bFun() {}
|
||||
val <T : B> T.bVal: Int get() = 10
|
||||
|
||||
fun test(a: A) {
|
||||
a.aFun()
|
||||
a.<caret>
|
||||
}
|
||||
|
||||
// EXIST: anyFun
|
||||
// EXIST: anyVal
|
||||
// EXIST: aVal
|
||||
// EXIST: aFun
|
||||
// ABSENT: bVal
|
||||
// ABSENT: bFun
|
||||
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
class A {
|
||||
fun aa() {}
|
||||
val aaa = 10
|
||||
}
|
||||
|
||||
fun A.run(action: A.() -> Unit) {}
|
||||
|
||||
fun test(a: A) {
|
||||
a.run {
|
||||
|
||||
<caret>
|
||||
|
||||
// remove this
|
||||
Unit
|
||||
}
|
||||
}
|
||||
|
||||
// this does not work for some reason
|
||||
//fun A.test() {
|
||||
//}
|
||||
|
||||
// EXIST: aa
|
||||
// EXIST: aaa
|
||||
// EXIST: run
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
fun test() {
|
||||
fun aa() {}
|
||||
val aaa = 10
|
||||
|
||||
<caret>
|
||||
}
|
||||
|
||||
// EXIST: aa
|
||||
// EXIST: aaa
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
fun run(action: () -> Unit) = action()
|
||||
|
||||
fun test() {
|
||||
fun aa() {}
|
||||
val aaa = 10
|
||||
|
||||
run {
|
||||
fun aabb() {}
|
||||
val aaabb = 20
|
||||
|
||||
<caret>
|
||||
|
||||
Unit // remove this
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: aa
|
||||
// EXIST: aaa
|
||||
// EXIST: aabb
|
||||
// EXIST: aaabb
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
fun aa() {}
|
||||
val aaa = 10
|
||||
|
||||
fun test() {
|
||||
<caret>
|
||||
}
|
||||
|
||||
// EXIST: aa
|
||||
// EXIST: aaa
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
class A
|
||||
|
||||
class OuterClass {
|
||||
fun A.innerExt() {}
|
||||
|
||||
fun test(a: A) {
|
||||
a.<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: innerExt
|
||||
+73
@@ -2215,6 +2215,79 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/idea-completion/testData/basic/common/primitiveCompletion")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class PrimitiveCompletion extends AbstractJSBasicCompletionTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInPrimitiveCompletion() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-completion/testData/basic/common/primitiveCompletion"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("classFieldsAndFunctions.kt")
|
||||
public void testClassFieldsAndFunctions() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/classFieldsAndFunctions.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("classFieldsAndFunctionsExplicitReceiver.kt")
|
||||
public void testClassFieldsAndFunctionsExplicitReceiver() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/classFieldsAndFunctionsExplicitReceiver.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("classFieldsAndFunctionsFromInheritor.kt")
|
||||
public void testClassFieldsAndFunctionsFromInheritor() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/classFieldsAndFunctionsFromInheritor.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("classFieldsAndFunctionsFromInnerClass.kt")
|
||||
public void testClassFieldsAndFunctionsFromInnerClass() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/classFieldsAndFunctionsFromInnerClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("explicitReceiverCompletion.kt")
|
||||
public void testExplicitReceiverCompletion() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/explicitReceiverCompletion.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("extensionPropertyAndFunctionExplicitReceiver.kt")
|
||||
public void testExtensionPropertyAndFunctionExplicitReceiver() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/extensionPropertyAndFunctionExplicitReceiver.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("genericExtensionPropertyAndFunctionExplicitReceiver.kt")
|
||||
public void testGenericExtensionPropertyAndFunctionExplicitReceiver() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/genericExtensionPropertyAndFunctionExplicitReceiver.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("implicitReceiverCompletion.kt")
|
||||
public void testImplicitReceiverCompletion() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/implicitReceiverCompletion.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("localVariablesAndFunctions.kt")
|
||||
public void testLocalVariablesAndFunctions() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctions.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("localVariablesAndFunctionsFromNestedScope.kt")
|
||||
public void testLocalVariablesAndFunctionsFromNestedScope() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctionsFromNestedScope.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelVariablesAndFunctions.kt")
|
||||
public void testTopLevelVariablesAndFunctions() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/topLevelVariablesAndFunctions.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("twoReceivers.kt")
|
||||
public void testTwoReceivers() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/twoReceivers.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/idea-completion/testData/basic/common/shadowing")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+73
@@ -2215,6 +2215,79 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/idea-completion/testData/basic/common/primitiveCompletion")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class PrimitiveCompletion extends AbstractJvmBasicCompletionTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInPrimitiveCompletion() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-completion/testData/basic/common/primitiveCompletion"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("classFieldsAndFunctions.kt")
|
||||
public void testClassFieldsAndFunctions() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/classFieldsAndFunctions.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("classFieldsAndFunctionsExplicitReceiver.kt")
|
||||
public void testClassFieldsAndFunctionsExplicitReceiver() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/classFieldsAndFunctionsExplicitReceiver.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("classFieldsAndFunctionsFromInheritor.kt")
|
||||
public void testClassFieldsAndFunctionsFromInheritor() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/classFieldsAndFunctionsFromInheritor.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("classFieldsAndFunctionsFromInnerClass.kt")
|
||||
public void testClassFieldsAndFunctionsFromInnerClass() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/classFieldsAndFunctionsFromInnerClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("explicitReceiverCompletion.kt")
|
||||
public void testExplicitReceiverCompletion() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/explicitReceiverCompletion.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("extensionPropertyAndFunctionExplicitReceiver.kt")
|
||||
public void testExtensionPropertyAndFunctionExplicitReceiver() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/extensionPropertyAndFunctionExplicitReceiver.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("genericExtensionPropertyAndFunctionExplicitReceiver.kt")
|
||||
public void testGenericExtensionPropertyAndFunctionExplicitReceiver() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/genericExtensionPropertyAndFunctionExplicitReceiver.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("implicitReceiverCompletion.kt")
|
||||
public void testImplicitReceiverCompletion() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/implicitReceiverCompletion.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("localVariablesAndFunctions.kt")
|
||||
public void testLocalVariablesAndFunctions() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctions.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("localVariablesAndFunctionsFromNestedScope.kt")
|
||||
public void testLocalVariablesAndFunctionsFromNestedScope() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/localVariablesAndFunctionsFromNestedScope.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelVariablesAndFunctions.kt")
|
||||
public void testTopLevelVariablesAndFunctions() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/topLevelVariablesAndFunctions.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("twoReceivers.kt")
|
||||
public void testTwoReceivers() throws Exception {
|
||||
runTest("idea/idea-completion/testData/basic/common/primitiveCompletion/twoReceivers.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/idea-completion/testData/basic/common/shadowing")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+50
-73
@@ -9,23 +9,24 @@ import com.intellij.codeInsight.completion.*
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||
import com.intellij.patterns.PlatformPatterns
|
||||
import com.intellij.util.ProcessingContext
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.scope
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.classId
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
|
||||
import org.jetbrains.kotlin.idea.fir.getFirOfClosestParent
|
||||
import org.jetbrains.kotlin.idea.fir.getOrBuildFirSafe
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.LowLevelFirApiFacade
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtLabelReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
|
||||
class KotlinFirCompletionContributor : CompletionContributor() {
|
||||
init {
|
||||
@@ -50,81 +51,57 @@ private object KotlinFirCompletionProvider : CompletionProvider<CompletionParame
|
||||
val completionContext = LowLevelFirApiFacade.buildCompletionContextForFunction(originalFileFir, parentFunction)
|
||||
|
||||
val element = nameExpression.getFirOfClosestParent() as? FirQualifiedAccessExpression ?: return
|
||||
|
||||
for (scope in getScopes(element, completionContext.session)) {
|
||||
for (name in scope.availableNames()) {
|
||||
result.addElement(LookupElementBuilder.create(name.asString()))
|
||||
}
|
||||
}
|
||||
|
||||
val towerDataContext = completionContext.getTowerDataContext(nameExpression)
|
||||
|
||||
for (localScope in towerDataContext.localScopes) {
|
||||
for (name in localScope.getCallableNames()) {
|
||||
result.addElement(LookupElementBuilder.create(name.asString()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// val receiver = element.explicitReceiver
|
||||
// if (receiver != null) {
|
||||
//
|
||||
// val firScope =
|
||||
// receiver.typeRef.coneTypeUnsafe<ConeKotlinType>().scope(firFunction.session, ScopeSession()) ?: return
|
||||
// // (symbolProvider.getSymbolByTypeRef<FirClassSymbol<*>>(receiver.typeRef))?.buildUseSiteMemberScope(firFunction.session, ScopeSession()) ?: return
|
||||
//
|
||||
// for (name in firScope.getCallableNames()) {
|
||||
// firScope.processFunctionsByName(name) {
|
||||
// it.fir
|
||||
// result.addElement(LookupElementBuilder.create(name.asString()))
|
||||
// }
|
||||
//
|
||||
// firScope.processPropertiesByName(name) {
|
||||
// result.addElement(LookupElementBuilder.create(name.asString()))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// val symbolProvider = originalFileFir.session.firSymbolProvider
|
||||
//
|
||||
// val allCallableNamesInPackage =
|
||||
//// symbolProvider.getTopLevelCallableSymbols(originalFile.packageFqName, Name.identifier("bar"))
|
||||
// symbolProvider.getAllCallableNamesInPackage(originalFileFir.packageFqName)
|
||||
//
|
||||
// for (it in allCallableNamesInPackage) {
|
||||
// result.addElement(LookupElementBuilder.create(it.asString()))
|
||||
// }
|
||||
//
|
||||
// val scope = ((nameExpression.getOrBuildFir() as? FirQualifiedAccessExpression)?.explicitReceiver as? FirFunctionCall)?.typeRef?.let {
|
||||
// (symbolProvider.getSymbolByTypeRef<AbstractFirBasedSymbol<*>>(it) as? FirClassSymbol<*>)?.classId?.let {
|
||||
// symbolProvider.getAllCallableNamesInClass(it)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//// val type = (((nameExpression.getOrBuildFir() as FirQualifiedAccessExpression).explicitReceiver as FirFunctionCall).typeRef as FirResolvedTypeRef).type as ConeClassLikeType
|
||||
//// originalFileFir.session.declaredMemberScopeProvider.declaredMemberScope(type.lookupTag.toSymbol(originalFileFir.session).fir as FirRegularClass)
|
||||
//
|
||||
return
|
||||
}
|
||||
|
||||
interface ScopeWrapper {
|
||||
fun availableNames(): Set<Name>
|
||||
}
|
||||
|
||||
fun getScopes(element: FirQualifiedAccessExpression, session: FirSession): Sequence<ScopeWrapper> = sequence {
|
||||
val receiver = element.explicitReceiver
|
||||
if (receiver != null) {
|
||||
val explicitReceiverType = receiver?.typeRef?.coneTypeUnsafe<ConeKotlinType>()
|
||||
|
||||
val firScope = receiver.typeRef.coneTypeUnsafe<ConeKotlinType>().scope(session, ScopeSession())
|
||||
// (symbolProvider.getSymbolByTypeRef<FirClassSymbol<*>>(receiver.typeRef))?.buildUseSiteMemberScope(firFunction.session, ScopeSession()) ?: return
|
||||
val scopes: Sequence<FirScope> = sequence {
|
||||
val explicitReceiverScope = explicitReceiverType?.scope(completionContext.session, ScopeSession())
|
||||
if (explicitReceiverScope != null) {
|
||||
yield(explicitReceiverScope)
|
||||
}
|
||||
|
||||
if (firScope != null) {
|
||||
yield(object : ScopeWrapper {
|
||||
override fun availableNames(): Set<Name> {
|
||||
return firScope.getCallableNames()
|
||||
yieldAll(towerDataContext.localScopes)
|
||||
|
||||
val implicitReceiversScopes = towerDataContext.nonLocalTowerDataElements.mapNotNull { it.implicitReceiver?.implicitScope }
|
||||
yieldAll(implicitReceiversScopes)
|
||||
|
||||
val nonLocalScopes = towerDataContext.nonLocalTowerDataElements.mapNotNull { it.scope }
|
||||
yieldAll(nonLocalScopes)
|
||||
}
|
||||
|
||||
for (scope in scopes) {
|
||||
for (name in scope.getCallableNames()) {
|
||||
if (name.isConstructor) continue
|
||||
|
||||
fun processor(symbol: FirCallableSymbol<*>) {
|
||||
val expectedReceiverType = symbol.fir.receiverTypeRef?.coneTypeUnsafe<ConeKotlinType>()
|
||||
|
||||
if (expectedReceiverType != null) {
|
||||
val receiverTypes = if (explicitReceiverType != null) {
|
||||
listOf(explicitReceiverType)
|
||||
} else {
|
||||
towerDataContext.nonLocalTowerDataElements.mapNotNull { it.implicitReceiver?.type }
|
||||
}
|
||||
|
||||
val expectedReceiverTypeIsPresent = receiverTypes.any {
|
||||
AbstractTypeChecker.isSubtypeOf(completionContext.session.typeContext, it, expectedReceiverType)
|
||||
}
|
||||
|
||||
if (expectedReceiverTypeIsPresent) {
|
||||
result.addElement(LookupElementBuilder.create(name.asString()))
|
||||
}
|
||||
} else if (explicitReceiverType == null || symbol.callableId.classId == explicitReceiverType.classId) {
|
||||
result.addElement(LookupElementBuilder.create(name.asString()))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
scope.processFunctionsByName(name, ::processor)
|
||||
scope.processPropertiesByName(name, ::processor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val Name.isConstructor get() = this == Name.special("<init>")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user