More correct completion list sorting by receivers
This commit is contained in:
@@ -41,6 +41,8 @@ import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.util.supertypesWithAny
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
||||
import java.lang.RuntimeException
|
||||
import java.util.*
|
||||
|
||||
sealed class CallType<TReceiver : KtElement?>(val descriptorKindFilter: DescriptorKindFilter) {
|
||||
object UNKNOWN : CallType<Nothing?>(DescriptorKindFilter.ALL)
|
||||
@@ -208,6 +210,8 @@ sealed class CallTypeAndReceiver<TReceiver : KtElement?, out TCallType : CallTyp
|
||||
}
|
||||
}
|
||||
|
||||
data class ReceiverType(val type: KotlinType, val receiverIndex: Int)
|
||||
|
||||
fun CallTypeAndReceiver<*, *>.receiverTypes(
|
||||
bindingContext: BindingContext,
|
||||
contextElement: PsiElement,
|
||||
@@ -215,17 +219,28 @@ fun CallTypeAndReceiver<*, *>.receiverTypes(
|
||||
resolutionFacade: ResolutionFacade,
|
||||
stableSmartCastsOnly: Boolean
|
||||
): Collection<KotlinType>? {
|
||||
return receiverTypesWithIndex(bindingContext, contextElement, moduleDescriptor, resolutionFacade, stableSmartCastsOnly)?.map { it.type }
|
||||
}
|
||||
|
||||
fun CallTypeAndReceiver<*, *>.receiverTypesWithIndex(
|
||||
bindingContext: BindingContext,
|
||||
contextElement: PsiElement,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
resolutionFacade: ResolutionFacade,
|
||||
stableSmartCastsOnly: Boolean
|
||||
): Collection<ReceiverType>? {
|
||||
val receiverExpression: KtExpression?
|
||||
when (this) {
|
||||
is CallTypeAndReceiver.CALLABLE_REFERENCE -> {
|
||||
if (receiver != null) {
|
||||
val lhs = bindingContext[BindingContext.DOUBLE_COLON_LHS, receiver] ?: return emptyList()
|
||||
when (lhs) {
|
||||
is DoubleColonLHS.Type -> return listOf(lhs.type)
|
||||
is DoubleColonLHS.Type -> return listOf(ReceiverType(lhs.type, 0))
|
||||
|
||||
is DoubleColonLHS.Expression -> {
|
||||
val receiverValue = ExpressionReceiver.create(receiver, lhs.type, bindingContext)
|
||||
return receiverValueTypes(receiverValue, lhs.dataFlowInfo, bindingContext, moduleDescriptor, stableSmartCastsOnly)
|
||||
.map { ReceiverType(it, 0) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -245,12 +260,12 @@ fun CallTypeAndReceiver<*, *>.receiverTypes(
|
||||
is CallTypeAndReceiver.SUPER_MEMBERS -> {
|
||||
val qualifier = receiver.superTypeQualifier
|
||||
if (qualifier != null) {
|
||||
return bindingContext.getType(receiver).singletonOrEmptyList()
|
||||
return bindingContext.getType(receiver).singletonOrEmptyList().map { ReceiverType(it, 0) }
|
||||
}
|
||||
else {
|
||||
val resolutionScope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
|
||||
val classDescriptor = resolutionScope.ownerDescriptor.parentsWithSelf.firstIsInstanceOrNull<ClassDescriptor>() ?: return emptyList()
|
||||
return classDescriptor.typeConstructor.supertypesWithAny()
|
||||
return classDescriptor.typeConstructor.supertypesWithAny().map { ReceiverType(it, 0) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,9 +295,12 @@ fun CallTypeAndReceiver<*, *>.receiverTypes(
|
||||
|
||||
val dataFlowInfo = bindingContext.getDataFlowInfo(contextElement)
|
||||
|
||||
return receiverValues.flatMap {
|
||||
receiverValueTypes(it, dataFlowInfo, bindingContext, moduleDescriptor, stableSmartCastsOnly)
|
||||
val result = ArrayList<ReceiverType>()
|
||||
for ((receiverIndex, receiverValue) in receiverValues.withIndex()) {
|
||||
val types = receiverValueTypes(receiverValue, dataFlowInfo, bindingContext, moduleDescriptor, stableSmartCastsOnly)
|
||||
types.mapTo(result) { ReceiverType(it, receiverIndex) }
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun receiverValueTypes(
|
||||
@@ -299,4 +317,4 @@ private fun receiverValueTypes(
|
||||
else {
|
||||
listOf(receiverValue.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
@@ -135,7 +134,7 @@ abstract class CompletionSession(
|
||||
protected val referenceVariantsHelper = ReferenceVariantsHelper(bindingContext, resolutionFacade, moduleDescriptor, isVisibleFilter)
|
||||
|
||||
protected val callTypeAndReceiver: CallTypeAndReceiver<*, *>
|
||||
protected val receiverTypes: Collection<KotlinType>?
|
||||
protected val receiverTypes: Collection<ReceiverType>?
|
||||
|
||||
init {
|
||||
val (callTypeAndReceiver, receiverTypes) = detectCallTypeAndReceiverTypes()
|
||||
@@ -370,7 +369,7 @@ abstract class CompletionSession(
|
||||
val filteredNotImportedExtensions = filterVariantsForRuntimeReceiverType(notImportedExtensions, referenceVariants.notImportedExtensions)
|
||||
|
||||
val runtimeVariants = ReferenceVariants(filteredVariants, filteredNotImportedExtensions)
|
||||
return Pair(runtimeVariants, lookupElementFactory.copy(receiverTypes = listOf(runtimeType)))
|
||||
return Pair(runtimeVariants, lookupElementFactory.copy(receiverTypes = listOf(ReceiverType(runtimeType, 0))))
|
||||
}
|
||||
|
||||
private fun <TDescriptor : DeclarationDescriptor> filterVariantsForRuntimeReceiverType(
|
||||
@@ -430,19 +429,19 @@ abstract class CompletionSession(
|
||||
callTypeAndReceiver.callType, inDescriptor, contextVariablesProvider)
|
||||
}
|
||||
|
||||
private fun detectCallTypeAndReceiverTypes(): Pair<CallTypeAndReceiver<*, *>, Collection<KotlinType>?> {
|
||||
private fun detectCallTypeAndReceiverTypes(): Pair<CallTypeAndReceiver<*, *>, Collection<ReceiverType>?> {
|
||||
if (nameExpression == null) {
|
||||
return CallTypeAndReceiver.UNKNOWN to null
|
||||
}
|
||||
|
||||
val callTypeAndReceiver = CallTypeAndReceiver.detect(nameExpression)
|
||||
|
||||
var receiverTypes = callTypeAndReceiver.receiverTypes(
|
||||
var receiverTypes = callTypeAndReceiver.receiverTypesWithIndex(
|
||||
bindingContext, nameExpression, moduleDescriptor, resolutionFacade,
|
||||
stableSmartCastsOnly = true /* we don't include smart cast receiver types for "unstable" receiver value to mark members grayed */)
|
||||
|
||||
if (callTypeAndReceiver is CallTypeAndReceiver.SAFE || isDebuggerContext) {
|
||||
receiverTypes = receiverTypes?.map { it.makeNotNullable() }
|
||||
receiverTypes = receiverTypes?.map { ReceiverType(it.type.makeNotNullable(), it.receiverIndex) }
|
||||
}
|
||||
|
||||
return callTypeAndReceiver to receiverTypes
|
||||
|
||||
+3
-3
@@ -24,15 +24,15 @@ import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.idea.util.CallType
|
||||
import org.jetbrains.kotlin.idea.util.ReceiverType
|
||||
import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallable
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.createSynthesizedInvokes
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import java.util.*
|
||||
|
||||
class ExtensionFunctionTypeValueCompletion(
|
||||
private val receiverTypes: Collection<KotlinType>,
|
||||
private val receiverTypes: Collection<ReceiverType>,
|
||||
private val callType: CallType<*>,
|
||||
private val lookupElementFactory: LookupElementFactory
|
||||
) {
|
||||
@@ -49,7 +49,7 @@ class ExtensionFunctionTypeValueCompletion(
|
||||
|
||||
val invokes = variableType.memberScope.getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_IDE)
|
||||
for (invoke in createSynthesizedInvokes(invokes)) {
|
||||
for (substituted in invoke.substituteExtensionIfCallable(receiverTypes, callType)) {
|
||||
for (substituted in invoke.substituteExtensionIfCallable(receiverTypes.map { it.type }, callType)) {
|
||||
val factory = object : AbstractLookupElementFactory {
|
||||
override fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection<LookupElement> {
|
||||
if (!useReceiverTypes) return emptyList()
|
||||
|
||||
+24
-11
@@ -30,15 +30,16 @@ import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.lambdaPresentation
|
||||
import org.jetbrains.kotlin.idea.core.moveCaret
|
||||
import org.jetbrains.kotlin.idea.util.CallType
|
||||
import org.jetbrains.kotlin.idea.util.ReceiverType
|
||||
import org.jetbrains.kotlin.idea.util.toFuzzyType
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.renderer.render
|
||||
import org.jetbrains.kotlin.resolve.calls.util.getValueParametersCountFromFunctionType
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.overriddenTreeUniqueAsSequence
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.resolve.findOriginalTopMostOverriddenDescriptors
|
||||
import org.jetbrains.kotlin.resolve.calls.util.getValueParametersCountFromFunctionType
|
||||
import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor
|
||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -62,7 +63,7 @@ interface AbstractLookupElementFactory {
|
||||
data /* we need copy() */
|
||||
class LookupElementFactory(
|
||||
val basicFactory: BasicLookupElementFactory,
|
||||
private val receiverTypes: Collection<KotlinType>?,
|
||||
private val receiverTypes: Collection<ReceiverType>?,
|
||||
private val callType: CallType<*>,
|
||||
private val inDescriptor: DeclarationDescriptor,
|
||||
private val contextVariablesProvider: ContextVariablesProvider,
|
||||
@@ -324,7 +325,7 @@ class LookupElementFactory(
|
||||
return callableWeightBasic(descriptor, receiverTypes)
|
||||
}
|
||||
|
||||
private fun callableWeightBasic(descriptor: CallableDescriptor, receiverTypes: Collection<KotlinType>): CallableWeight? {
|
||||
private fun callableWeightBasic(descriptor: CallableDescriptor, receiverTypes: Collection<ReceiverType>): CallableWeight? {
|
||||
descriptor.callableWeightBasedOnReceiver(receiverTypes, CallableWeight.receiverCastRequired)?.let { return it }
|
||||
|
||||
return when (descriptor.containingDeclaration) {
|
||||
@@ -334,21 +335,33 @@ class LookupElementFactory(
|
||||
}
|
||||
|
||||
private fun CallableDescriptor.callableWeightBasedOnReceiver(
|
||||
receiverTypes: Collection<KotlinType>,
|
||||
receiverTypes: Collection<ReceiverType>,
|
||||
onReceiverTypeMismatch: CallableWeight?
|
||||
): CallableWeight? {
|
||||
val receiverParameter = extensionReceiverParameter
|
||||
?: dispatchReceiverParameter
|
||||
?: return null
|
||||
|
||||
for ((receiverIndex, receiverType) in receiverTypes.withIndex()) {
|
||||
val weight = callableWeightForReceiverType(receiverType, receiverParameter.type)
|
||||
for (receiverType in receiverTypes) {
|
||||
val weight = callableWeightForReceiverType(receiverType.type, receiverParameter.type)
|
||||
if (weight != null) {
|
||||
// if descriptor is matching all receivers then use null as receiverIndex - otherwise e.g. all members of Any would have too high priority
|
||||
val receiverIndexToUse = if (receiverIndex == 0 && receiverTypes.drop(1).all { callableWeightForReceiverType(it, receiverParameter.type) != null })
|
||||
null
|
||||
else
|
||||
receiverIndex
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CallableWeight(weight, receiverIndexToUse)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ class SmartCompletionSession(
|
||||
}
|
||||
|
||||
val filter = smartCompletion!!.descriptorFilter
|
||||
var contextVariableTypesForReferenceVariants = filter?.let {
|
||||
val contextVariableTypesForReferenceVariants = filter?.let {
|
||||
withCollectRequiredContextVariableTypes { lookupElementFactory ->
|
||||
val (imported, notImported) = referenceVariantsWithNonInitializedVarExcluded ?: return@withCollectRequiredContextVariableTypes
|
||||
imported.forEach { collector.addElements(filter(it, lookupElementFactory)) }
|
||||
|
||||
+18
-1
@@ -17,7 +17,9 @@ class Derived : Base() {
|
||||
fun aaLocalFun(){}
|
||||
|
||||
with (y) {
|
||||
aa<caret>
|
||||
if (this is Z1 && this is Z2) {
|
||||
aa<caret>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,10 +27,21 @@ class Derived : Base() {
|
||||
interface X {
|
||||
fun aaX()
|
||||
}
|
||||
|
||||
interface Y : X {
|
||||
fun aaY()
|
||||
}
|
||||
|
||||
interface Z1 {
|
||||
fun aaaZ1()
|
||||
fun aabZ1()
|
||||
}
|
||||
|
||||
interface Z2 {
|
||||
fun aaaZ2()
|
||||
fun aabZ2()
|
||||
}
|
||||
|
||||
fun Any.aaAnyExtensionFun(){}
|
||||
fun Derived.aaExtensionFun(){}
|
||||
|
||||
@@ -43,6 +56,10 @@ fun Y.aaYExt(){}
|
||||
// ORDER: aaLocalVal
|
||||
// ORDER: aaLocalFun
|
||||
// ORDER: aaY
|
||||
// ORDER: aaaZ1
|
||||
// ORDER: aaaZ2
|
||||
// ORDER: aabZ1
|
||||
// ORDER: aabZ2
|
||||
// ORDER: aaX
|
||||
// ORDER: aaYExt
|
||||
// ORDER: aaXExt
|
||||
|
||||
Reference in New Issue
Block a user