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 {
|
protected fun createLookupElementFactory(contextVariablesProvider: ContextVariablesProvider): LookupElementFactory {
|
||||||
return LookupElementFactory(basicLookupElementFactory, resolutionFacade, receiverTypes,
|
return LookupElementFactory(basicLookupElementFactory, resolutionFacade, receiverTypes,
|
||||||
callTypeAndReceiver.callType, contextVariablesProvider)
|
callTypeAndReceiver.callType, inDescriptor, contextVariablesProvider)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun detectCallTypeAndReceiverTypes(): Pair<CallTypeAndReceiver<*, *>, Collection<KotlinType>?> {
|
private fun detectCallTypeAndReceiverTypes(): Pair<CallTypeAndReceiver<*, *>, Collection<KotlinType>?> {
|
||||||
|
|||||||
@@ -16,7 +16,10 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.completion
|
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.codeInsight.lookup.*
|
||||||
import com.intellij.openapi.progress.ProcessCanceledException
|
import com.intellij.openapi.progress.ProcessCanceledException
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
@@ -62,6 +65,7 @@ tailrec fun <T : Any> LookupElement.getUserDataDeep(key: Key<T>): T? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum class ItemPriority {
|
enum class ItemPriority {
|
||||||
|
SUPER_METHOD_WITH_ARGUMENTS,
|
||||||
DEFAULT,
|
DEFAULT,
|
||||||
IMPLEMENT,
|
IMPLEMENT,
|
||||||
OVERRIDE,
|
OVERRIDE,
|
||||||
|
|||||||
+37
-7
@@ -34,11 +34,13 @@ import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
|||||||
import org.jetbrains.kotlin.renderer.render
|
import org.jetbrains.kotlin.renderer.render
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
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.SamAdapterExtensionFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
|
||||||
data /* we need copy() */
|
data /* we need copy() */
|
||||||
class LookupElementFactory(
|
class LookupElementFactory(
|
||||||
@@ -46,6 +48,7 @@ class LookupElementFactory(
|
|||||||
private val resolutionFacade: ResolutionFacade,
|
private val resolutionFacade: ResolutionFacade,
|
||||||
private val receiverTypes: Collection<KotlinType>?,
|
private val receiverTypes: Collection<KotlinType>?,
|
||||||
private val callType: CallType<*>?,
|
private val callType: CallType<*>?,
|
||||||
|
private val inDescriptor: DeclarationDescriptor,
|
||||||
private val contextVariablesProvider: ContextVariablesProvider
|
private val contextVariablesProvider: ContextVariablesProvider
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
@@ -57,6 +60,14 @@ class LookupElementFactory(
|
|||||||
|
|
||||||
val insertHandlerProvider = basicFactory.insertHandlerProvider
|
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> {
|
public fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection<LookupElement> {
|
||||||
val result = SmartList<LookupElement>()
|
val result = SmartList<LookupElement>()
|
||||||
|
|
||||||
@@ -66,8 +77,13 @@ class LookupElementFactory(
|
|||||||
result.add(lookupElement)
|
result.add(lookupElement)
|
||||||
|
|
||||||
// add special item for function with one argument of function type with more than one parameter
|
// 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) {
|
if (descriptor is FunctionDescriptor && isNormalCall) {
|
||||||
result.addSpecialFunctionCallElements(descriptor, useReceiverTypes)
|
if (callType != CallType.SUPER_MEMBERS) {
|
||||||
|
result.addSpecialFunctionCallElements(descriptor, useReceiverTypes)
|
||||||
|
}
|
||||||
|
else if (useReceiverTypes) {
|
||||||
|
result.addIfNotNull(createSuperFunctionCallWithArguments(descriptor))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@@ -94,7 +110,7 @@ class LookupElementFactory(
|
|||||||
val fuzzyParameterType = FuzzyType(parameterType, descriptor.typeParameters)
|
val fuzzyParameterType = FuzzyType(parameterType, descriptor.typeParameters)
|
||||||
for ((variable, substitutor) in contextVariablesProvider.functionTypeVariables(fuzzyParameterType)) {
|
for ((variable, substitutor) in contextVariablesProvider.functionTypeVariables(fuzzyParameterType)) {
|
||||||
val substitutedDescriptor = descriptor.substitute(substitutor)
|
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
|
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)
|
var lookupElement = createLookupElement(descriptor, useReceiverTypes)
|
||||||
|
|
||||||
val needTypeArguments = (insertHandlerProvider.insertHandler(descriptor) as KotlinFunctionInsertHandler.Normal).inputTypeArguments
|
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,
|
originalLookupElement: LookupElement,
|
||||||
private val descriptor: FunctionDescriptor,
|
private val descriptor: FunctionDescriptor,
|
||||||
private val argumentText: String,
|
private val argumentText: String,
|
||||||
private val needTypeArguments: Boolean
|
private val needTypeArguments: Boolean
|
||||||
) : LookupElementDecorator<LookupElement>(originalLookupElement) {
|
) : 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 hashCode() = delegate.hashCode() * 17 + argumentText.hashCode()
|
||||||
|
|
||||||
override fun renderElement(presentation: LookupElementPresentation) {
|
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
|
||||||
@@ -9,3 +9,4 @@ class Derived : Base() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ELEMENT: foo
|
// ELEMENT: foo
|
||||||
|
// TAIL_TEXT: "(p: Int)"
|
||||||
@@ -9,3 +9,4 @@ 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);
|
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")
|
@TestMetadata("TopLevelClassCompletionInQualifiedCall.kt")
|
||||||
public void testTopLevelClassCompletionInQualifiedCall() throws Exception {
|
public void testTopLevelClassCompletionInQualifiedCall() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TopLevelClassCompletionInQualifiedCall.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TopLevelClassCompletionInQualifiedCall.kt");
|
||||||
|
|||||||
+12
@@ -703,6 +703,18 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("TopLevelClassCompletionInQualifiedCall.kt")
|
||||||
public void testTopLevelClassCompletionInQualifiedCall() throws Exception {
|
public void testTopLevelClassCompletionInQualifiedCall() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TopLevelClassCompletionInQualifiedCall.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TopLevelClassCompletionInQualifiedCall.kt");
|
||||||
|
|||||||
+6
@@ -485,6 +485,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("ThisConstructorArgument.kt")
|
||||||
public void testThisConstructorArgument() throws Exception {
|
public void testThisConstructorArgument() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/ThisConstructorArgument.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/ThisConstructorArgument.kt");
|
||||||
|
|||||||
+6
@@ -149,6 +149,12 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("SuperTypeArg.kt")
|
||||||
public void testSuperTypeArg() throws Exception {
|
public void testSuperTypeArg() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/SuperTypeArg.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/SuperTypeArg.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user