KT-7349 Replace keyword "companion" in completion with "companion object"

This commit is contained in:
Valentin Kipyatkov
2015-05-14 18:15:52 +03:00
parent db40f1ee5a
commit 8ea0441348
22 changed files with 109 additions and 64 deletions
@@ -19,8 +19,10 @@ package org.jetbrains.kotlin.idea.completion
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiErrorElement
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.filters.*
import com.intellij.psi.filters.position.LeftNeighbour
import com.intellij.psi.filters.position.PositionElementFilter
@@ -31,7 +33,8 @@ import org.jetbrains.kotlin.lexer.JetKeywordToken
import org.jetbrains.kotlin.lexer.JetTokens.*
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.prevLeafSkipWhitespacesAndComments
import org.jetbrains.kotlin.psi.psiUtil.nextLeaf
import org.jetbrains.kotlin.psi.psiUtil.prevLeaf
import org.jetbrains.kotlin.psi.psiUtil.siblings
object KeywordLookupObject
@@ -54,7 +57,20 @@ object KeywordCompletion {
val parserFilter = buildFilter(position)
for (keywordToken in ALL_KEYWORDS) {
val keyword = keywordToken.getValue()
var keyword = keywordToken.getValue()
if (keyword == COMPANION_KEYWORD.getValue()) { // complete "companion object" instead of simply "companion" unless we are before "object" already
fun PsiElement.isSpace() = this is PsiWhiteSpace && '\n' !in getText()
var next = position.nextLeaf { !(it.isSpace() || it.getText() == "$") }?.getText()
if (next != null && next.startsWith("$")) {
next = next.substring(1)
}
if (next != OBJECT_KEYWORD.getValue()) {
keyword += " " + OBJECT_KEYWORD.getValue()
}
}
if (keyword.startsWith(prefix)/* use simple matching by prefix, not prefix matcher from completion*/ && parserFilter(keywordToken)) {
val element = LookupElementBuilder.create(KeywordLookupObject, keyword)
.bold()
@@ -79,7 +95,7 @@ object KeywordCompletion {
private class CommentFilter() : ElementFilter {
override fun isAcceptable(element : Any?, context : PsiElement?)
= (element is PsiElement) && JetPsiUtil.isInComment(element as PsiElement)
= (element is PsiElement) && JetPsiUtil.isInComment(element)
override fun isClassAcceptable(hintClass: Class<out Any?>)
= true
@@ -109,14 +125,14 @@ object KeywordCompletion {
is JetWithExpressionInitializer -> {
val initializer = _parent.getInitializer()
if (prevParent == initializer) {
return buildFilterWithContext("val v = ", initializer, position)
return buildFilterWithContext("val v = ", initializer!!, position)
}
}
is JetParameter -> {
val default = _parent.getDefaultValue()
if (prevParent == default) {
return buildFilterWithContext("val v = ", default, position)
return buildFilterWithContext("val v = ", default!!, position)
}
}
}
@@ -158,14 +174,14 @@ object KeywordCompletion {
return { keywordTokenType ->
val postfix = KEYWORD_TO_DUMMY_POSTFIX[keywordTokenType] ?: ""
val file = psiFactory.createFile(prefixText + keywordTokenType.getValue() + postfix)
val elementAt = file.findElementAt(prefixText.length)!!
val elementAt = file.findElementAt(prefixText.length())!!
when {
!elementAt.getNode()!!.getElementType().matchesKeyword(keywordTokenType) -> false
elementAt.getNonStrictParentOfType<PsiErrorElement>() != null -> false
elementAt.prevLeafSkipWhitespacesAndComments() is PsiErrorElement -> false
elementAt.prevLeaf { it !is PsiWhiteSpace && it !is PsiComment } is PsiErrorElement -> false
else -> true
}
@@ -194,14 +210,14 @@ object KeywordCompletion {
while (child != position) {
if (child is JetDeclaration) {
if (child == prevDeclaration) {
builder.appendReducedText(child!!)
builder.appendReducedText(child)
}
}
else {
builder.append(child!!.getText())
}
child = child!!.getNextSibling()
child = child.getNextSibling()
}
}
@@ -16,17 +16,19 @@
package org.jetbrains.kotlin.idea.completion
import com.intellij.codeInsight.lookup.CharFilter
import com.intellij.codeInsight.lookup.Lookup
import com.intellij.codeInsight.lookup.CharFilter.Result
import org.jetbrains.kotlin.psi.JetFile
import com.intellij.openapi.util.Key
import com.intellij.codeInsight.completion.CompletionService
import com.intellij.codeInsight.completion.CompletionProgressIndicator
import com.intellij.codeInsight.completion.CompletionService
import com.intellij.codeInsight.lookup.CharFilter
import com.intellij.codeInsight.lookup.CharFilter.Result
import com.intellij.codeInsight.lookup.Lookup
import com.intellij.openapi.util.Key
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.psi.psiUtil.prevLeafSkipWhitespacesAndComments
import com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.JetFunctionLiteral
import org.jetbrains.kotlin.psi.psiUtil.prevLeaf
public class KotlinCompletionCharFilter() : CharFilter() {
companion object {
@@ -86,9 +88,9 @@ public class KotlinCompletionCharFilter() : CharFilter() {
}
private fun isInFunctionLiteralStart(position: PsiElement): Boolean {
var prev = position.prevLeafSkipWhitespacesAndComments()
var prev = position.prevLeaf { it !is PsiWhiteSpace && it !is PsiComment }
if (prev?.getNode()?.getElementType() == JetTokens.LPAR) {
prev = prev?.prevLeafSkipWhitespacesAndComments()
prev = prev?.prevLeaf { it !is PsiWhiteSpace && it !is PsiComment }
}
if (prev?.getNode()?.getElementType() != JetTokens.LBRACE) return false
val functionLiteral = prev!!.getParent() as? JetFunctionLiteral ?: return false
@@ -39,7 +39,7 @@ public object KotlinKeywordInsertHandler : InsertHandler<LookupElement> {
FILE_KEYWORD,
CATCH_KEYWORD,
FINALLY_KEYWORD,
DYNAMIC_KEYWORD).map { it.getValue() }
DYNAMIC_KEYWORD).map { it.getValue() } + "companion object"
override fun handleInsert(context: InsertionContext, item: LookupElement) {
val keyword = item.getLookupString()
@@ -0,0 +1,7 @@
class C {
compa<caret>object {
}
}
// ELEMENT: "companion"
@@ -0,0 +1,7 @@
class C {
companion <caret>object {
}
}
// ELEMENT: "companion"
@@ -0,0 +1,3 @@
class C {
compa<caret>
}
@@ -0,0 +1,3 @@
class C {
companion object<caret>
}
@@ -34,5 +34,5 @@ class MouseMovedEventArgs
// EXIST: constructor
// EXIST: init
/*why?*/
// EXIST: companion
// EXIST: companion object
// NOTHING_ELSE: true
@@ -37,6 +37,6 @@ class B {
// EXIST: var
// EXIST: vararg
/*why?*/
// EXIST: companion
// EXIST: companion object
/*TODO*/
// NOTHING_ELSE: true
@@ -37,5 +37,5 @@ class A {
// EXIST: constructor
// EXIST: init
/*why?*/
// EXIST: companion
// EXIST: companion object
// NOTHING_ELSE: true
@@ -0,0 +1,6 @@
class TestClass {
<caret>
object O {}
}
// EXIST: "companion object"
@@ -37,6 +37,6 @@ var a : Int
// EXIST: var
// EXIST: vararg
/*why?*/
// EXIST: companion
// EXIST: companion object
/*TODO*/
// NOTHING_ELSE: true
@@ -35,5 +35,5 @@ public class Test {
// EXIST: constructor
// EXIST: init
/*why?*/
// EXIST: companion
// EXIST: companion object
// NOTHING_ELSE: true
@@ -29,5 +29,5 @@ class TestClass {
/*why?*/
// EXIST: constructor
// EXIST: init
// EXIST: companion
// EXIST: companion object
// NOTHING_ELSE: true
@@ -28,6 +28,6 @@ package Test
// EXIST: var
// EXIST: vararg
/*why?*/
// EXIST: companion
// EXIST: companion object
/*TODO*/
// NOTHING_ELSE: true
@@ -33,5 +33,5 @@ class Some {
/*why?*/
// EXIST: constructor
// EXIST: init
// EXIST: companion
// EXIST: companion object
// NOTHING_ELSE: true
@@ -33,5 +33,5 @@ class Some {
/*why?*/
// EXIST: constructor
// EXIST: init
// EXIST: companion
// EXIST: companion object
// NOTHING_ELSE: true
@@ -35,5 +35,5 @@ class Some {
/*why?*/
// EXIST: constructor
// EXIST: init
// EXIST: companion
// EXIST: companion object
// NOTHING_ELSE: true
@@ -27,6 +27,6 @@
// EXIST: var
// EXIST: vararg
/*why?*/
// EXIST: companion
// EXIST: companion object
/*TODO*/
// NOTHING_ELSE: true
@@ -95,6 +95,12 @@ public class KeywordCompletionTestGenerated extends AbstractKeywordCompletionTes
doTest(fileName);
}
@TestMetadata("CompanionObjectBeforeObject.kt")
public void testCompanionObjectBeforeObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/CompanionObjectBeforeObject.kt");
doTest(fileName);
}
@TestMetadata("ContinueWithLabel.kt")
public void testContinueWithLabel() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/ContinueWithLabel.kt");
@@ -31,6 +31,12 @@ import java.util.regex.Pattern;
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class KeywordCompletionHandlerTestGenerated extends AbstractKeywordCompletionHandlerTest {
@TestMetadata("AddCompanionToObject.kt")
public void testAddCompanionToObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/keywords/AddCompanionToObject.kt");
doTest(fileName);
}
public void testAllFilesPresentInKeywords() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/handlers/keywords"), Pattern.compile("^(.+)\\.kt$"), true);
}
@@ -41,6 +47,12 @@ public class KeywordCompletionHandlerTestGenerated extends AbstractKeywordComple
doTest(fileName);
}
@TestMetadata("CompanionObject.kt")
public void testCompanionObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/keywords/CompanionObject.kt");
doTest(fileName);
}
@TestMetadata("FileKeyword.kt")
public void testFileKeyword() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/keywords/FileKeyword.kt");