Extension methods shown with type arguments substituted in completion list
This commit is contained in:
+13
-9
@@ -32,12 +32,12 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.jet.lang.resolve.scopes.getDescriptorsFiltered
|
||||
import org.jetbrains.jet.lang.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.jet.lang.resolve.scopes.DescriptorKindExclude
|
||||
import org.jetbrains.jet.plugin.util.extensionsUtils.isExtensionCallable
|
||||
import org.jetbrains.jet.lang.types.JetType
|
||||
import org.jetbrains.jet.lang.types.TypeUtils
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker
|
||||
import org.jetbrains.jet.lexer.JetTokens
|
||||
import org.jetbrains.jet.lang.resolve.calls.callUtil.getCall
|
||||
import org.jetbrains.jet.utils.addIfNotNull
|
||||
import org.jetbrains.jet.plugin.util.extensionsUtils.substituteExtensionIfCallable
|
||||
|
||||
public class ReferenceVariantsHelper(
|
||||
private val context: BindingContext,
|
||||
@@ -131,11 +131,13 @@ public class ReferenceVariantsHelper(
|
||||
val dataFlowInfo = context.getDataFlowInfo(expression)
|
||||
val receiverValues = receivers.map { it.getValue() }
|
||||
|
||||
resolutionScope.getDescriptorsFiltered(kindFilter, nameFilter).filterTo(descriptorsSet) {
|
||||
if (it is CallableDescriptor && it.getExtensionReceiverParameter() != null)
|
||||
it.isExtensionCallable(receiverValues, context, dataFlowInfo, false)
|
||||
else
|
||||
true
|
||||
for (descriptor in resolutionScope.getDescriptorsFiltered(kindFilter, nameFilter)) {
|
||||
if (descriptor is CallableDescriptor && descriptor.getExtensionReceiverParameter() != null) {
|
||||
descriptorsSet.addIfNotNull(descriptor.substituteExtensionIfCallable(receiverValues, context, dataFlowInfo, false))
|
||||
}
|
||||
else {
|
||||
descriptorsSet.add(descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
return descriptorsSet
|
||||
@@ -198,8 +200,10 @@ public class ReferenceVariantsHelper(
|
||||
nameFilter: (Name) -> Boolean
|
||||
) {
|
||||
if (!kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) {
|
||||
resolutionScope.getDescriptorsFiltered(kindFilter.exclude(DescriptorKindExclude.NonExtensions), nameFilter)
|
||||
.filterTo(this) { (it as CallableDescriptor).isExtensionCallable(receiver, isInfixCall, context, dataFlowInfo) }
|
||||
for (callable in resolutionScope.getDescriptorsFiltered(kindFilter.exclude(DescriptorKindExclude.NonExtensions), nameFilter)) {
|
||||
val substituted = (callable as CallableDescriptor).substituteExtensionIfCallable(receiver, isInfixCall, context, dataFlowInfo)
|
||||
addIfNotNull(substituted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,52 +33,69 @@ import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintsUtil
|
||||
import org.jetbrains.jet.utils.addIfNotNull
|
||||
import java.util.HashSet
|
||||
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.jet.lang.types.TypeSubstitutor
|
||||
|
||||
public fun CallableDescriptor.isExtensionCallable(receivers: Collection<ReceiverValue>,
|
||||
//TODO: what if multiple receiver types match? this can result in different substitutions
|
||||
|
||||
public fun CallableDescriptor.substituteExtensionIfCallable(receivers: Collection<ReceiverValue>,
|
||||
context: BindingContext,
|
||||
dataFlowInfo: DataFlowInfo,
|
||||
isInfixCall: Boolean): Boolean
|
||||
= receivers.any { isExtensionCallable(it, isInfixCall, context, dataFlowInfo) }
|
||||
isInfixCall: Boolean): CallableDescriptor? {
|
||||
return receivers.stream()
|
||||
.map { substituteExtensionIfCallable(it, isInfixCall, context, dataFlowInfo) }
|
||||
.firstOrNull { it != null }
|
||||
}
|
||||
|
||||
public fun CallableDescriptor.isExtensionCallableWithImplicitReceiver(scope: JetScope, context: BindingContext, dataFlowInfo: DataFlowInfo): Boolean
|
||||
= isExtensionCallable(scope.getImplicitReceiversHierarchy().map { it.getValue() }, context, dataFlowInfo, false)
|
||||
public fun CallableDescriptor.substituteExtensionIfCallableWithImplicitReceiver(scope: JetScope, context: BindingContext, dataFlowInfo: DataFlowInfo): CallableDescriptor?
|
||||
= substituteExtensionIfCallable(scope.getImplicitReceiversHierarchy().map { it.getValue() }, context, dataFlowInfo, false)
|
||||
|
||||
public fun CallableDescriptor.isExtensionCallable(
|
||||
public fun CallableDescriptor.substituteExtensionIfCallable(
|
||||
receiver: ReceiverValue,
|
||||
isInfixCall: Boolean,
|
||||
bindingContext: BindingContext,
|
||||
dataFlowInfo: DataFlowInfo
|
||||
): Boolean {
|
||||
): CallableDescriptor? {
|
||||
val receiverParameter = getExtensionReceiverParameter()!!
|
||||
if (!receiver.exists()) return false
|
||||
if (!receiver.exists()) return null
|
||||
|
||||
if (isInfixCall && (this !is SimpleFunctionDescriptor || getValueParameters().size() != 1)) {
|
||||
return false
|
||||
return null
|
||||
}
|
||||
|
||||
return SmartCastUtils.getSmartCastVariants(receiver, bindingContext, dataFlowInfo)
|
||||
.any { checkReceiverResolution(it, receiverParameter, getTypeParameters()) }
|
||||
for (type in SmartCastUtils.getSmartCastVariants(receiver, bindingContext, dataFlowInfo)) {
|
||||
val substitutor = checkReceiverResolution(type, receiverParameter, getTypeParameters())
|
||||
if (substitutor != null) {
|
||||
return substitute(substitutor)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun checkReceiverResolution(
|
||||
receiverType: JetType,
|
||||
receiverParameter: ReceiverParameterDescriptor,
|
||||
typeParameters: List<TypeParameterDescriptor>
|
||||
): Boolean {
|
||||
val typeNamesInReceiver = HashSet<TypeParameterDescriptor>()
|
||||
typeNamesInReceiver.addUsedTypeParameters(receiverParameter.getType())
|
||||
): TypeSubstitutor? {
|
||||
val typeParamsInReceiver = HashSet<TypeParameterDescriptor>()
|
||||
typeParamsInReceiver.addUsedTypeParameters(receiverParameter.getType())
|
||||
|
||||
val constraintSystem = ConstraintSystemImpl()
|
||||
val typeVariables = LinkedHashMap<TypeParameterDescriptor, Variance>()
|
||||
for (typeParameter in typeParameters) {
|
||||
if (typeNamesInReceiver.contains(typeParameter)) {
|
||||
if (typeParamsInReceiver.contains(typeParameter)) {
|
||||
typeVariables[typeParameter] = Variance.INVARIANT
|
||||
}
|
||||
}
|
||||
constraintSystem.registerTypeVariables(typeVariables)
|
||||
|
||||
constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), ConstraintPosition.RECEIVER_POSITION)
|
||||
return constraintSystem.getStatus().isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, true)
|
||||
|
||||
if (constraintSystem.getStatus().isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, true)) {
|
||||
return constraintSystem.getResultingSubstitutor()
|
||||
}
|
||||
else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableSet<TypeParameterDescriptor>.addUsedTypeParameters(jetType: JetType) {
|
||||
|
||||
Reference in New Issue
Block a user