KT-8968 Special completion after "super."
#KT-8968 Fixed
This commit is contained in:
@@ -420,7 +420,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
|
||||
protected fun createLookupElementFactory(contextVariablesProvider: ContextVariablesProvider): LookupElementFactory {
|
||||
return LookupElementFactory(basicLookupElementFactory, resolutionFacade, receiverTypes,
|
||||
callTypeAndReceiver.callType, contextVariablesProvider)
|
||||
callTypeAndReceiver.callType, inDescriptor, contextVariablesProvider)
|
||||
}
|
||||
|
||||
private fun detectCallTypeAndReceiverTypes(): Pair<CallTypeAndReceiver<*, *>, Collection<KotlinType>?> {
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
|
||||
import com.intellij.codeInsight.completion.*
|
||||
import com.intellij.codeInsight.completion.CompletionProgressIndicator
|
||||
import com.intellij.codeInsight.completion.CompletionService
|
||||
import com.intellij.codeInsight.completion.InsertionContext
|
||||
import com.intellij.codeInsight.completion.PrefixMatcher
|
||||
import com.intellij.codeInsight.lookup.*
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.openapi.util.Key
|
||||
@@ -62,6 +65,7 @@ tailrec fun <T : Any> LookupElement.getUserDataDeep(key: Key<T>): T? {
|
||||
}
|
||||
|
||||
enum class ItemPriority {
|
||||
SUPER_METHOD_WITH_ARGUMENTS,
|
||||
DEFAULT,
|
||||
IMPLEMENT,
|
||||
OVERRIDE,
|
||||
|
||||
+37
-7
@@ -34,11 +34,13 @@ import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.renderer.render
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor
|
||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
data /* we need copy() */
|
||||
class LookupElementFactory(
|
||||
@@ -46,6 +48,7 @@ class LookupElementFactory(
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val receiverTypes: Collection<KotlinType>?,
|
||||
private val callType: CallType<*>?,
|
||||
private val inDescriptor: DeclarationDescriptor,
|
||||
private val contextVariablesProvider: ContextVariablesProvider
|
||||
) {
|
||||
companion object {
|
||||
@@ -57,6 +60,14 @@ class LookupElementFactory(
|
||||
|
||||
val insertHandlerProvider = basicFactory.insertHandlerProvider
|
||||
|
||||
private val superFunctions: Set<FunctionDescriptor> by lazy {
|
||||
inDescriptor.parentsWithSelf
|
||||
.filterIsInstance<FunctionDescriptor>()
|
||||
.toList()
|
||||
.flatMap { it.overriddenDescriptors }
|
||||
.toSet()
|
||||
}
|
||||
|
||||
public fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection<LookupElement> {
|
||||
val result = SmartList<LookupElement>()
|
||||
|
||||
@@ -66,8 +77,13 @@ class LookupElementFactory(
|
||||
result.add(lookupElement)
|
||||
|
||||
// add special item for function with one argument of function type with more than one parameter
|
||||
if (descriptor is FunctionDescriptor && isNormalCall && callType != CallType.SUPER_MEMBERS) {
|
||||
result.addSpecialFunctionCallElements(descriptor, useReceiverTypes)
|
||||
if (descriptor is FunctionDescriptor && isNormalCall) {
|
||||
if (callType != CallType.SUPER_MEMBERS) {
|
||||
result.addSpecialFunctionCallElements(descriptor, useReceiverTypes)
|
||||
}
|
||||
else if (useReceiverTypes) {
|
||||
result.addIfNotNull(createSuperFunctionCallWithArguments(descriptor))
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -94,7 +110,7 @@ class LookupElementFactory(
|
||||
val fuzzyParameterType = FuzzyType(parameterType, descriptor.typeParameters)
|
||||
for ((variable, substitutor) in contextVariablesProvider.functionTypeVariables(fuzzyParameterType)) {
|
||||
val substitutedDescriptor = descriptor.substitute(substitutor)
|
||||
add(createFunctionCallElementWithArgument(substitutedDescriptor, variable.name.render(), useReceiverTypes))
|
||||
add(createFunctionCallElementWithArguments(substitutedDescriptor, variable.name.render(), useReceiverTypes))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,21 +153,35 @@ class LookupElementFactory(
|
||||
return lookupElement
|
||||
}
|
||||
|
||||
private fun createFunctionCallElementWithArgument(descriptor: FunctionDescriptor, argumentText: String, useReceiverTypes: Boolean): LookupElement {
|
||||
private fun createSuperFunctionCallWithArguments(descriptor: FunctionDescriptor): LookupElement? {
|
||||
if (descriptor.valueParameters.isEmpty()) return null
|
||||
if (descriptor !in superFunctions) return null
|
||||
|
||||
val argumentText = descriptor.valueParameters.map {
|
||||
(if (it.varargElementType != null) "*" else "") + it.name.render()
|
||||
}.joinToString(", ")
|
||||
|
||||
val lookupElement = createFunctionCallElementWithArguments(descriptor, argumentText, true)
|
||||
lookupElement.assignPriority(ItemPriority.SUPER_METHOD_WITH_ARGUMENTS)
|
||||
lookupElement.putUserData(KotlinCompletionCharFilter.SUPPRESS_ITEM_SELECTION_BY_CHARS_ON_TYPING, Unit)
|
||||
return lookupElement
|
||||
}
|
||||
|
||||
private fun createFunctionCallElementWithArguments(descriptor: FunctionDescriptor, argumentText: String, useReceiverTypes: Boolean): LookupElement {
|
||||
var lookupElement = createLookupElement(descriptor, useReceiverTypes)
|
||||
|
||||
val needTypeArguments = (insertHandlerProvider.insertHandler(descriptor) as KotlinFunctionInsertHandler.Normal).inputTypeArguments
|
||||
return FunctionCallWithArgumentLookupElement(lookupElement, descriptor, argumentText, needTypeArguments)
|
||||
return FunctionCallWithArgumentsLookupElement(lookupElement, descriptor, argumentText, needTypeArguments)
|
||||
}
|
||||
|
||||
private inner class FunctionCallWithArgumentLookupElement(
|
||||
private inner class FunctionCallWithArgumentsLookupElement(
|
||||
originalLookupElement: LookupElement,
|
||||
private val descriptor: FunctionDescriptor,
|
||||
private val argumentText: String,
|
||||
private val needTypeArguments: Boolean
|
||||
) : LookupElementDecorator<LookupElement>(originalLookupElement) {
|
||||
|
||||
override fun equals(other: Any?) = other is FunctionCallWithArgumentLookupElement && delegate == other.delegate && argumentText == other.argumentText
|
||||
override fun equals(other: Any?) = other is FunctionCallWithArgumentsLookupElement && delegate == other.delegate && argumentText == other.argumentText
|
||||
override fun hashCode() = delegate.hashCode() * 17 + argumentText.hashCode()
|
||||
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
open class B<T> {
|
||||
open fun xxx_foo(p1: T, vararg p2: String) {}
|
||||
open fun xxx_bar(p1: Int, p2: String) {}
|
||||
open val xxx_val: Int = 0
|
||||
}
|
||||
|
||||
class C : B<String>() {
|
||||
override fun xxx_foo(p1: String, vararg p2: String) {
|
||||
super.xxx_<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// WITH_ORDER
|
||||
// EXIST: { lookupString: "xxx_foo", itemText: "xxx_foo", tailText: "(p1, *p2)", typeText: "Unit", attributes: "bold" }
|
||||
// EXIST: { lookupString: "xxx_foo", itemText: "xxx_foo", tailText: "(p1: String, vararg p2: String)", typeText: "Unit", attributes: "bold" }
|
||||
// EXIST: { lookupString: "xxx_val", itemText: "xxx_val", tailText: null, typeText: "Int", attributes: "bold" }
|
||||
// EXIST: { lookupString: "xxx_bar", itemText: "xxx_bar", tailText: "(p1: Int, p2: String)", typeText: "Unit", attributes: "bold" }
|
||||
// NOTHING_ELSE
|
||||
@@ -0,0 +1,17 @@
|
||||
open class B {
|
||||
open fun foo() {}
|
||||
open fun bar() {}
|
||||
}
|
||||
|
||||
class C : B() {
|
||||
override fun foo() {
|
||||
super.<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: { lookupString: "foo", itemText: "foo", tailText: "()", typeText: "Unit", attributes: "bold" }
|
||||
// EXIST: { lookupString: "bar", itemText: "bar", tailText: "()", typeText: "Unit", attributes: "bold" }
|
||||
// EXIST: equals
|
||||
// EXIST: hashCode
|
||||
// EXIST: toString
|
||||
// NOTHING_ELSE
|
||||
@@ -8,4 +8,5 @@ class Derived : Base() {
|
||||
}
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
// ELEMENT: foo
|
||||
// TAIL_TEXT: "(p: Int)"
|
||||
@@ -8,4 +8,5 @@ class Derived : Base() {
|
||||
}
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
// ELEMENT: foo
|
||||
// TAIL_TEXT: "(p: Int)"
|
||||
@@ -0,0 +1,12 @@
|
||||
open class Base {
|
||||
open fun foo(p1: Int, vararg p2: Int){}
|
||||
}
|
||||
|
||||
class Derived : Base() {
|
||||
override fun foo(p1: Int, vararg p2: Int) {
|
||||
super.<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
// TAIL_TEXT: "(p1, *p2)"
|
||||
@@ -0,0 +1,12 @@
|
||||
open class Base {
|
||||
open fun foo(p1: Int, vararg p2: Int){}
|
||||
}
|
||||
|
||||
class Derived : Base() {
|
||||
override fun foo(p1: Int, vararg p2: Int) {
|
||||
super.foo(p1, *p2)<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
// TAIL_TEXT: "(p1, *p2)"
|
||||
@@ -0,0 +1,16 @@
|
||||
open class B {
|
||||
open fun foo(p1: Int, p2: String): Int = 0
|
||||
open fun bar(p1: Int, p2: String): Int = 0
|
||||
}
|
||||
|
||||
class C : B() {
|
||||
override fun foo(p1: Int, p2: String): Int {
|
||||
return super.<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: { lookupString: "foo", itemText: "foo", tailText: "(p1, p2)", typeText: "Int", attributes: "bold" }
|
||||
// EXIST: { lookupString: "foo", itemText: "foo", tailText: "(p1: Int, p2: String)", typeText: "Int", attributes: "bold" }
|
||||
// EXIST: { lookupString: "bar", itemText: "bar", tailText: "(p1: Int, p2: String)", typeText: "Int", attributes: "bold" }
|
||||
// EXIST: hashCode
|
||||
// NOTHING_ELSE
|
||||
+12
@@ -703,6 +703,18 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SuperMembers3.kt")
|
||||
public void testSuperMembers3() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/SuperMembers3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SuperMembers4.kt")
|
||||
public void testSuperMembers4() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/SuperMembers4.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("TopLevelClassCompletionInQualifiedCall.kt")
|
||||
public void testTopLevelClassCompletionInQualifiedCall() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TopLevelClassCompletionInQualifiedCall.kt");
|
||||
|
||||
+12
@@ -703,6 +703,18 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SuperMembers3.kt")
|
||||
public void testSuperMembers3() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/SuperMembers3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SuperMembers4.kt")
|
||||
public void testSuperMembers4() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/SuperMembers4.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("TopLevelClassCompletionInQualifiedCall.kt")
|
||||
public void testTopLevelClassCompletionInQualifiedCall() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TopLevelClassCompletionInQualifiedCall.kt");
|
||||
|
||||
+6
@@ -485,6 +485,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SuperMembers2.kt")
|
||||
public void testSuperMembers2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/SuperMembers2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ThisConstructorArgument.kt")
|
||||
public void testThisConstructorArgument() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/ThisConstructorArgument.kt");
|
||||
|
||||
+6
@@ -149,6 +149,12 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SuperMethod2.kt")
|
||||
public void testSuperMethod2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/SuperMethod2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SuperTypeArg.kt")
|
||||
public void testSuperTypeArg() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/SuperTypeArg.kt");
|
||||
|
||||
Reference in New Issue
Block a user