diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt index 253c29d752f..27b54172205 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt @@ -39,6 +39,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.utils.addToStdlib.check import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull public class KotlinCompletionContributor : CompletionContributor() { @@ -275,21 +276,29 @@ public class KotlinCompletionContributor : CompletionContributor() { if (invocationCount == 0 && prefixMatcher.getPrefix().isEmpty() && AFTER_INTEGER_LITERAL_AND_DOT.accepts(position)) return true // no auto-popup on typing after "val", "var" and "fun" because it's likely the name of the declaration which is being typed by user - if (invocationCount == 0 && isInExtensionReceiver(position)) return true + if (invocationCount == 0) { + val callable = isInExtensionReceiverOf(position) + if (callable != null) { + return when (callable) { + is JetNamedFunction -> prefixMatcher.prefix.let { it.isEmpty() || it[0].isLowerCase() /* function name usually starts with lower case letter */ } + else -> true + } + } + } return false } - private fun isInExtensionReceiver(position: PsiElement): Boolean { - val nameRef = position.getParent() as? JetNameReferenceExpression ?: return false - val userType = nameRef.getParent() as? JetUserType ?: return false - val typeRef = userType.getParent() as? JetTypeReference ?: return false - if (userType != typeRef.getTypeElement()) return false + private fun isInExtensionReceiverOf(position: PsiElement): JetCallableDeclaration? { + val nameRef = position.getParent() as? JetNameReferenceExpression ?: return null + val userType = nameRef.getParent() as? JetUserType ?: return null + val typeRef = userType.getParent() as? JetTypeReference ?: return null + if (userType != typeRef.getTypeElement()) return null val parent = typeRef.getParent() return when (parent) { - is JetNamedFunction -> typeRef == parent.getReceiverTypeReference() - is JetProperty -> typeRef == parent.getReceiverTypeReference() - else -> false + is JetNamedFunction -> parent.check { typeRef == it.receiverTypeReference } + is JetProperty -> parent.check { typeRef == it.receiverTypeReference } + else -> null } } diff --git a/idea/idea-completion/testData/basic/common/AutopopupInFunExtensionReceiver.kt b/idea/idea-completion/testData/basic/common/AutopopupInFunExtensionReceiver.kt new file mode 100644 index 00000000000..0618be50a63 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/AutopopupInFunExtensionReceiver.kt @@ -0,0 +1,6 @@ +class Xyz + +fun X + +// INVOCATION_COUNT: 0 +// EXIST: Xyz diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java index 94a48c75cf0..7ae4beb8437 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java @@ -67,6 +67,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("AutopopupInFunExtensionReceiver.kt") + public void testAutopopupInFunExtensionReceiver() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/AutopopupInFunExtensionReceiver.kt"); + doTest(fileName); + } + @TestMetadata("BasicAny.kt") public void testBasicAny() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/BasicAny.kt"); diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java index 842800421d6..243d6a426da 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java @@ -67,6 +67,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("AutopopupInFunExtensionReceiver.kt") + public void testAutopopupInFunExtensionReceiver() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/AutopopupInFunExtensionReceiver.kt"); + doTest(fileName); + } + @TestMetadata("BasicAny.kt") public void testBasicAny() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/BasicAny.kt");