diff --git a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.kt b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.kt index c878f009e48..a624ef398b1 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.kt @@ -27,19 +27,20 @@ import org.jetbrains.jet.lang.psi.JetExpression import org.jetbrains.jet.lang.psi.JetFile import org.jetbrains.jet.lexer.JetTokens import org.jetbrains.jet.plugin.completion.smart.SmartCompletion -import org.jetbrains.jet.plugin.references.JetSimpleNameReference import com.intellij.patterns.PsiJavaPatterns.elementType import com.intellij.patterns.PsiJavaPatterns.psiElement -import com.intellij.patterns.PsiElementPattern import com.intellij.psi.PsiElement +import com.intellij.psi.PsiComment +import com.intellij.psi.PsiWhiteSpace +import org.jetbrains.jet.lang.psi.JetTypeReference public class JetCompletionContributor : CompletionContributor() { private val AFTER_NUMBER_LITERAL = psiElement().afterLeafSkipping(psiElement().withText(""), psiElement().withElementType(elementType().oneOf(JetTokens.FLOAT_LITERAL, JetTokens.INTEGER_LITERAL))) - private val EXTENSION_RECEIVER_TYPE_DUMMY_IDENTIFIER: String = "KotlinExtensionDummy.fake() {}" // A way to add reference into file at completion place - private val EXTENSION_RECEIVER_TYPE_ACTIVATION_PATTERN: PsiElementPattern.Capture = PlatformPatterns.psiElement().afterLeaf(JetTokens.FUN_KEYWORD.toString(), JetTokens.VAL_KEYWORD.toString(), JetTokens.VAR_KEYWORD.toString()) + private val EXTENSION_RECEIVER_TYPE_DUMMY_IDENTIFIER = "KotlinExtensionDummy.fake() {}" // A way to add reference into file at completion place + private val EXTENSION_RECEIVER_TYPE_ACTIVATION_PATTERN = psiElement().afterLeaf(JetTokens.FUN_KEYWORD.toString(), JetTokens.VAL_KEYWORD.toString(), JetTokens.VAR_KEYWORD.toString()) ;{ val provider = object : CompletionProvider() { @@ -57,6 +58,7 @@ public class JetCompletionContributor : CompletionContributor() { val offset = context.getStartOffset() val tokenBefore = psiFile.findElementAt(Math.max(0, offset - 1)) + val dummyIdentifier = when { context.getCompletionType() == CompletionType.SMART -> CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED + "$" // add '$' to ignore context after the caret @@ -64,6 +66,8 @@ public class JetCompletionContributor : CompletionContributor() { EXTENSION_RECEIVER_TYPE_ACTIVATION_PATTERN.accepts(tokenBefore) -> EXTENSION_RECEIVER_TYPE_DUMMY_IDENTIFIER + tokenBefore != null && isExtensionReceiverAfterDot(tokenBefore) -> CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED + "." + else -> CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED } context.setDummyIdentifier(dummyIdentifier) @@ -102,6 +106,25 @@ public class JetCompletionContributor : CompletionContributor() { } } + private val declarationKeywords = setOf(JetTokens.FUN_KEYWORD, JetTokens.VAL_KEYWORD, JetTokens.VAR_KEYWORD) + + private fun isExtensionReceiverAfterDot(tokenBefore: PsiElement): Boolean { + var prev = tokenBefore.getPrevSibling() + if (tokenBefore.getNode()!!.getElementType() != JetTokens.DOT) { + if (prev == null || prev!!.getNode()!!.getElementType() != JetTokens.DOT) return false + prev = prev!!.getPrevSibling() + } + + while (prev != null) { + if (prev!!.getNode()!!.getElementType() in declarationKeywords) { + return true + } + if (prev !is PsiComment && prev !is PsiWhiteSpace && prev !is JetTypeReference) return false + prev = prev!!.getPrevSibling() + } + return false + } + private fun performCompletion(parameters: CompletionParameters, result: CompletionResultSet) { val position = parameters.getPosition() if (position.getContainingFile() !is JetFile) return diff --git a/idea/testData/completion/basic/common/NestedClassNameForExtension.kt b/idea/testData/completion/basic/common/NestedClassNameForExtension.kt new file mode 100644 index 00000000000..929b6c57652 --- /dev/null +++ b/idea/testData/completion/basic/common/NestedClassNameForExtension.kt @@ -0,0 +1,8 @@ +class Test { + public class Nested +} + +fun Test. +} + +// EXIST: Nested diff --git a/idea/testData/completion/basic/common/NestedClassNameForExtension2.kt b/idea/testData/completion/basic/common/NestedClassNameForExtension2.kt new file mode 100644 index 00000000000..f2a55c674b5 --- /dev/null +++ b/idea/testData/completion/basic/common/NestedClassNameForExtension2.kt @@ -0,0 +1,8 @@ +class Test { + public class Nested +} + +fun Test.N +} + +// EXIST: Nested diff --git a/idea/tests/org/jetbrains/jet/completion/JSBasicCompletionTestGenerated.java b/idea/tests/org/jetbrains/jet/completion/JSBasicCompletionTestGenerated.java index a46ed07b0c7..14eacda04a7 100644 --- a/idea/tests/org/jetbrains/jet/completion/JSBasicCompletionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/completion/JSBasicCompletionTestGenerated.java @@ -334,6 +334,16 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes doTest("idea/testData/completion/basic/common/NamedObject.kt"); } + @TestMetadata("NestedClassNameForExtension.kt") + public void testNestedClassNameForExtension() throws Exception { + doTest("idea/testData/completion/basic/common/NestedClassNameForExtension.kt"); + } + + @TestMetadata("NestedClassNameForExtension2.kt") + public void testNestedClassNameForExtension2() throws Exception { + doTest("idea/testData/completion/basic/common/NestedClassNameForExtension2.kt"); + } + @TestMetadata("NoClassNameDuplication.kt") public void testNoClassNameDuplication() throws Exception { doTest("idea/testData/completion/basic/common/NoClassNameDuplication.kt"); diff --git a/idea/tests/org/jetbrains/jet/completion/JvmBasicCompletionTestGenerated.java b/idea/tests/org/jetbrains/jet/completion/JvmBasicCompletionTestGenerated.java index 828f934fdc4..ea4bcc1bf10 100644 --- a/idea/tests/org/jetbrains/jet/completion/JvmBasicCompletionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/completion/JvmBasicCompletionTestGenerated.java @@ -334,6 +334,16 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT doTest("idea/testData/completion/basic/common/NamedObject.kt"); } + @TestMetadata("NestedClassNameForExtension.kt") + public void testNestedClassNameForExtension() throws Exception { + doTest("idea/testData/completion/basic/common/NestedClassNameForExtension.kt"); + } + + @TestMetadata("NestedClassNameForExtension2.kt") + public void testNestedClassNameForExtension2() throws Exception { + doTest("idea/testData/completion/basic/common/NestedClassNameForExtension2.kt"); + } + @TestMetadata("NoClassNameDuplication.kt") public void testNoClassNameDuplication() throws Exception { doTest("idea/testData/completion/basic/common/NoClassNameDuplication.kt");