Fixed extensions completion for runtime receiver type in debugger (broken by previos changes in extensions completion)
This commit is contained in:
+23
-29
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.idea.resolve.frontendService
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtCodeFragment
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.KtTypeReference
|
||||
@@ -43,8 +42,6 @@ import org.jetbrains.kotlin.resolve.scopes.utils.collectSyntheticExtensionProper
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope
|
||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.util.*
|
||||
|
||||
@@ -59,10 +56,10 @@ class ReferenceVariantsHelper(
|
||||
nameFilter: (Name) -> Boolean,
|
||||
filterOutJavaGettersAndSetters: Boolean = false,
|
||||
filterOutShadowed: Boolean = true,
|
||||
useRuntimeReceiverType: Boolean = false
|
||||
useReceiverType: KotlinType? = null
|
||||
): Collection<DeclarationDescriptor>
|
||||
= getReferenceVariants(expression, CallTypeAndReceiver.detect(expression),
|
||||
kindFilter, nameFilter, filterOutJavaGettersAndSetters, filterOutShadowed, useRuntimeReceiverType)
|
||||
kindFilter, nameFilter, filterOutJavaGettersAndSetters, filterOutShadowed, useReceiverType)
|
||||
|
||||
fun getReferenceVariants(
|
||||
contextElement: PsiElement,
|
||||
@@ -71,10 +68,10 @@ class ReferenceVariantsHelper(
|
||||
nameFilter: (Name) -> Boolean,
|
||||
filterOutJavaGettersAndSetters: Boolean = false,
|
||||
filterOutShadowed: Boolean = true,
|
||||
useRuntimeReceiverType: Boolean = false
|
||||
useReceiverType: KotlinType? = null
|
||||
): Collection<DeclarationDescriptor> {
|
||||
var variants: Collection<DeclarationDescriptor>
|
||||
= getReferenceVariantsNoVisibilityFilter(contextElement, kindFilter, nameFilter, callTypeAndReceiver, useRuntimeReceiverType)
|
||||
= getReferenceVariantsNoVisibilityFilter(contextElement, kindFilter, nameFilter, callTypeAndReceiver, useReceiverType)
|
||||
.filter { !it.isAnnotatedAsHidden() && visibilityFilter(it) }
|
||||
|
||||
if (filterOutShadowed) {
|
||||
@@ -108,7 +105,7 @@ class ReferenceVariantsHelper(
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
useRuntimeReceiverType: Boolean
|
||||
useReceiverType: KotlinType?
|
||||
): Collection<DeclarationDescriptor> {
|
||||
val callType = callTypeAndReceiver.callType
|
||||
|
||||
@@ -164,19 +161,26 @@ class ReferenceVariantsHelper(
|
||||
descriptors.addAll(qualifier.scope.getDescriptorsFiltered(kindFilter exclude DescriptorKindExclude.Extensions, nameFilter))
|
||||
}
|
||||
|
||||
val expressionType = if (useRuntimeReceiverType)
|
||||
getQualifierRuntimeType(receiverExpression)
|
||||
else
|
||||
bindingContext.getType(receiverExpression)
|
||||
if (expressionType != null && !expressionType.isError()) {
|
||||
val receiverValue = ExpressionReceiver(receiverExpression, expressionType)
|
||||
val explicitReceiverTypes = smartCastManager
|
||||
.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, bindingContext, containingDeclaration, dataFlowInfo)
|
||||
|
||||
descriptors.processAll(implicitReceiverTypes, explicitReceiverTypes, resolutionScope, callType, kindFilter, nameFilter)
|
||||
val explicitReceiverTypes = if (useReceiverType != null) {
|
||||
listOf(useReceiverType)
|
||||
}
|
||||
else {
|
||||
val expressionType = bindingContext.getType(receiverExpression)
|
||||
if (expressionType != null && !expressionType.isError()) {
|
||||
val receiverValue = ExpressionReceiver(receiverExpression, expressionType)
|
||||
smartCastManager.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, bindingContext, containingDeclaration, dataFlowInfo)
|
||||
|
||||
}
|
||||
else {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
descriptors.processAll(implicitReceiverTypes, explicitReceiverTypes, resolutionScope, callType, kindFilter, nameFilter)
|
||||
}
|
||||
else {
|
||||
assert(useReceiverType == null) { "'useReceiverType' parameter is not supported for implicit receiver" }
|
||||
|
||||
descriptors.processAll(implicitReceiverTypes, implicitReceiverTypes, resolutionScope, callType, kindFilter, nameFilter)
|
||||
|
||||
// add non-instance members
|
||||
@@ -310,6 +314,7 @@ class ReferenceVariantsHelper(
|
||||
nameFilter: (Name) -> Boolean
|
||||
) {
|
||||
if (kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) return
|
||||
if (receiverTypes.isEmpty()) return
|
||||
|
||||
fun process(extension: CallableDescriptor) {
|
||||
if (kindFilter.accepts(extension) && nameFilter(extension.name)) {
|
||||
@@ -334,15 +339,4 @@ class ReferenceVariantsHelper(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getQualifierRuntimeType(receiver: KtExpression): KotlinType? {
|
||||
val type = bindingContext.getType(receiver)
|
||||
if (type != null && TypeUtils.canHaveSubtypes(KotlinTypeChecker.DEFAULT, type)) {
|
||||
val evaluator = receiver.getContainingFile().getCopyableUserData(KtCodeFragment.RUNTIME_TYPE_EVALUATOR)
|
||||
val runtimeType = evaluator?.invoke(receiver)
|
||||
if (runtimeType == type) return null
|
||||
return runtimeType
|
||||
}
|
||||
return type
|
||||
}
|
||||
}
|
||||
|
||||
+24
-13
@@ -49,6 +49,8 @@ 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.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
@@ -268,14 +270,17 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
data class ReferenceVariants(val imported: Collection<DeclarationDescriptor>, val notImportedExtensions: Collection<CallableDescriptor>)
|
||||
|
||||
protected val referenceVariants: ReferenceVariants? by lazy {
|
||||
if (descriptorKindFilter == null) return@lazy null
|
||||
descriptorKindFilter?.let { collectReferenceVariants(it) }
|
||||
}
|
||||
|
||||
private fun collectReferenceVariants(descriptorKindFilter: DescriptorKindFilter, runtimeReceiverType: KotlinType? = null): ReferenceVariants {
|
||||
var variants = referenceVariantsHelper.getReferenceVariants(
|
||||
nameExpression!!,
|
||||
descriptorKindFilter!!,
|
||||
descriptorKindFilter,
|
||||
descriptorNameFilter,
|
||||
filterOutJavaGettersAndSetters = false,
|
||||
filterOutShadowed = false)
|
||||
filterOutShadowed = false,
|
||||
useReceiverType = runtimeReceiverType)
|
||||
|
||||
variants = variants.excludeNonInitializedVariable(nameExpression)
|
||||
|
||||
@@ -283,7 +288,12 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
|
||||
var notImportedExtensions: Collection<CallableDescriptor> = emptyList()
|
||||
if (callTypeAndReceiver.shouldCompleteCallableExtensions()) {
|
||||
val extensions = indicesHelper.getCallableTopLevelExtensions({ prefixMatcher.prefixMatches(it) }, callTypeAndReceiver, expression!!, bindingContext)
|
||||
val nameFilter: (String) -> Boolean = { prefixMatcher.prefixMatches(it) }
|
||||
val extensions = if (runtimeReceiverType != null)
|
||||
indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, listOf(runtimeReceiverType), nameFilter)
|
||||
else
|
||||
indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, expression!!, bindingContext, nameFilter)
|
||||
|
||||
val pair = extensions.partition { isImportableDescriptorImported(it) }
|
||||
variants += pair.first
|
||||
notImportedExtensions = pair.second
|
||||
@@ -298,7 +308,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
variants = referenceVariantsHelper.filterOutJavaGettersAndSetters(variants)
|
||||
}
|
||||
|
||||
ReferenceVariants(variants, notImportedExtensions)
|
||||
return ReferenceVariants(variants, notImportedExtensions)
|
||||
}
|
||||
|
||||
// filters out variable inside its initializer
|
||||
@@ -315,14 +325,15 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
}
|
||||
|
||||
protected fun getRuntimeReceiverTypeReferenceVariants(): Collection<DeclarationDescriptor> {
|
||||
val descriptors = referenceVariantsHelper.getReferenceVariants(
|
||||
nameExpression!!,
|
||||
descriptorKindFilter!!,
|
||||
descriptorNameFilter,
|
||||
useRuntimeReceiverType = true,
|
||||
filterOutJavaGettersAndSetters = configuration.filterOutJavaGettersAndSetters
|
||||
).excludeNonInitializedVariable(nameExpression)
|
||||
return descriptors.filter { descriptor ->
|
||||
val explicitReceiver = callTypeAndReceiver.receiver as? KtExpression ?: return emptyList()
|
||||
val type = bindingContext.getType(explicitReceiver) ?: return emptyList()
|
||||
if (!TypeUtils.canHaveSubtypes(KotlinTypeChecker.DEFAULT, type)) return emptyList()
|
||||
val evaluator = file.getCopyableUserData(KtCodeFragment.RUNTIME_TYPE_EVALUATOR) ?: return emptyList()
|
||||
val runtimeType = evaluator(explicitReceiver)
|
||||
if (runtimeType == null || runtimeType == type) return emptyList()
|
||||
|
||||
val (variants, notImportedExtensions/*TODO: use them*/) = collectReferenceVariants(descriptorKindFilter!!, runtimeType)
|
||||
return variants.filter { descriptor ->
|
||||
referenceVariants!!.imported.none { compareDescriptors(project, it, descriptor) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,13 +90,22 @@ public class KotlinIndicesHelper(
|
||||
}
|
||||
|
||||
public fun getCallableTopLevelExtensions(
|
||||
nameFilter: (String) -> Boolean,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
position: KtExpression,
|
||||
bindingContext: BindingContext
|
||||
bindingContext: BindingContext,
|
||||
nameFilter: (String) -> Boolean
|
||||
): Collection<CallableDescriptor> {
|
||||
val receiverTypes = callTypeAndReceiver.receiverTypes(bindingContext, position, moduleDescriptor, resolutionFacade, predictableSmartCastsOnly = false)
|
||||
if (receiverTypes == null || receiverTypes.isEmpty()) return emptyList()
|
||||
?: return emptyList()
|
||||
return getCallableTopLevelExtensions(callTypeAndReceiver, receiverTypes, nameFilter)
|
||||
}
|
||||
|
||||
public fun getCallableTopLevelExtensions(
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
receiverTypes: Collection<KotlinType>,
|
||||
nameFilter: (String) -> Boolean
|
||||
): Collection<CallableDescriptor> {
|
||||
if (receiverTypes.isEmpty()) return emptyList()
|
||||
|
||||
val receiverTypeNames = HashSet<String>()
|
||||
receiverTypes.forEach { receiverTypeNames.addTypeNames(it) }
|
||||
|
||||
@@ -33,16 +33,18 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.JetBundle
|
||||
import org.jetbrains.kotlin.idea.actions.*
|
||||
import org.jetbrains.kotlin.idea.actions.KotlinAddImportAction
|
||||
import org.jetbrains.kotlin.idea.actions.createGroupedImportsAction
|
||||
import org.jetbrains.kotlin.idea.actions.createSingleImportAction
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolveScope
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper
|
||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||
import org.jetbrains.kotlin.idea.core.isVisible
|
||||
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
|
||||
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
|
||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isImportDirectiveExpression
|
||||
@@ -166,7 +168,7 @@ internal abstract class AutoImportFixBase<T: KtExpression>(expression: T, val di
|
||||
}
|
||||
}
|
||||
|
||||
result.addAll(indicesHelper.getCallableTopLevelExtensions({ it == nameStr }, callTypeAndReceiver, element, bindingContext))
|
||||
result.addAll(indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, element, bindingContext) { it == nameStr })
|
||||
|
||||
return if (result.size > 1)
|
||||
reduceCandidatesBasedOnDependencyRuleViolation(result, file)
|
||||
|
||||
Reference in New Issue
Block a user