From 601fe05cb0d9678e133dc58bb9bb5821c95b1a7c Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 19 Nov 2014 13:27:13 +0300 Subject: [PATCH] Moved methods for checking extensions applicability from TipsManager to extensionUtils.kt (and made them all extension methods) --- .../jet/plugin/caches/KotlinIndicesHelper.kt | 7 +- .../jet/plugin/codeInsight/TipsManager.kt | 83 +------------- .../macro/BaseJetVariableMacro.java | 4 +- .../jet/plugin/util/extensionsUtils.kt | 105 ++++++++++++++++++ 4 files changed, 113 insertions(+), 86 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/util/extensionsUtils.kt diff --git a/idea/src/org/jetbrains/jet/plugin/caches/KotlinIndicesHelper.kt b/idea/src/org/jetbrains/jet/plugin/caches/KotlinIndicesHelper.kt index 5f3b4a25c1f..87a1f432ed8 100644 --- a/idea/src/org/jetbrains/jet/plugin/caches/KotlinIndicesHelper.kt +++ b/idea/src/org/jetbrains/jet/plugin/caches/KotlinIndicesHelper.kt @@ -35,7 +35,7 @@ import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver.LookupMode import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue import org.jetbrains.jet.lang.resolve.calls.smartcasts.DataFlowInfo import com.intellij.psi.stubs.StringStubIndexExtension -import org.jetbrains.jet.plugin.codeInsight.TipsManager +import org.jetbrains.jet.plugin.util.extensionsUtils.isExtensionCallable public class KotlinIndicesHelper(private val project: Project, private val resolveSession: ResolveSessionForBodies, @@ -211,8 +211,9 @@ public class KotlinIndicesHelper(private val project: Project, .filter { it.getExtensionReceiverParameter() != null } } - return descriptors.filter { visibilityFilter(it) && - TipsManager.checkIsExtensionCallable(receiverValue, it, isInfixCall, bindingContext, dataFlowInfo) } + return descriptors.filter { + visibilityFilter(it) && it.isExtensionCallable(receiverValue, isInfixCall, bindingContext, dataFlowInfo) + } } public fun getClassDescriptors(nameFilter: (String) -> Boolean, kindFilter: (ClassKind) -> Boolean): Collection { diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.kt b/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.kt index 9e712b525a4..75e4c513457 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.kt +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.kt @@ -32,12 +32,7 @@ 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.lang.types.JetType -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl -import com.google.dart.compiler.util.Maps -import org.jetbrains.jet.lang.types.Variance -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintsUtil +import org.jetbrains.jet.plugin.util.extensionsUtils.isExtensionCallable public object TipsManager{ @@ -153,88 +148,14 @@ public object TipsManager{ resolutionScope.getDescriptorsFiltered(kindFilter, nameFilter) .stream() .filterIsInstance(javaClass()) - .filterTo(this) { checkIsExtensionCallable(receiver, it, isInfixCall, context, dataFlowInfo) } + .filterTo(this) { it.isExtensionCallable(receiver, isInfixCall, context, dataFlowInfo) } } } - public fun CallableDescriptor.isExtensionCallable(receivers: Collection, - context: BindingContext, - dataFlowInfo: DataFlowInfo, - isInfixCall: Boolean): Boolean - = receivers.any { checkIsExtensionCallable(it, this, isInfixCall, context, dataFlowInfo) } - - public fun CallableDescriptor.isExtensionCallableWithImplicitReceiver(scope: JetScope, context: BindingContext, dataFlowInfo: DataFlowInfo): Boolean - = isExtensionCallable(scope.getImplicitReceiversHierarchy().map { it.getValue() }, context, dataFlowInfo, false) - public fun getPackageReferenceVariants(expression: JetSimpleNameExpression, context: BindingContext, nameFilter: (Name) -> Boolean): Collection { val resolutionScope = context[BindingContext.RESOLUTION_SCOPE, expression] ?: return listOf() return resolutionScope.getDescriptorsFiltered(DescriptorKindFilter.PACKAGES, nameFilter) } - - /* - * Checks if receiver declaration could be resolved to call expected receiver. - */ - public fun checkIsExtensionCallable( - receiverArgument: ReceiverValue, - callableDescriptor: CallableDescriptor, - isInfixCall: Boolean, - bindingContext: BindingContext, - dataFlowInfo: DataFlowInfo - ): Boolean { - if (isInfixCall && (callableDescriptor !is SimpleFunctionDescriptor || callableDescriptor.getValueParameters().size() != 1)) { - return false - } - - val types = SmartCastUtils.getSmartCastVariants(receiverArgument, bindingContext, dataFlowInfo) - - for (type in types) { - if (checkReceiverResolution(receiverArgument, type, callableDescriptor)) return true - } - - return false - } - - private fun checkReceiverResolution(receiverArgument: ReceiverValue, receiverType: JetType, callableDescriptor: CallableDescriptor): Boolean { - val receiverParameter = callableDescriptor.getExtensionReceiverParameter() - - if (!receiverArgument.exists() && receiverParameter == null) { - // Both receivers do not exist - return true - } - - if (!(receiverArgument.exists() && receiverParameter != null)) { - return false - } - - val typeNamesInReceiver = collectUsedTypeNames(receiverParameter.getType()) - - val constraintSystem = ConstraintSystemImpl() - val typeVariables = LinkedHashMap() - for (typeParameterDescriptor in callableDescriptor.getTypeParameters()) { - if (typeNamesInReceiver.contains(typeParameterDescriptor.getName())) { - typeVariables.put(typeParameterDescriptor, Variance.INVARIANT) - } - } - constraintSystem.registerTypeVariables(typeVariables) - - constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), ConstraintPosition.RECEIVER_POSITION) - return constraintSystem.getStatus().isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, true) - } - - private fun collectUsedTypeNames(jetType: JetType): Set { - val typeNames = HashSet() - - val descriptor = jetType.getConstructor().getDeclarationDescriptor() - if (descriptor != null) { - typeNames.add(descriptor.getName()) - } - - for (argument in jetType.getArguments()) { - typeNames.addAll(collectUsedTypeNames(argument.getType())) - } - - return typeNames - } } diff --git a/idea/src/org/jetbrains/jet/plugin/liveTemplates/macro/BaseJetVariableMacro.java b/idea/src/org/jetbrains/jet/plugin/liveTemplates/macro/BaseJetVariableMacro.java index 18c8c709474..60be89b860d 100644 --- a/idea/src/org/jetbrains/jet/plugin/liveTemplates/macro/BaseJetVariableMacro.java +++ b/idea/src/org/jetbrains/jet/plugin/liveTemplates/macro/BaseJetVariableMacro.java @@ -40,8 +40,8 @@ import org.jetbrains.jet.lang.resolve.scopes.DescriptorKindFilter; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingComponents; import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage; -import org.jetbrains.jet.plugin.codeInsight.TipsManager; import org.jetbrains.jet.plugin.project.ResolveSessionForBodies; +import org.jetbrains.jet.plugin.util.extensionsUtils.ExtensionsUtilsPackage; import java.util.ArrayList; import java.util.LinkedHashSet; @@ -83,7 +83,7 @@ public abstract class BaseJetVariableMacro extends Macro { VariableDescriptor variableDescriptor = (VariableDescriptor) declarationDescriptor; if (variableDescriptor.getExtensionReceiverParameter() != null - && !TipsManager.INSTANCE$.isExtensionCallableWithImplicitReceiver(variableDescriptor, scope, bindingContext, dataFlowInfo)) continue; + && !ExtensionsUtilsPackage.isExtensionCallableWithImplicitReceiver(variableDescriptor, scope, bindingContext, dataFlowInfo)) continue; if (isSuitable(variableDescriptor, scope, project, components)) { filteredDescriptors.add(variableDescriptor); diff --git a/idea/src/org/jetbrains/jet/plugin/util/extensionsUtils.kt b/idea/src/org/jetbrains/jet/plugin/util/extensionsUtils.kt new file mode 100644 index 00000000000..4ec329bdf9c --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/util/extensionsUtils.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.util.extensionsUtils + +import org.jetbrains.jet.lang.descriptors.CallableDescriptor +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.resolve.calls.smartcasts.DataFlowInfo +import org.jetbrains.jet.lang.resolve.scopes.JetScope +import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor +import org.jetbrains.jet.lang.resolve.calls.smartcasts.SmartCastUtils +import org.jetbrains.jet.lang.types.JetType +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl +import java.util.LinkedHashMap +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor +import org.jetbrains.jet.lang.types.Variance +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintsUtil +import org.jetbrains.jet.lang.resolve.name.Name +import java.util.HashSet + +public fun CallableDescriptor.isExtensionCallable(receivers: Collection, + context: BindingContext, + dataFlowInfo: DataFlowInfo, + isInfixCall: Boolean): Boolean + = receivers.any { isExtensionCallable(it, isInfixCall, context, dataFlowInfo) } + +public fun CallableDescriptor.isExtensionCallableWithImplicitReceiver(scope: JetScope, context: BindingContext, dataFlowInfo: DataFlowInfo): Boolean + = isExtensionCallable(scope.getImplicitReceiversHierarchy().map { it.getValue() }, context, dataFlowInfo, false) + +public fun CallableDescriptor.isExtensionCallable( + receiver: ReceiverValue, + isInfixCall: Boolean, + bindingContext: BindingContext, + dataFlowInfo: DataFlowInfo +): Boolean { + if (isInfixCall && (this !is SimpleFunctionDescriptor || getValueParameters().size() != 1)) { + return false + } + + val types = SmartCastUtils.getSmartCastVariants(receiver, bindingContext, dataFlowInfo) + + for (type in types) { + if (checkReceiverResolution(receiver, type, this)) return true + } + + return false +} + +private fun checkReceiverResolution(receiverArgument: ReceiverValue, receiverType: JetType, callableDescriptor: CallableDescriptor): Boolean { + val receiverParameter = callableDescriptor.getExtensionReceiverParameter() + + if (!receiverArgument.exists() && receiverParameter == null) { + // Both receivers do not exist + return true + } + + if (!(receiverArgument.exists() && receiverParameter != null)) { + return false + } + + val typeNamesInReceiver = collectUsedTypeNames(receiverParameter.getType()) + + val constraintSystem = ConstraintSystemImpl() + val typeVariables = LinkedHashMap() + for (typeParameterDescriptor in callableDescriptor.getTypeParameters()) { + if (typeNamesInReceiver.contains(typeParameterDescriptor.getName())) { + typeVariables.put(typeParameterDescriptor, Variance.INVARIANT) + } + } + constraintSystem.registerTypeVariables(typeVariables) + + constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), ConstraintPosition.RECEIVER_POSITION) + return constraintSystem.getStatus().isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, true) +} + +private fun collectUsedTypeNames(jetType: JetType): Set { + val typeNames = HashSet() + + val descriptor = jetType.getConstructor().getDeclarationDescriptor() + if (descriptor != null) { + typeNames.add(descriptor.getName()) + } + + for (argument in jetType.getArguments()) { + typeNames.addAll(collectUsedTypeNames(argument.getType())) + } + + return typeNames +} +