KT-7349 Replace keyword "companion" in completion with "companion object"
This commit is contained in:
@@ -16,35 +16,26 @@
|
||||
|
||||
package org.jetbrains.kotlin.psi.psiUtil
|
||||
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import java.util.Collections
|
||||
import com.intellij.extapi.psi.StubBasedPsiElementBase
|
||||
import java.util.ArrayList
|
||||
import kotlin.test.assertTrue
|
||||
import com.intellij.psi.search.SearchScope
|
||||
import com.intellij.psi.search.PsiSearchScopeUtil
|
||||
import com.intellij.psi.PsiParameterList
|
||||
import com.intellij.psi.PsiParameter
|
||||
import com.intellij.psi.PsiPackage
|
||||
import com.intellij.psi.JavaDirectoryService
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import org.jetbrains.kotlin.psi.stubs.KotlinClassOrObjectStub
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
|
||||
import com.intellij.lang.ASTNode
|
||||
import com.intellij.openapi.util.Condition
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import com.intellij.psi.PsiComment
|
||||
import org.jetbrains.kotlin.resolve.calls.CallTransformer.CallForImplicitInvoke
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.search.PsiSearchScopeUtil
|
||||
import com.intellij.psi.search.SearchScope
|
||||
import com.intellij.psi.stubs.StubElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.JetNodeTypes
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.stubs.KotlinClassOrObjectStub
|
||||
import org.jetbrains.kotlin.resolve.calls.CallTransformer.CallForImplicitInvoke
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.lastIsInstanceOrNull
|
||||
import java.util.ArrayList
|
||||
import java.util.Collections
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
public fun JetCallElement.getCallNameExpression(): JetSimpleNameExpression? {
|
||||
val calleeExpression = getCalleeExpression() ?: return null
|
||||
@@ -419,25 +410,17 @@ public fun PsiElement.prevLeaf(skipEmptyElements: Boolean = false): PsiElement?
|
||||
public fun PsiElement.nextLeaf(skipEmptyElements: Boolean = false): PsiElement?
|
||||
= PsiTreeUtil.nextLeaf(this, skipEmptyElements)
|
||||
|
||||
public fun PsiElement.prevLeafSkipWhitespacesAndComments(): PsiElement? {
|
||||
public fun PsiElement.prevLeaf(filter: (PsiElement) -> Boolean): PsiElement? {
|
||||
var leaf = prevLeaf()
|
||||
while (leaf is PsiWhiteSpace || leaf is PsiComment) {
|
||||
while (leaf != null && !filter(leaf)) {
|
||||
leaf = leaf.prevLeaf()
|
||||
}
|
||||
return leaf
|
||||
}
|
||||
|
||||
public fun PsiElement.prevLeafSkipWhitespaces(): PsiElement? {
|
||||
var leaf = prevLeaf()
|
||||
while (leaf is PsiWhiteSpace) {
|
||||
leaf = leaf.prevLeaf()
|
||||
}
|
||||
return leaf
|
||||
}
|
||||
|
||||
public fun PsiElement.nextLeafSkipWhitespacesAndComments(): PsiElement? {
|
||||
public fun PsiElement.nextLeaf(filter: (PsiElement) -> Boolean): PsiElement? {
|
||||
var leaf = nextLeaf()
|
||||
while (leaf is PsiWhiteSpace || leaf is PsiComment) {
|
||||
while (leaf != null && !filter(leaf)) {
|
||||
leaf = leaf.nextLeaf()
|
||||
}
|
||||
return leaf
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-9
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+6
@@ -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");
|
||||
|
||||
+12
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user