From 0ee2b512ff571dcc0c7f4ab0e2256ba5755a5ab1 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 28 Oct 2015 19:27:22 +0300 Subject: [PATCH] Completion of non-imported extensions in debugger for runtime receiver type --- .../idea/completion/BasicCompletionSession.kt | 10 +++++++-- .../idea/completion/CompletionSession.kt | 21 ++++++++++--------- .../smart/SmartCompletionSession.kt | 8 ++++--- .../runtimeType/notImportedExtension.kt | 8 +++++++ .../notImportedExtension.kt.fragment | 1 + .../runtimeCast/NotImportedExtension.kt | 8 +++++++ .../runtimeCast/NotImportedExtension.kt.after | 1 + .../NotImportedExtension.kt.after.imports | 2 ++ .../NotImportedExtension.kt.fragment | 1 + ...ragmentCompletionHandlerTestGenerated.java | 6 ++++++ .../CodeFragmentCompletionTestGenerated.java | 6 ++++++ 11 files changed, 57 insertions(+), 15 deletions(-) create mode 100644 idea/idea-completion/testData/basic/codeFragments/runtimeType/notImportedExtension.kt create mode 100644 idea/idea-completion/testData/basic/codeFragments/runtimeType/notImportedExtension.kt.fragment create mode 100644 idea/idea-completion/testData/handlers/runtimeCast/NotImportedExtension.kt create mode 100644 idea/idea-completion/testData/handlers/runtimeCast/NotImportedExtension.kt.after create mode 100644 idea/idea-completion/testData/handlers/runtimeCast/NotImportedExtension.kt.after.imports create mode 100644 idea/idea-completion/testData/handlers/runtimeCast/NotImportedExtension.kt.fragment diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt index e6054a3cd37..fbcbccc3a5a 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt @@ -240,9 +240,15 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, if (completionKind != CompletionKind.KEYWORDS_ONLY) { completeNonImported() + flushToResultSet() + if (position.getContainingFile() is KtCodeFragment) { - flushToResultSet() - collector.addDescriptorElements(getRuntimeReceiverTypeReferenceVariants(), withReceiverCast = true) + val variants = getRuntimeReceiverTypeReferenceVariants() + if (variants != null) { + collector.addDescriptorElements(variants.imported, withReceiverCast = true) + collector.addDescriptorElements(variants.notImportedExtensions, withReceiverCast = true, notImported = true) + flushToResultSet() + } } } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt index 781967c7e7b..b6b5c0422aa 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt @@ -324,18 +324,19 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC return this } - protected fun getRuntimeReceiverTypeReferenceVariants(): Collection { - val explicitReceiver = callTypeAndReceiver.receiver as? KtExpression ?: return emptyList() - val type = bindingContext.getType(explicitReceiver) ?: return emptyList() - if (!TypeUtils.canHaveSubtypes(KotlinTypeChecker.DEFAULT, type)) return emptyList() - val evaluator = file.getCopyableUserData(KtCodeFragment.RUNTIME_TYPE_EVALUATOR) ?: return emptyList() + protected fun getRuntimeReceiverTypeReferenceVariants(): ReferenceVariants? { + val explicitReceiver = callTypeAndReceiver.receiver as? KtExpression ?: return null + val type = bindingContext.getType(explicitReceiver) ?: return null + if (!TypeUtils.canHaveSubtypes(KotlinTypeChecker.DEFAULT, type)) return null + val evaluator = file.getCopyableUserData(KtCodeFragment.RUNTIME_TYPE_EVALUATOR) ?: return null val runtimeType = evaluator(explicitReceiver) - if (runtimeType == null || runtimeType == type) return emptyList() + if (runtimeType == null || runtimeType == type) return null - val (variants, notImportedExtensions/*TODO: use them*/) = collectReferenceVariants(descriptorKindFilter!!, runtimeType) - return variants.filter { descriptor -> - referenceVariants!!.imported.none { compareDescriptors(project, it, descriptor) } - } + val (variants, notImportedExtensions) = collectReferenceVariants(descriptorKindFilter!!, runtimeType) + val normalVariants = referenceVariants!!.imported + referenceVariants!!.notImportedExtensions + val filteredVariants = variants.filter { descriptor -> normalVariants.none { compareDescriptors(project, it, descriptor) } } + val filteredNotImportedExtensions = notImportedExtensions.filter { descriptor -> normalVariants.none { compareDescriptors(project, it, descriptor) } } + return ReferenceVariants(filteredVariants, filteredNotImportedExtensions) } protected fun shouldCompleteTopLevelCallablesFromIndex(): Boolean { diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt index 196307fc5d2..28a34af87ff 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt @@ -85,10 +85,12 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para } if (position.getContainingFile() is KtCodeFragment) { - getRuntimeReceiverTypeReferenceVariants().forEach { - collector.addElements(filter(it).map { it.withReceiverCast() }) + val variants = getRuntimeReceiverTypeReferenceVariants() + if (variants != null) { + variants.imported.forEach { collector.addElements(filter(it).map { it.withReceiverCast() }) } + variants.notImportedExtensions.forEach { collector.addElements(filter(it).map { it.withReceiverCast() }, notImported = true) } + flushToResultSet() } - flushToResultSet() } } diff --git a/idea/idea-completion/testData/basic/codeFragments/runtimeType/notImportedExtension.kt b/idea/idea-completion/testData/basic/codeFragments/runtimeType/notImportedExtension.kt new file mode 100644 index 00000000000..1a4230d3440 --- /dev/null +++ b/idea/idea-completion/testData/basic/codeFragments/runtimeType/notImportedExtension.kt @@ -0,0 +1,8 @@ +fun foo(o: Any) { + val a = 1 +} + +// INVOCATION_COUNT: 1 +// EXIST: read, write + +// RUNTIME_TYPE: java.util.concurrent.locks.ReentrantReadWriteLock \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/codeFragments/runtimeType/notImportedExtension.kt.fragment b/idea/idea-completion/testData/basic/codeFragments/runtimeType/notImportedExtension.kt.fragment new file mode 100644 index 00000000000..03f9c3af623 --- /dev/null +++ b/idea/idea-completion/testData/basic/codeFragments/runtimeType/notImportedExtension.kt.fragment @@ -0,0 +1 @@ +o. \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/runtimeCast/NotImportedExtension.kt b/idea/idea-completion/testData/handlers/runtimeCast/NotImportedExtension.kt new file mode 100644 index 00000000000..efe2f9e0ea2 --- /dev/null +++ b/idea/idea-completion/testData/handlers/runtimeCast/NotImportedExtension.kt @@ -0,0 +1,8 @@ +fun foo(o: Any) { + val a = 1 +} + +// INVOCATION_COUNT: 1 +// ELEMENT: read + +// RUNTIME_TYPE: java.util.concurrent.locks.ReentrantReadWriteLock diff --git a/idea/idea-completion/testData/handlers/runtimeCast/NotImportedExtension.kt.after b/idea/idea-completion/testData/handlers/runtimeCast/NotImportedExtension.kt.after new file mode 100644 index 00000000000..f057766cb43 --- /dev/null +++ b/idea/idea-completion/testData/handlers/runtimeCast/NotImportedExtension.kt.after @@ -0,0 +1 @@ +(o as ReentrantReadWriteLock).read { } \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/runtimeCast/NotImportedExtension.kt.after.imports b/idea/idea-completion/testData/handlers/runtimeCast/NotImportedExtension.kt.after.imports new file mode 100644 index 00000000000..e71fbf4bbe5 --- /dev/null +++ b/idea/idea-completion/testData/handlers/runtimeCast/NotImportedExtension.kt.after.imports @@ -0,0 +1,2 @@ +import kotlin.concurrent.read +import java.util.concurrent.locks.ReentrantReadWriteLock \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/runtimeCast/NotImportedExtension.kt.fragment b/idea/idea-completion/testData/handlers/runtimeCast/NotImportedExtension.kt.fragment new file mode 100644 index 00000000000..03f9c3af623 --- /dev/null +++ b/idea/idea-completion/testData/handlers/runtimeCast/NotImportedExtension.kt.fragment @@ -0,0 +1 @@ +o. \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/CodeFragmentCompletionHandlerTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/CodeFragmentCompletionHandlerTestGenerated.java index 7114958f6f0..4191c28ab97 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/CodeFragmentCompletionHandlerTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/CodeFragmentCompletionHandlerTestGenerated.java @@ -64,4 +64,10 @@ public class CodeFragmentCompletionHandlerTestGenerated extends AbstractCodeFrag String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/runtimeCast/InsertImport.kt"); doTest(fileName); } + + @TestMetadata("NotImportedExtension.kt") + public void testNotImportedExtension() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/runtimeCast/NotImportedExtension.kt"); + doTest(fileName); + } } diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/CodeFragmentCompletionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/CodeFragmentCompletionTestGenerated.java index 1df2ebecc30..778bb0de3a4 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/CodeFragmentCompletionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/CodeFragmentCompletionTestGenerated.java @@ -115,6 +115,12 @@ public class CodeFragmentCompletionTestGenerated extends AbstractCodeFragmentCom doTest(fileName); } + @TestMetadata("notImportedExtension.kt") + public void testNotImportedExtension() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/codeFragments/runtimeType/notImportedExtension.kt"); + doTest(fileName); + } + @TestMetadata("runtimeCast.kt") public void testRuntimeCast() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/codeFragments/runtimeType/runtimeCast.kt");