Completion and import popup for bound callable references

This commit is contained in:
Valentin Kipyatkov
2016-06-20 19:36:30 +03:00
parent 079d857aa2
commit e05aa41bbc
13 changed files with 206 additions and 24 deletions
@@ -152,8 +152,7 @@ class ReferenceVariantsHelper(
}
is CallTypeAndReceiver.CALLABLE_REFERENCE -> {
val resolutionScope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
return getVariantsForCallableReference(callTypeAndReceiver.receiver, resolutionScope, kindFilter, nameFilter)
return getVariantsForCallableReference(callTypeAndReceiver, contextElement, useReceiverType, kindFilter, nameFilter)
}
is CallTypeAndReceiver.DEFAULT -> receiverExpression = null
@@ -227,24 +226,37 @@ class ReferenceVariantsHelper(
}
private fun getVariantsForCallableReference(
receiverExpression: KtExpression?,
resolutionScope: LexicalScope,
callTypeAndReceiver: CallTypeAndReceiver.CALLABLE_REFERENCE,
contextElement: PsiElement,
useReceiverType: KotlinType?,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> {
val descriptors = LinkedHashSet<DeclarationDescriptor>()
if (receiverExpression != null) {
val type =
(bindingContext.get(BindingContext.DOUBLE_COLON_LHS, receiverExpression) as? DoubleColonLHS.Type)?.type
?: return emptyList()
descriptors.addNonExtensionMembers(listOf(type), kindFilter, nameFilter, constructorFilter = { true })
val resolutionScope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
descriptors.addScopeAndSyntheticExtensions(resolutionScope, listOf(type), CallType.CALLABLE_REFERENCE, kindFilter, nameFilter)
val receiver = callTypeAndReceiver.receiver
if (receiver != null) {
val isStatic = bindingContext[BindingContext.DOUBLE_COLON_LHS, receiver] is DoubleColonLHS.Type
val staticScope = (type.constructor.declarationDescriptor as? ClassDescriptor)?.staticScope
if (staticScope != null) {
descriptors.addAll(staticScope.getDescriptorsFiltered(kindFilter, nameFilter))
val explicitReceiverTypes = if (useReceiverType != null) {
listOf(useReceiverType)
}
else {
callTypeAndReceiver.receiverTypes(bindingContext, contextElement, moduleDescriptor, resolutionFacade, predictableSmartCastsOnly = false)!!
}
val constructorFilter = { descriptor: ClassDescriptor -> if (isStatic) true else descriptor.isInner }
descriptors.addNonExtensionMembers(explicitReceiverTypes, kindFilter, nameFilter, constructorFilter)
descriptors.addScopeAndSyntheticExtensions(resolutionScope, explicitReceiverTypes, CallType.CALLABLE_REFERENCE, kindFilter, nameFilter)
if (isStatic) {
explicitReceiverTypes
.map { (it.constructor.declarationDescriptor as? ClassDescriptor)?.staticScope }
.filterNotNull()
.flatMapTo(descriptors) { scope -> scope.getDescriptorsFiltered(kindFilter, nameFilter) }
}
}
else {
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.psi.psiUtil.isImportDirectiveExpression
import org.jetbrains.kotlin.psi.psiUtil.isPackageDirectiveExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
@@ -34,6 +35,7 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
import org.jetbrains.kotlin.util.supertypesWithAny
@@ -216,9 +218,20 @@ fun CallTypeAndReceiver<*, *>.receiverTypes(
val receiverExpression: KtExpression?
when (this) {
is CallTypeAndReceiver.CALLABLE_REFERENCE -> {
return receiver?.let {
(bindingContext[BindingContext.DOUBLE_COLON_LHS, it] as? DoubleColonLHS.Type)?.type
}.singletonOrEmptyList()
if (receiver != null) {
val lhs = bindingContext[BindingContext.DOUBLE_COLON_LHS, receiver] ?: return emptyList()
when (lhs) {
is DoubleColonLHS.Type -> return listOf(lhs.type)
is DoubleColonLHS.Expression -> {
val receiverValue = ExpressionReceiver.create(receiver, lhs.type, bindingContext)
return receiverValueTypes(receiverValue, lhs.dataFlowInfo, bindingContext, moduleDescriptor, predictableSmartCastsOnly)
}
}
}
else {
return emptyList()
}
}
is CallTypeAndReceiver.DEFAULT -> receiverExpression = null
@@ -267,13 +280,23 @@ fun CallTypeAndReceiver<*, *>.receiverTypes(
val dataFlowInfo = bindingContext.getDataFlowInfo(contextElement)
return receiverValues.flatMap { receiverValue ->
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, bindingContext, moduleDescriptor)
if (dataFlowValue.isPredictable || !predictableSmartCastsOnly) { // we don't include smart cast receiver types for "unpredictable" receiver value to mark members grayed
SmartCastManager().getSmartCastVariantsWithLessSpecificExcluded(receiverValue, bindingContext, moduleDescriptor, dataFlowInfo)
}
else {
listOf(receiverValue.type)
}
return receiverValues.flatMap {
receiverValueTypes(it, dataFlowInfo, bindingContext, moduleDescriptor, predictableSmartCastsOnly)
}
}
private fun receiverValueTypes(
receiverValue: ReceiverValue,
dataFlowInfo: DataFlowInfo,
bindingContext: BindingContext,
moduleDescriptor: ModuleDescriptor,
predictableSmartCastsOnly: Boolean
): List<KotlinType> {
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, bindingContext, moduleDescriptor)
return if (dataFlowValue.isPredictable || !predictableSmartCastsOnly) { // we don't include smart cast receiver types for "unpredictable" receiver value to mark members grayed
SmartCastManager().getSmartCastVariantsWithLessSpecificExcluded(receiverValue, bindingContext, moduleDescriptor, dataFlowInfo)
}
else {
listOf(receiverValue.type)
}
}