extensionsUtils.kt uses FuzzyType + more correct treatment of receiver nullability there
This commit is contained in:
+32
-35
@@ -36,6 +36,7 @@ import org.jetbrains.jet.lang.types.JetType
|
|||||||
import org.jetbrains.jet.lang.types.TypeUtils
|
import org.jetbrains.jet.lang.types.TypeUtils
|
||||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker
|
||||||
import org.jetbrains.jet.lexer.JetTokens
|
import org.jetbrains.jet.lexer.JetTokens
|
||||||
|
import org.jetbrains.jet.plugin.util.CallType
|
||||||
import org.jetbrains.jet.plugin.util.substituteExtensionIfCallable
|
import org.jetbrains.jet.plugin.util.substituteExtensionIfCallable
|
||||||
|
|
||||||
public class ReferenceVariantsHelper(
|
public class ReferenceVariantsHelper(
|
||||||
@@ -43,12 +44,6 @@ public class ReferenceVariantsHelper(
|
|||||||
private val visibilityFilter: (DeclarationDescriptor) -> Boolean
|
private val visibilityFilter: (DeclarationDescriptor) -> Boolean
|
||||||
) {
|
) {
|
||||||
|
|
||||||
public enum class CallType {
|
|
||||||
NORMAL
|
|
||||||
INFIX
|
|
||||||
SAFE
|
|
||||||
}
|
|
||||||
|
|
||||||
public data class ReceiversData(
|
public data class ReceiversData(
|
||||||
public val receivers: Collection<ReceiverValue>,
|
public val receivers: Collection<ReceiverValue>,
|
||||||
public val callType: CallType
|
public val callType: CallType
|
||||||
@@ -114,7 +109,7 @@ public class ReferenceVariantsHelper(
|
|||||||
variant.getMemberScope().getDescriptorsFiltered(mask, nameFilter).filterTo(descriptors, ::filterIfInfix)
|
variant.getMemberScope().getDescriptorsFiltered(mask, nameFilter).filterTo(descriptors, ::filterIfInfix)
|
||||||
}
|
}
|
||||||
|
|
||||||
descriptors.addCallableExtensions(resolutionScope, receiverValue, dataFlowInfo, callType == CallType.INFIX, kindFilter, nameFilter)
|
descriptors.addCallableExtensions(resolutionScope, receiverValue, dataFlowInfo, callType, kindFilter, nameFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
return descriptors
|
return descriptors
|
||||||
@@ -132,7 +127,7 @@ public class ReferenceVariantsHelper(
|
|||||||
|
|
||||||
for (descriptor in resolutionScope.getDescriptorsFiltered(kindFilter, nameFilter)) {
|
for (descriptor in resolutionScope.getDescriptorsFiltered(kindFilter, nameFilter)) {
|
||||||
if (descriptor is CallableDescriptor && descriptor.getExtensionReceiverParameter() != null) {
|
if (descriptor is CallableDescriptor && descriptor.getExtensionReceiverParameter() != null) {
|
||||||
descriptorsSet.addAll(descriptor.substituteExtensionIfCallable(receiverValues, context, dataFlowInfo, false))
|
descriptorsSet.addAll(descriptor.substituteExtensionIfCallable(receiverValues, context, dataFlowInfo, CallType.NORMAL))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
descriptorsSet.add(descriptor)
|
descriptorsSet.add(descriptor)
|
||||||
@@ -165,42 +160,17 @@ public class ReferenceVariantsHelper(
|
|||||||
return type
|
return type
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getReferenceVariantsReceiver(expression: JetSimpleNameExpression): Pair<JetExpression, CallType>? {
|
|
||||||
val receiverExpression = expression.getReceiverExpression() ?: return null
|
|
||||||
val parent = expression.getParent()
|
|
||||||
val callType = when (parent) {
|
|
||||||
is JetBinaryExpression -> CallType.INFIX
|
|
||||||
|
|
||||||
is JetCallExpression -> {
|
|
||||||
if ((parent.getParent() as JetQualifiedExpression).getOperationSign() == JetTokens.SAFE_ACCESS)
|
|
||||||
CallType.SAFE
|
|
||||||
else
|
|
||||||
CallType.NORMAL
|
|
||||||
}
|
|
||||||
|
|
||||||
is JetQualifiedExpression -> {
|
|
||||||
if (parent.getOperationSign() == JetTokens.SAFE_ACCESS)
|
|
||||||
CallType.SAFE
|
|
||||||
else
|
|
||||||
CallType.NORMAL
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> return null
|
|
||||||
}
|
|
||||||
return receiverExpression to callType
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun MutableCollection<DeclarationDescriptor>.addCallableExtensions(
|
private fun MutableCollection<DeclarationDescriptor>.addCallableExtensions(
|
||||||
resolutionScope: JetScope,
|
resolutionScope: JetScope,
|
||||||
receiver: ReceiverValue,
|
receiver: ReceiverValue,
|
||||||
dataFlowInfo: DataFlowInfo,
|
dataFlowInfo: DataFlowInfo,
|
||||||
isInfixCall: Boolean,
|
callType: CallType,
|
||||||
kindFilter: DescriptorKindFilter,
|
kindFilter: DescriptorKindFilter,
|
||||||
nameFilter: (Name) -> Boolean
|
nameFilter: (Name) -> Boolean
|
||||||
) {
|
) {
|
||||||
if (!kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) {
|
if (!kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) {
|
||||||
for (callable in resolutionScope.getDescriptorsFiltered(kindFilter.exclude(DescriptorKindExclude.NonExtensions), nameFilter)) {
|
for (callable in resolutionScope.getDescriptorsFiltered(kindFilter.exclude(DescriptorKindExclude.NonExtensions), nameFilter)) {
|
||||||
addAll((callable as CallableDescriptor).substituteExtensionIfCallable(receiver, isInfixCall, context, dataFlowInfo))
|
addAll((callable as CallableDescriptor).substituteExtensionIfCallable(receiver, callType, context, dataFlowInfo))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,4 +182,31 @@ public class ReferenceVariantsHelper(
|
|||||||
val resolutionScope = context[BindingContext.RESOLUTION_SCOPE, expression] ?: return listOf()
|
val resolutionScope = context[BindingContext.RESOLUTION_SCOPE, expression] ?: return listOf()
|
||||||
return resolutionScope.getDescriptorsFiltered(DescriptorKindFilter.PACKAGES, nameFilter).filter(visibilityFilter)
|
return resolutionScope.getDescriptorsFiltered(DescriptorKindFilter.PACKAGES, nameFilter).filter(visibilityFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class object {
|
||||||
|
public fun getReferenceVariantsReceiver(expression: JetSimpleNameExpression): Pair<JetExpression, CallType>? {
|
||||||
|
val receiverExpression = expression.getReceiverExpression() ?: return null
|
||||||
|
val parent = expression.getParent()
|
||||||
|
val callType = when (parent) {
|
||||||
|
is JetBinaryExpression -> CallType.INFIX
|
||||||
|
|
||||||
|
is JetCallExpression -> {
|
||||||
|
if ((parent.getParent() as JetQualifiedExpression).getOperationSign() == JetTokens.SAFE_ACCESS)
|
||||||
|
CallType.SAFE
|
||||||
|
else
|
||||||
|
CallType.NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
is JetQualifiedExpression -> {
|
||||||
|
if (parent.getOperationSign() == JetTokens.SAFE_ACCESS)
|
||||||
|
CallType.SAFE
|
||||||
|
else
|
||||||
|
CallType.NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> return null
|
||||||
|
}
|
||||||
|
return receiverExpression to callType
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ import java.util.LinkedHashMap
|
|||||||
import org.jetbrains.jet.lang.types.Variance
|
import org.jetbrains.jet.lang.types.Variance
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition
|
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintsUtil
|
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintsUtil
|
||||||
import org.jetbrains.jet.plugin.util.makeNotNullable
|
|
||||||
import org.jetbrains.jet.plugin.util.makeNullable
|
|
||||||
import org.jetbrains.jet.lang.types.TypeSubstitutor
|
import org.jetbrains.jet.lang.types.TypeSubstitutor
|
||||||
import org.jetbrains.jet.lang.types.typeUtil.isSubtypeOf
|
import org.jetbrains.jet.lang.types.typeUtil.isSubtypeOf
|
||||||
|
|
||||||
@@ -36,7 +34,6 @@ fun CallableDescriptor.fuzzyReturnType(): FuzzyType? {
|
|||||||
return FuzzyType(returnType, getTypeParameters())
|
return FuzzyType(returnType, getTypeParameters())
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: replace code in extensionsUtils.kt with use of FuzzyType
|
|
||||||
fun CallableDescriptor.fuzzyExtensionReceiverType(): FuzzyType? {
|
fun CallableDescriptor.fuzzyExtensionReceiverType(): FuzzyType? {
|
||||||
val receiverParameter = getExtensionReceiverParameter()
|
val receiverParameter = getExtensionReceiverParameter()
|
||||||
return if (receiverParameter != null) FuzzyType(receiverParameter.getType(), getTypeParameters()) else null
|
return if (receiverParameter != null) FuzzyType(receiverParameter.getType(), getTypeParameters()) else null
|
||||||
@@ -64,10 +61,30 @@ class FuzzyType(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun matchedSubstitutor(expectedType: JetType): TypeSubstitutor? {
|
public fun checkIsSubtypeOf(otherType: JetType): TypeSubstitutor?
|
||||||
|
= matchedSubstitutor(otherType, MatchKind.IS_SUBTYPE)
|
||||||
|
|
||||||
|
public fun checkIsSuperTypeOf(otherType: JetType): TypeSubstitutor?
|
||||||
|
= matchedSubstitutor(otherType, MatchKind.IS_SUPERTYPE)
|
||||||
|
|
||||||
|
private enum class MatchKind {
|
||||||
|
IS_SUBTYPE
|
||||||
|
IS_SUPERTYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun matchedSubstitutor(otherType: JetType, matchKind: MatchKind): TypeSubstitutor? {
|
||||||
if (type.isError()) return null
|
if (type.isError()) return null
|
||||||
|
if (otherType.isError()) return null
|
||||||
|
|
||||||
|
fun JetType.checkInheritance(otherType: JetType): Boolean {
|
||||||
|
return when (matchKind) {
|
||||||
|
MatchKind.IS_SUBTYPE -> this.isSubtypeOf(otherType)
|
||||||
|
MatchKind.IS_SUPERTYPE -> otherType.isSubtypeOf(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (usedTypeParameters == null || usedTypeParameters.isEmpty()) {
|
if (usedTypeParameters == null || usedTypeParameters.isEmpty()) {
|
||||||
return if (type.isSubtypeOf(expectedType)) TypeSubstitutor.EMPTY else null
|
return if (type.checkInheritance(otherType)) TypeSubstitutor.EMPTY else null
|
||||||
}
|
}
|
||||||
|
|
||||||
val constraintSystem = ConstraintSystemImpl()
|
val constraintSystem = ConstraintSystemImpl()
|
||||||
@@ -79,11 +96,15 @@ class FuzzyType(
|
|||||||
}
|
}
|
||||||
constraintSystem.registerTypeVariables(typeVariables)
|
constraintSystem.registerTypeVariables(typeVariables)
|
||||||
|
|
||||||
constraintSystem.addSubtypeConstraint(type, expectedType, ConstraintPosition.SPECIAL/*TODO?*/)
|
when (matchKind) {
|
||||||
|
MatchKind.IS_SUBTYPE -> constraintSystem.addSubtypeConstraint(type, otherType, ConstraintPosition.SPECIAL)
|
||||||
|
MatchKind.IS_SUPERTYPE -> constraintSystem.addSubtypeConstraint(otherType, type, ConstraintPosition.SPECIAL)
|
||||||
|
}
|
||||||
|
|
||||||
if (constraintSystem.getStatus().isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, true)) {
|
if (constraintSystem.getStatus().isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, true)) {
|
||||||
val substitutor = constraintSystem.getResultingSubstitutor()
|
val substitutor = constraintSystem.getResultingSubstitutor()
|
||||||
val substitutedType = substitutor.substitute(type, Variance.INVARIANT/*TODO?*/)
|
val substitutedType = substitutor.substitute(type, Variance.INVARIANT)
|
||||||
return if (substitutedType.isSubtypeOf(expectedType)) substitutor else null
|
return if (substitutedType != null && substitutedType.checkInheritance(otherType)) substitutor else null
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -23,23 +23,19 @@ import org.jetbrains.jet.lang.resolve.calls.smartcasts.DataFlowInfo
|
|||||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope
|
import org.jetbrains.jet.lang.resolve.scopes.JetScope
|
||||||
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor
|
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor
|
||||||
import org.jetbrains.jet.lang.resolve.calls.smartcasts.SmartCastUtils
|
import org.jetbrains.jet.lang.resolve.calls.smartcasts.SmartCastUtils
|
||||||
import org.jetbrains.jet.lang.types.JetType
|
import org.jetbrains.jet.lang.types.TypeUtils
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl
|
|
||||||
import java.util.LinkedHashMap
|
public enum class CallType {
|
||||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
|
NORMAL
|
||||||
import org.jetbrains.jet.lang.types.Variance
|
SAFE
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition
|
INFIX
|
||||||
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.substituteExtensionIfCallable(receivers: Collection<ReceiverValue>,
|
public fun CallableDescriptor.substituteExtensionIfCallable(receivers: Collection<ReceiverValue>,
|
||||||
context: BindingContext,
|
context: BindingContext,
|
||||||
dataFlowInfo: DataFlowInfo,
|
dataFlowInfo: DataFlowInfo,
|
||||||
isInfixCall: Boolean): Collection<CallableDescriptor> {
|
callType: CallType): Collection<CallableDescriptor> {
|
||||||
val stream = receivers.stream().flatMap { substituteExtensionIfCallable(it, isInfixCall, context, dataFlowInfo).stream() }
|
val stream = receivers.stream().flatMap { substituteExtensionIfCallable(it, callType, context, dataFlowInfo).stream() }
|
||||||
if (getTypeParameters().isEmpty()) { // optimization for non-generic callables
|
if (getTypeParameters().isEmpty()) { // optimization for non-generic callables
|
||||||
return stream.firstOrNull()?.let { listOf(it) } ?: listOf()
|
return stream.firstOrNull()?.let { listOf(it) } ?: listOf()
|
||||||
}
|
}
|
||||||
@@ -49,24 +45,36 @@ public fun CallableDescriptor.substituteExtensionIfCallable(receivers: Collectio
|
|||||||
}
|
}
|
||||||
|
|
||||||
public fun CallableDescriptor.substituteExtensionIfCallableWithImplicitReceiver(scope: JetScope, context: BindingContext, dataFlowInfo: DataFlowInfo): Collection<CallableDescriptor>
|
public fun CallableDescriptor.substituteExtensionIfCallableWithImplicitReceiver(scope: JetScope, context: BindingContext, dataFlowInfo: DataFlowInfo): Collection<CallableDescriptor>
|
||||||
= substituteExtensionIfCallable(scope.getImplicitReceiversHierarchy().map { it.getValue() }, context, dataFlowInfo, false)
|
= substituteExtensionIfCallable(scope.getImplicitReceiversHierarchy().map { it.getValue() }, context, dataFlowInfo, CallType.NORMAL)
|
||||||
|
|
||||||
public fun CallableDescriptor.substituteExtensionIfCallable(
|
public fun CallableDescriptor.substituteExtensionIfCallable(
|
||||||
receiver: ReceiverValue,
|
receiver: ReceiverValue,
|
||||||
isInfixCall: Boolean,
|
callType: CallType,
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
dataFlowInfo: DataFlowInfo
|
dataFlowInfo: DataFlowInfo
|
||||||
): Collection<CallableDescriptor> {
|
): Collection<CallableDescriptor> {
|
||||||
val receiverParameter = getExtensionReceiverParameter()!!
|
|
||||||
if (!receiver.exists()) return listOf()
|
if (!receiver.exists()) return listOf()
|
||||||
|
|
||||||
if (isInfixCall && (this !is SimpleFunctionDescriptor || getValueParameters().size() != 1)) {
|
if (callType == CallType.INFIX && (this !is SimpleFunctionDescriptor || getValueParameters().size() != 1)) {
|
||||||
return listOf()
|
return listOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
val substitutors = SmartCastUtils.getSmartCastVariants(receiver, bindingContext, dataFlowInfo)
|
var types = SmartCastUtils.getSmartCastVariants(receiver, bindingContext, dataFlowInfo).stream()
|
||||||
.stream()
|
|
||||||
.map { checkReceiverResolution(it, receiverParameter, getTypeParameters()) }
|
if (callType == CallType.SAFE) {
|
||||||
|
types = types.map { it.makeNotNullable() }
|
||||||
|
}
|
||||||
|
|
||||||
|
val extensionReceiverType = fuzzyExtensionReceiverType()!!
|
||||||
|
val substitutors = types
|
||||||
|
.map {
|
||||||
|
var substitutor = extensionReceiverType.checkIsSuperTypeOf(it)
|
||||||
|
// check if we may fail due to receiver expression being nullable
|
||||||
|
if (substitutor == null && TypeUtils.isNullableType(it) && !TypeUtils.isNullableType(extensionReceiverType.type)) {
|
||||||
|
substitutor = extensionReceiverType.checkIsSuperTypeOf(it.makeNotNullable())
|
||||||
|
}
|
||||||
|
substitutor
|
||||||
|
}
|
||||||
.filterNotNull()
|
.filterNotNull()
|
||||||
if (getTypeParameters().isEmpty()) { // optimization for non-generic callables
|
if (getTypeParameters().isEmpty()) { // optimization for non-generic callables
|
||||||
return if (substitutors.any()) listOf(this) else listOf()
|
return if (substitutors.any()) listOf(this) else listOf()
|
||||||
@@ -76,38 +84,3 @@ public fun CallableDescriptor.substituteExtensionIfCallable(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkReceiverResolution(
|
|
||||||
receiverType: JetType,
|
|
||||||
receiverParameter: ReceiverParameterDescriptor,
|
|
||||||
typeParameters: List<TypeParameterDescriptor>
|
|
||||||
): TypeSubstitutor? {
|
|
||||||
val typeParamsInReceiver = HashSet<TypeParameterDescriptor>()
|
|
||||||
typeParamsInReceiver.addUsedTypeParameters(receiverParameter.getType())
|
|
||||||
|
|
||||||
val constraintSystem = ConstraintSystemImpl()
|
|
||||||
val typeVariables = LinkedHashMap<TypeParameterDescriptor, Variance>()
|
|
||||||
for (typeParameter in typeParameters) {
|
|
||||||
if (typeParamsInReceiver.contains(typeParameter)) {
|
|
||||||
typeVariables[typeParameter] = Variance.INVARIANT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
constraintSystem.registerTypeVariables(typeVariables)
|
|
||||||
|
|
||||||
constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), ConstraintPosition.RECEIVER_POSITION)
|
|
||||||
|
|
||||||
if (constraintSystem.getStatus().isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, true)) {
|
|
||||||
return constraintSystem.getResultingSubstitutor()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun MutableSet<TypeParameterDescriptor>.addUsedTypeParameters(jetType: JetType) {
|
|
||||||
addIfNotNull(jetType.getConstructor().getDeclarationDescriptor() as? TypeParameterDescriptor)
|
|
||||||
|
|
||||||
for (argument in jetType.getArguments()) {
|
|
||||||
addUsedTypeParameters(argument.getType())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import org.jetbrains.jet.lang.resolve.name.FqName
|
|||||||
import org.jetbrains.jet.lang.psi.*
|
import org.jetbrains.jet.lang.psi.*
|
||||||
import org.jetbrains.jet.lang.resolve.*
|
import org.jetbrains.jet.lang.resolve.*
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name
|
import org.jetbrains.jet.lang.resolve.name.Name
|
||||||
import org.jetbrains.jet.lang.psi.psiUtil.getReceiverExpression
|
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope
|
import org.jetbrains.jet.lang.resolve.scopes.JetScope
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import java.util.HashSet
|
import java.util.HashSet
|
||||||
@@ -36,6 +35,8 @@ import org.jetbrains.jet.lang.resolve.calls.smartcasts.DataFlowInfo
|
|||||||
import com.intellij.psi.stubs.StringStubIndexExtension
|
import com.intellij.psi.stubs.StringStubIndexExtension
|
||||||
import org.jetbrains.jet.plugin.caches.resolve.ResolutionFacade
|
import org.jetbrains.jet.plugin.caches.resolve.ResolutionFacade
|
||||||
import org.jetbrains.jet.plugin.util.substituteExtensionIfCallable
|
import org.jetbrains.jet.plugin.util.substituteExtensionIfCallable
|
||||||
|
import org.jetbrains.jet.plugin.util.CallType
|
||||||
|
import org.jetbrains.jet.plugin.codeInsight.ReferenceVariantsHelper
|
||||||
|
|
||||||
public class KotlinIndicesHelper(
|
public class KotlinIndicesHelper(
|
||||||
private val project: Project,
|
private val project: Project,
|
||||||
@@ -110,9 +111,9 @@ public class KotlinIndicesHelper(
|
|||||||
dataFlowInfo: DataFlowInfo) {
|
dataFlowInfo: DataFlowInfo) {
|
||||||
val matchingNames = fqNames.filter { nameFilter(it.shortName().asString()) }
|
val matchingNames = fqNames.filter { nameFilter(it.shortName().asString()) }
|
||||||
|
|
||||||
val receiverExpression = expression.getReceiverExpression()
|
val receiverPair = ReferenceVariantsHelper.getReferenceVariantsReceiver(expression)
|
||||||
if (receiverExpression != null) {
|
if (receiverPair != null) {
|
||||||
val isInfixCall = expression.getParent() is JetBinaryExpression
|
val (receiverExpression, callType) = receiverPair
|
||||||
|
|
||||||
val expressionType = bindingContext[BindingContext.EXPRESSION_TYPE, receiverExpression]
|
val expressionType = bindingContext[BindingContext.EXPRESSION_TYPE, receiverExpression]
|
||||||
if (expressionType == null || expressionType.isError()) return
|
if (expressionType == null || expressionType.isError()) return
|
||||||
@@ -122,7 +123,7 @@ public class KotlinIndicesHelper(
|
|||||||
val receiverValue = ExpressionReceiver(receiverExpression, expressionType)
|
val receiverValue = ExpressionReceiver(receiverExpression, expressionType)
|
||||||
|
|
||||||
matchingNames.flatMapTo(this) {
|
matchingNames.flatMapTo(this) {
|
||||||
findSuitableExtensions(it, index, receiverValue, dataFlowInfo, isInfixCall, resolutionScope, moduleDescriptor, bindingContext)
|
findSuitableExtensions(it, index, receiverValue, dataFlowInfo, callType, resolutionScope, moduleDescriptor, bindingContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -130,7 +131,7 @@ public class KotlinIndicesHelper(
|
|||||||
|
|
||||||
for (receiver in resolutionScope.getImplicitReceiversHierarchy()) {
|
for (receiver in resolutionScope.getImplicitReceiversHierarchy()) {
|
||||||
matchingNames.flatMapTo(this) {
|
matchingNames.flatMapTo(this) {
|
||||||
findSuitableExtensions(it, index, receiver.getValue(), dataFlowInfo, false, resolutionScope, moduleDescriptor, bindingContext)
|
findSuitableExtensions(it, index, receiver.getValue(), dataFlowInfo, CallType.NORMAL, resolutionScope, moduleDescriptor, bindingContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,7 +144,7 @@ public class KotlinIndicesHelper(
|
|||||||
index: StringStubIndexExtension<out JetCallableDeclaration>?,
|
index: StringStubIndexExtension<out JetCallableDeclaration>?,
|
||||||
receiverValue: ReceiverValue,
|
receiverValue: ReceiverValue,
|
||||||
dataFlowInfo: DataFlowInfo,
|
dataFlowInfo: DataFlowInfo,
|
||||||
isInfixCall: Boolean,
|
callType: CallType,
|
||||||
resolutionScope: JetScope,
|
resolutionScope: JetScope,
|
||||||
module: ModuleDescriptor,
|
module: ModuleDescriptor,
|
||||||
bindingContext: BindingContext): Stream<CallableDescriptor> {
|
bindingContext: BindingContext): Stream<CallableDescriptor> {
|
||||||
@@ -162,7 +163,7 @@ public class KotlinIndicesHelper(
|
|||||||
|
|
||||||
return descriptors.stream()
|
return descriptors.stream()
|
||||||
.filter(visibilityFilter)
|
.filter(visibilityFilter)
|
||||||
.flatMap { it.substituteExtensionIfCallable(receiverValue, isInfixCall, bindingContext, dataFlowInfo).stream() }
|
.flatMap { it.substituteExtensionIfCallable(receiverValue, callType, bindingContext, dataFlowInfo).stream() }
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun getClassDescriptors(nameFilter: (String) -> Boolean, kindFilter: (ClassKind) -> Boolean): Collection<ClassDescriptor> {
|
public fun getClassDescriptors(nameFilter: (String) -> Boolean, kindFilter: (ClassKind) -> Boolean): Collection<ClassDescriptor> {
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import org.jetbrains.jet.plugin.refactoring.comparePossiblyOverridingDescriptors
|
|||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
import org.jetbrains.jet.lang.psi.psiUtil.getStrictParentOfType
|
import org.jetbrains.jet.lang.psi.psiUtil.getStrictParentOfType
|
||||||
import org.jetbrains.jet.plugin.util.makeNotNullable
|
import org.jetbrains.jet.plugin.util.makeNotNullable
|
||||||
|
import org.jetbrains.jet.plugin.util.CallType
|
||||||
|
|
||||||
class CompletionSessionConfiguration(
|
class CompletionSessionConfiguration(
|
||||||
val completeNonImportedDeclarations: Boolean,
|
val completeNonImportedDeclarations: Boolean,
|
||||||
@@ -80,7 +81,7 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess
|
|||||||
var receiverTypes = receivers.flatMap {
|
var receiverTypes = receivers.flatMap {
|
||||||
SmartCastUtils.getSmartCastVariantsWithLessSpecificExcluded(it, bindingContext, dataFlowInfo)
|
SmartCastUtils.getSmartCastVariantsWithLessSpecificExcluded(it, bindingContext, dataFlowInfo)
|
||||||
}
|
}
|
||||||
if (callType == ReferenceVariantsHelper.CallType.SAFE) {
|
if (callType == CallType.SAFE) {
|
||||||
receiverTypes = receiverTypes.map { it.makeNotNullable() }
|
receiverTypes = receiverTypes.map { it.makeNotNullable() }
|
||||||
}
|
}
|
||||||
receiverTypes
|
receiverTypes
|
||||||
|
|||||||
@@ -129,12 +129,12 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
|
|||||||
val result = ArrayList<LookupElement>()
|
val result = ArrayList<LookupElement>()
|
||||||
val types = descriptor.fuzzyTypes(smartCastTypes)
|
val types = descriptor.fuzzyTypes(smartCastTypes)
|
||||||
val classifier = { (expectedInfo: ExpectedInfo) ->
|
val classifier = { (expectedInfo: ExpectedInfo) ->
|
||||||
val substitutor = types.stream().map { it.matchedSubstitutor(expectedInfo.type) }.firstOrNull()
|
val substitutor = types.stream().map { it.checkIsSubtypeOf(expectedInfo.type) }.firstOrNull()
|
||||||
if (substitutor != null) {
|
if (substitutor != null) {
|
||||||
ExpectedInfoClassification.matches(substitutor)
|
ExpectedInfoClassification.matches(substitutor)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val substitutor2 = types.stream().map { it.makeNotNullable().matchedSubstitutor(expectedInfo.type) }.firstOrNull()
|
val substitutor2 = types.stream().map { it.makeNotNullable().checkIsSubtypeOf(expectedInfo.type) }.firstOrNull()
|
||||||
if (substitutor2 != null) {
|
if (substitutor2 != null) {
|
||||||
ExpectedInfoClassification.matchesIfNotNullable(substitutor2)
|
ExpectedInfoClassification.matchesIfNotNullable(substitutor2)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,13 +111,13 @@ class ExpectedInfoClassification private(val substitutor: TypeSubstitutor?, val
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun FuzzyType.classifyExpectedInfo(expectedInfo: ExpectedInfo): ExpectedInfoClassification {
|
fun FuzzyType.classifyExpectedInfo(expectedInfo: ExpectedInfo): ExpectedInfoClassification {
|
||||||
val substitutor = matchedSubstitutor(expectedInfo.type)
|
val substitutor = checkIsSubtypeOf(expectedInfo.type)
|
||||||
if (substitutor != null) {
|
if (substitutor != null) {
|
||||||
return ExpectedInfoClassification.matches(substitutor)
|
return ExpectedInfoClassification.matches(substitutor)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNullable()) {
|
if (isNullable()) {
|
||||||
val substitutor2 = makeNotNullable().matchedSubstitutor(expectedInfo.type)
|
val substitutor2 = makeNotNullable().checkIsSubtypeOf(expectedInfo.type)
|
||||||
if (substitutor2 != null) {
|
if (substitutor2 != null) {
|
||||||
return ExpectedInfoClassification.matchesIfNotNullable(substitutor2)
|
return ExpectedInfoClassification.matchesIfNotNullable(substitutor2)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun<T> T.doSomething(t: T): T = t
|
||||||
|
|
||||||
|
fun foo(s: String?) {
|
||||||
|
s.<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXIST: { itemText: "doSomething", tailText: "(t: String?) for T in <root>", typeText: "String?" }
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun<T> T.doSomething(t: T): T = t
|
||||||
|
|
||||||
|
fun foo(s: String?) {
|
||||||
|
s?.<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXIST: { itemText: "doSomething", tailText: "(t: String) for T in <root>", typeText: "String" }
|
||||||
@@ -826,6 +826,18 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("SubstitutedSignature5.kt")
|
||||||
|
public void testSubstitutedSignature5() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/SubstitutedSignature5.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("SubstitutedSignature6.kt")
|
||||||
|
public void testSubstitutedSignature6() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/SubstitutedSignature6.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("TopLevelClassCompletionInQualifiedCall.kt")
|
@TestMetadata("TopLevelClassCompletionInQualifiedCall.kt")
|
||||||
public void testTopLevelClassCompletionInQualifiedCall() throws Exception {
|
public void testTopLevelClassCompletionInQualifiedCall() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/TopLevelClassCompletionInQualifiedCall.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/TopLevelClassCompletionInQualifiedCall.kt");
|
||||||
|
|||||||
@@ -826,6 +826,18 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("SubstitutedSignature5.kt")
|
||||||
|
public void testSubstitutedSignature5() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/SubstitutedSignature5.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("SubstitutedSignature6.kt")
|
||||||
|
public void testSubstitutedSignature6() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/SubstitutedSignature6.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("TopLevelClassCompletionInQualifiedCall.kt")
|
@TestMetadata("TopLevelClassCompletionInQualifiedCall.kt")
|
||||||
public void testTopLevelClassCompletionInQualifiedCall() throws Exception {
|
public void testTopLevelClassCompletionInQualifiedCall() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/TopLevelClassCompletionInQualifiedCall.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/TopLevelClassCompletionInQualifiedCall.kt");
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package org.jetbrains.jet.completion;
|
|||||||
import com.intellij.testFramework.TestDataPath;
|
import com.intellij.testFramework.TestDataPath;
|
||||||
import org.jetbrains.jet.JUnit3RunnerWithInners;
|
import org.jetbrains.jet.JUnit3RunnerWithInners;
|
||||||
import org.jetbrains.jet.JetTestUtils;
|
import org.jetbrains.jet.JetTestUtils;
|
||||||
|
import org.jetbrains.jet.test.InnerTestClasses;
|
||||||
import org.jetbrains.jet.test.TestMetadata;
|
import org.jetbrains.jet.test.TestMetadata;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user