Make completion for overriding functions respect suspend modifier

Fixes #KT-22200
This commit is contained in:
Kirill Rakhman
2018-01-09 21:52:18 +01:00
committed by Alexander Udalov
parent 8bc020f31b
commit b567817d1f
6 changed files with 44 additions and 10 deletions
@@ -524,12 +524,16 @@ internal class DescriptorRendererImpl(
functionDescriptor.isInfix && (functionDescriptor.overriddenDescriptors.none { it.isInfix } || alwaysRenderModifiers) functionDescriptor.isInfix && (functionDescriptor.overriddenDescriptors.none { it.isInfix } || alwaysRenderModifiers)
renderModifier(builder, functionDescriptor.isTailrec, "tailrec") renderModifier(builder, functionDescriptor.isTailrec, "tailrec")
renderModifier(builder, functionDescriptor.isSuspend, "suspend") renderSuspendModifier(functionDescriptor, builder)
renderModifier(builder, functionDescriptor.isInline, "inline") renderModifier(builder, functionDescriptor.isInline, "inline")
renderModifier(builder, isInfix, "infix") renderModifier(builder, isInfix, "infix")
renderModifier(builder, isOperator, "operator") renderModifier(builder, isOperator, "operator")
} }
private fun renderSuspendModifier(functionDescriptor: FunctionDescriptor, builder: StringBuilder) {
renderModifier(builder, functionDescriptor.isSuspend, "suspend")
}
override fun render(declarationDescriptor: DeclarationDescriptor): String { override fun render(declarationDescriptor: DeclarationDescriptor): String {
return buildString { return buildString {
declarationDescriptor.accept(RenderDeclarationDescriptorVisitor(), this) declarationDescriptor.accept(RenderDeclarationDescriptorVisitor(), this)
@@ -630,6 +634,8 @@ internal class DescriptorRendererImpl(
if (includeAdditionalModifiers) { if (includeAdditionalModifiers) {
renderAdditionalModifiers(function, builder) renderAdditionalModifiers(function, builder)
} else {
renderSuspendModifier(function, builder)
} }
renderMemberKind(function, builder) renderMemberKind(function, builder)
@@ -24,6 +24,7 @@ import com.intellij.icons.AllIcons
import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.ui.RowIcon import com.intellij.ui.RowIcon
import org.jetbrains.kotlin.backend.common.descriptors.isSuspend
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.KotlinDescriptorIconProvider import org.jetbrains.kotlin.idea.KotlinDescriptorIconProvider
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
@@ -43,8 +44,8 @@ import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
class OverridesCompletion( class OverridesCompletion(
private val collector: LookupElementsCollector, private val collector: LookupElementsCollector,
private val lookupElementFactory: BasicLookupElementFactory private val lookupElementFactory: BasicLookupElementFactory
) { ) {
private val PRESENTATION_RENDERER = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.withOptions { private val PRESENTATION_RENDERER = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.withOptions {
modifiers = emptySet() modifiers = emptySet()
@@ -85,7 +86,9 @@ class OverridesCompletion(
val baseClassIcon = KotlinDescriptorIconProvider.getIcon(baseClass, baseClassDeclaration, 0) val baseClassIcon = KotlinDescriptorIconProvider.getIcon(baseClass, baseClassDeclaration, 0)
lookupElement = object : LookupElementDecorator<LookupElement>(lookupElement) { lookupElement = object : LookupElementDecorator<LookupElement>(lookupElement) {
override fun getLookupString() = if (declaration == null) "override" else delegate.lookupString // don't use "override" as lookup string when already in the name of declaration override fun getLookupString() =
if (declaration == null) "override" else delegate.lookupString // don't use "override" as lookup string when already in the name of declaration
override fun getAllLookupStrings() = setOf(lookupString, delegate.lookupString) override fun getAllLookupStrings() = setOf(lookupString, delegate.lookupString)
override fun renderElement(presentation: LookupElementPresentation) { override fun renderElement(presentation: LookupElementPresentation) {
@@ -122,6 +125,7 @@ class OverridesCompletion(
val prototype = memberObject.generateMember(classOrObject, false) val prototype = memberObject.generateMember(classOrObject, false)
prototype.modifierList!!.replace(modifierList) prototype.modifierList!!.replace(modifierList)
val insertedMember = dummyMember.replaced(prototype) val insertedMember = dummyMember.replaced(prototype)
if (memberObject.descriptor.isSuspend) insertedMember.addModifier(KtTokens.SUSPEND_KEYWORD)
ShortenReferences.DEFAULT.process(insertedMember) ShortenReferences.DEFAULT.process(insertedMember)
@@ -135,8 +139,7 @@ class OverridesCompletion(
context.document.deleteString(offset, atCharOffset + 1) context.document.deleteString(offset, atCharOffset + 1)
context.editor.moveCaret(offset) context.editor.moveCaret(offset)
} } else {
else {
moveCaretIntoGeneratedElement(context.editor, insertedMember) moveCaretIntoGeneratedElement(context.editor, insertedMember)
} }
} }
@@ -156,8 +159,7 @@ class OverridesCompletion(
if (descriptorToOverride !is PropertyDescriptor) return false if (descriptorToOverride !is PropertyDescriptor) return false
return if (declaration.valOrVarKeyword?.node?.elementType == KtTokens.VAL_KEYWORD) { return if (declaration.valOrVarKeyword?.node?.elementType == KtTokens.VAL_KEYWORD) {
!descriptorToOverride.isVar !descriptorToOverride.isVar
} } else {
else {
true // var can override either var or val true // var can override either var or val
} }
} }
@@ -5,7 +5,7 @@ interface I {
} }
class Base1 { class Base1 {
protected open fun bar(){} protected open suspend fun bar(){}
} }
open class Base2 : Base1() { open class Base2 : Base1() {
@@ -16,7 +16,7 @@ class A : Base2(), I {
} }
// EXIST: { lookupString: "override", itemText: "override" } // EXIST: { lookupString: "override", itemText: "override" }
// EXIST: { itemText: "override fun bar() {...}", lookupString: "override", allLookupStrings: "bar, override", tailText: null, typeText: "Base1", attributes: "" } // EXIST: { itemText: "override suspend fun bar() {...}", lookupString: "override", allLookupStrings: "bar, override", tailText: null, typeText: "Base1", attributes: "" }
// EXIST: { itemText: "override fun equals(other: Any?): Boolean {...}", lookupString: "override", allLookupStrings: "equals, override", tailText: null, typeText: "Any", attributes: "" } // EXIST: { itemText: "override fun equals(other: Any?): Boolean {...}", lookupString: "override", allLookupStrings: "equals, override", tailText: null, typeText: "Any", attributes: "" }
// EXIST: { itemText: "override fun foo(p: Int) {...}", lookupString: "override", allLookupStrings: "foo, override", tailText: null, typeText: "I", attributes: "bold" } // EXIST: { itemText: "override fun foo(p: Int) {...}", lookupString: "override", allLookupStrings: "foo, override", tailText: null, typeText: "I", attributes: "bold" }
// EXIST: { itemText: "override fun hashCode(): Int {...}", lookupString: "override", allLookupStrings: "hashCode, override", tailText: null, typeText: "Any", attributes: "" } // EXIST: { itemText: "override fun hashCode(): Int {...}", lookupString: "override", allLookupStrings: "hashCode, override", tailText: null, typeText: "Any", attributes: "" }
@@ -0,0 +1,9 @@
interface I {
suspend fun foo()
}
class A : I {
o<caret>
}
// ELEMENT_TEXT: "override suspend fun foo() {...}"
@@ -0,0 +1,11 @@
interface I {
suspend fun foo()
}
class A : I {
override suspend fun foo() {
<caret><selection>TODO("not implemented") //To change body of created functions use File | Settings | File Templates.</selection>
}
}
// ELEMENT_TEXT: "override suspend fun foo() {...}"
@@ -582,6 +582,12 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion
doTest(fileName); doTest(fileName);
} }
@TestMetadata("Suspend.kt")
public void testSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/override/Suspend.kt");
doTest(fileName);
}
@TestMetadata("TypeFunctionName.kt") @TestMetadata("TypeFunctionName.kt")
public void testTypeFunctionName() throws Exception { public void testTypeFunctionName() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/override/TypeFunctionName.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/override/TypeFunctionName.kt");