From c068bd3158ab8c2b8a27e5cf578e3ab4454b07f4 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 31 Aug 2016 19:46:03 +0300 Subject: [PATCH] Fixed correct detection of bold members in case of multiple receivers (broken by previous changes) --- .../idea/completion/LookupElementFactory.kt | 41 +++++++++++-------- .../basic/common/boldOrGrayed/TwoReceivers.kt | 23 +++++++++++ .../test/JSBasicCompletionTestGenerated.java | 6 +++ .../test/JvmBasicCompletionTestGenerated.java | 6 +++ 4 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 idea/idea-completion/testData/basic/common/boldOrGrayed/TwoReceivers.kt diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt index 46903ca06c8..ff687f3986e 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt @@ -47,6 +47,7 @@ import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.addIfNotNull +import java.util.* interface AbstractLookupElementFactory { fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection @@ -342,30 +343,34 @@ class LookupElementFactory( ?: dispatchReceiverParameter ?: return null + val matchingReceiverIndices = HashSet() + var bestReceiverType: ReceiverType? = null + var bestWeight: CallableWeightEnum? = null for (receiverType in receiverTypes) { val weight = callableWeightForReceiverType(receiverType.type, receiverParameter.type) if (weight != null) { - val receiverIndex = receiverType.receiverIndex - - var receiverIndexToUse: Int? = receiverIndex - if (receiverIndex == 0) { - val maxReceiverIndex = receiverTypes.map { it.receiverIndex }.max()!! - if (maxReceiverIndex > 0) { - val matchesAllReceivers = receiverTypes - .filter { it.receiverIndex != 0 && callableWeightForReceiverType(it.type, receiverParameter.type) != null } - .map { it.receiverIndex } - .toSet() - .containsAll((1..maxReceiverIndex).toList()) - if (matchesAllReceivers) { // if descriptor is matching all receivers then use null as receiverIndex - otherwise e.g. all members of Any would have too high priority - receiverIndexToUse = null - } - } + if (bestWeight == null || weight < bestWeight) { + bestWeight = weight + bestReceiverType = receiverType } - - return CallableWeight(weight, receiverIndexToUse) + matchingReceiverIndices.add(receiverType.receiverIndex) } } - return onReceiverTypeMismatch + + if (bestWeight == null) return onReceiverTypeMismatch + + val receiverIndex = bestReceiverType!!.receiverIndex + + var receiverIndexToUse: Int? = receiverIndex + val maxReceiverIndex = receiverTypes.map { it.receiverIndex }.max()!! + if (maxReceiverIndex > 0) { + val matchesAllReceivers = (0..maxReceiverIndex).all { it in matchingReceiverIndices } + if (matchesAllReceivers) { // if descriptor is matching all receivers then use null as receiverIndex - otherwise e.g. all members of Any would have too high priority + receiverIndexToUse = null + } + } + + return CallableWeight(bestWeight, receiverIndexToUse) } private fun CallableDescriptor.callableWeightForReceiverType(receiverType: KotlinType, receiverParameterType: KotlinType): CallableWeightEnum? { diff --git a/idea/idea-completion/testData/basic/common/boldOrGrayed/TwoReceivers.kt b/idea/idea-completion/testData/basic/common/boldOrGrayed/TwoReceivers.kt new file mode 100644 index 00000000000..15d4321ee21 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/boldOrGrayed/TwoReceivers.kt @@ -0,0 +1,23 @@ +interface Base { + fun inBase() +} + +interface I1 : Base { + fun inI1() +} + +interface I2 : I1 { + fun inI2() +} + +fun foo(i1: I1, i2: I2) { + with(i1) { + with(i2) { + + } + } +} +// EXIST: { lookupString: "inI1", attributes: "bold" } +// EXIST: { lookupString: "inI2", attributes: "bold" } +// EXIST: { lookupString: "inBase", attributes: "" } +// EXIST: { lookupString: "equals", attributes: "" } diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java index 25cc68d2531..ab91487bc91 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java @@ -1184,6 +1184,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/boldOrGrayed/SafeCallAfterNullable.kt"); doTest(fileName); } + + @TestMetadata("TwoReceivers.kt") + public void testTwoReceivers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/boldOrGrayed/TwoReceivers.kt"); + doTest(fileName); + } } @TestMetadata("idea/idea-completion/testData/basic/common/callableReference") diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java index 99ac71c9d84..6647cd5d75d 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java @@ -1184,6 +1184,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/boldOrGrayed/SafeCallAfterNullable.kt"); doTest(fileName); } + + @TestMetadata("TwoReceivers.kt") + public void testTwoReceivers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/boldOrGrayed/TwoReceivers.kt"); + doTest(fileName); + } } @TestMetadata("idea/idea-completion/testData/basic/common/callableReference")