Fixed KT-1797 No completion for nested class name in extension function definition
#KT-1797 Fixed
This commit is contained in:
@@ -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<PsiElement> = 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<CompletionParameters>() {
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
class Test {
|
||||
public class Nested
|
||||
}
|
||||
|
||||
fun Test.<caret>
|
||||
}
|
||||
|
||||
// EXIST: Nested
|
||||
@@ -0,0 +1,8 @@
|
||||
class Test {
|
||||
public class Nested
|
||||
}
|
||||
|
||||
fun Test.N<caret>
|
||||
}
|
||||
|
||||
// EXIST: Nested
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user