Add basic completion for operator fun names
#KT-11250 fixed
This commit is contained in:
@@ -142,6 +142,20 @@ public class OperatorConventions {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static KtToken getOperationSymbolForName(@NotNull Name name) {
|
||||
if (!isConventionName(name)) return null;
|
||||
|
||||
KtToken token;
|
||||
token = BINARY_OPERATION_NAMES.inverse().get(name);
|
||||
if (token != null) return token;
|
||||
token = UNARY_OPERATION_NAMES.inverse().get(name);
|
||||
if (token != null) return token;
|
||||
token = ASSIGNMENT_OPERATIONS.inverse().get(name);
|
||||
if (token != null) return token;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isConventionName(@NotNull Name name) {
|
||||
return CONVENTION_NAMES.contains(name) || COMPONENT_REGEX.matches(name.asString());
|
||||
}
|
||||
|
||||
+24
@@ -25,6 +25,7 @@ import com.intellij.codeInsight.template.TemplateManager
|
||||
import com.intellij.patterns.PatternCondition
|
||||
import com.intellij.patterns.StandardPatterns
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.util.ProcessingContext
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
@@ -96,6 +97,9 @@ class BasicCompletionSession(
|
||||
}
|
||||
}
|
||||
|
||||
if (OPERATOR_NAME.isApplicable())
|
||||
return OPERATOR_NAME
|
||||
|
||||
if (NamedArgumentCompletion.isOnlyNamedArgumentExpected(nameExpression)) {
|
||||
return NAMED_ARGUMENTS_ONLY
|
||||
}
|
||||
@@ -453,6 +457,26 @@ class BasicCompletionSession(
|
||||
}
|
||||
}
|
||||
|
||||
private val OPERATOR_NAME = object : CompletionKind {
|
||||
override val descriptorKindFilter: DescriptorKindFilter?
|
||||
get() = null
|
||||
|
||||
fun isApplicable(): Boolean {
|
||||
if (nameExpression == null || nameExpression != expression) return false
|
||||
val func = position.getParentOfType<KtNamedFunction>(strict = false) ?: return false
|
||||
val funcNameIdentifier = func.nameIdentifier ?: return false
|
||||
val identifierInNameExpression = nameExpression.nextLeaf { it is LeafPsiElement && it.elementType == KtTokens.IDENTIFIER } ?: return false
|
||||
if (!func.hasModifier(KtTokens.OPERATOR_KEYWORD) || identifierInNameExpression != funcNameIdentifier) return false
|
||||
val originalFunc = toFromOriginalFileMapper.toOriginalFile(func) ?: return false
|
||||
return !originalFunc.isTopLevel || (originalFunc.isExtensionDeclaration())
|
||||
}
|
||||
|
||||
override fun doComplete() {
|
||||
OperatorNameCompletion.doComplete(collector, descriptorNameFilter)
|
||||
flushToResultSet()
|
||||
}
|
||||
}
|
||||
|
||||
private val DECLARATION_NAME = object : CompletionKind {
|
||||
override val descriptorKindFilter: DescriptorKindFilter?
|
||||
get() = null
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
|
||||
import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||
import org.jetbrains.kotlin.lexer.KtSingleValueToken
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.COMPARE_TO
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.CONTAINS
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.EQUALS
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.GET
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.INVOKE
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.SET
|
||||
|
||||
object OperatorNameCompletion {
|
||||
|
||||
val additionalOperatorPresentation = mapOf(
|
||||
SET to "[...] = ...",
|
||||
GET to "[...]",
|
||||
CONTAINS to "in !in",
|
||||
COMPARE_TO to "< > <= >=",
|
||||
EQUALS to "== !=",
|
||||
INVOKE to "(...)"
|
||||
)
|
||||
|
||||
private fun buildLookupElement(opName: Name): LookupElement {
|
||||
val element = LookupElementBuilder.create(opName)
|
||||
|
||||
val symbol =
|
||||
(OperatorConventions.getOperationSymbolForName(opName) as? KtSingleValueToken)?.value ?:
|
||||
additionalOperatorPresentation[opName]
|
||||
|
||||
if (symbol != null) return element.withTypeText(symbol)
|
||||
return element
|
||||
}
|
||||
|
||||
fun doComplete(collector: LookupElementsCollector, descriptorNameFilter: (String) -> Boolean) {
|
||||
collector.addElements(OperatorConventions.CONVENTION_NAMES
|
||||
.filter { descriptorNameFilter(it.asString()) }
|
||||
.map(this::buildLookupElement))
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
operator fun <caret>() {
|
||||
|
||||
}
|
||||
|
||||
// NOTHING_ELSE
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
class Some {
|
||||
|
||||
}
|
||||
|
||||
operator fun Some.<caret>() {
|
||||
|
||||
}
|
||||
|
||||
// EXIST: {"lookupString":"compareTo","typeText":"< > <= >="}
|
||||
// EXIST: {"lookupString":"contains","typeText":"in !in"}
|
||||
// EXIST: {"lookupString":"dec","typeText":"--"}
|
||||
// EXIST: {"lookupString":"div","typeText":"/"}
|
||||
// EXIST: {"lookupString":"divAssign","typeText":"/="}
|
||||
// EXIST: {"lookupString":"equals","typeText":"== !="}
|
||||
// EXIST: {"lookupString":"get","typeText":"[...]"}
|
||||
// EXIST: {"lookupString":"getValue"}
|
||||
// EXIST: {"lookupString":"hasNext"}
|
||||
// EXIST: {"lookupString":"inc","typeText":"++"}
|
||||
// EXIST: {"lookupString":"invoke","typeText":"(...)"}
|
||||
// EXIST: {"lookupString":"iterator"}
|
||||
// EXIST: {"lookupString":"minus","typeText":"-"}
|
||||
// EXIST: {"lookupString":"minusAssign","typeText":"-="}
|
||||
// EXIST: {"lookupString":"next"}
|
||||
// EXIST: {"lookupString":"not","typeText":"!"}
|
||||
// EXIST: {"lookupString":"plus","typeText":"+"}
|
||||
// EXIST: {"lookupString":"plusAssign","typeText":"+="}
|
||||
// EXIST: {"lookupString":"rangeTo","typeText":".."}
|
||||
// EXIST: {"lookupString":"rem","typeText":"%"}
|
||||
// EXIST: {"lookupString":"remAssign","typeText":"%="}
|
||||
// EXIST: {"lookupString":"set","typeText":"[...] = ..."}
|
||||
// EXIST: {"lookupString":"setValue"}
|
||||
// EXIST: {"lookupString":"times","typeText":"*"}
|
||||
// EXIST: {"lookupString":"timesAssign","typeText":"*="}
|
||||
// EXIST: {"lookupString":"unaryMinus","typeText":"-"}
|
||||
// EXIST: {"lookupString":"unaryPlus","typeText":"+"}
|
||||
// NOTHING_ELSE
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
class Some {
|
||||
operator fun <caret>() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: {"lookupString":"compareTo","typeText":"< > <= >="}
|
||||
// EXIST: {"lookupString":"contains","typeText":"in !in"}
|
||||
// EXIST: {"lookupString":"dec","typeText":"--"}
|
||||
// EXIST: {"lookupString":"div","typeText":"/"}
|
||||
// EXIST: {"lookupString":"divAssign","typeText":"/="}
|
||||
// EXIST: {"lookupString":"equals","typeText":"== !="}
|
||||
// EXIST: {"lookupString":"get","typeText":"[...]"}
|
||||
// EXIST: {"lookupString":"getValue"}
|
||||
// EXIST: {"lookupString":"hasNext"}
|
||||
// EXIST: {"lookupString":"inc","typeText":"++"}
|
||||
// EXIST: {"lookupString":"invoke","typeText":"(...)"}
|
||||
// EXIST: {"lookupString":"iterator"}
|
||||
// EXIST: {"lookupString":"minus","typeText":"-"}
|
||||
// EXIST: {"lookupString":"minusAssign","typeText":"-="}
|
||||
// EXIST: {"lookupString":"next"}
|
||||
// EXIST: {"lookupString":"not","typeText":"!"}
|
||||
// EXIST: {"lookupString":"plus","typeText":"+"}
|
||||
// EXIST: {"lookupString":"plusAssign","typeText":"+="}
|
||||
// EXIST: {"lookupString":"rangeTo","typeText":".."}
|
||||
// EXIST: {"lookupString":"rem","typeText":"%"}
|
||||
// EXIST: {"lookupString":"remAssign","typeText":"%="}
|
||||
// EXIST: {"lookupString":"set","typeText":"[...] = ..."}
|
||||
// EXIST: {"lookupString":"setValue"}
|
||||
// EXIST: {"lookupString":"times","typeText":"*"}
|
||||
// EXIST: {"lookupString":"timesAssign","typeText":"*="}
|
||||
// EXIST: {"lookupString":"unaryMinus","typeText":"-"}
|
||||
// EXIST: {"lookupString":"unaryPlus","typeText":"+"}
|
||||
// NOTHING_ELSE
|
||||
+27
@@ -2021,6 +2021,33 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/idea-completion/testData/basic/common/operatorNames")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class OperatorNames extends AbstractJSBasicCompletionTest {
|
||||
public void testAllFilesPresentInOperatorNames() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/operatorNames"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("NoOperatorNameForTopLevel.kt")
|
||||
public void testNoOperatorNameForTopLevel() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/operatorNames/NoOperatorNameForTopLevel.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("OperatorNameForExtension.kt")
|
||||
public void testOperatorNameForExtension() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/operatorNames/OperatorNameForExtension.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("OperatorNameForMember.kt")
|
||||
public void testOperatorNameForMember() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/operatorNames/OperatorNameForMember.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/idea-completion/testData/basic/common/override")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+27
@@ -2021,6 +2021,33 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/idea-completion/testData/basic/common/operatorNames")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class OperatorNames extends AbstractJvmBasicCompletionTest {
|
||||
public void testAllFilesPresentInOperatorNames() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/operatorNames"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("NoOperatorNameForTopLevel.kt")
|
||||
public void testNoOperatorNameForTopLevel() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/operatorNames/NoOperatorNameForTopLevel.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("OperatorNameForExtension.kt")
|
||||
public void testOperatorNameForExtension() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/operatorNames/OperatorNameForExtension.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("OperatorNameForMember.kt")
|
||||
public void testOperatorNameForMember() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/operatorNames/OperatorNameForMember.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/idea-completion/testData/basic/common/override")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user