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