Moved methods for checking extensions applicability from TipsManager to extensionUtils.kt (and made them all extension methods)
This commit is contained in:
@@ -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.scopes.receivers.ReceiverValue
|
||||||
import org.jetbrains.jet.lang.resolve.calls.smartcasts.DataFlowInfo
|
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.codeInsight.TipsManager
|
import org.jetbrains.jet.plugin.util.extensionsUtils.isExtensionCallable
|
||||||
|
|
||||||
public class KotlinIndicesHelper(private val project: Project,
|
public class KotlinIndicesHelper(private val project: Project,
|
||||||
private val resolveSession: ResolveSessionForBodies,
|
private val resolveSession: ResolveSessionForBodies,
|
||||||
@@ -211,8 +211,9 @@ public class KotlinIndicesHelper(private val project: Project,
|
|||||||
.filter { it.getExtensionReceiverParameter() != null }
|
.filter { it.getExtensionReceiverParameter() != null }
|
||||||
}
|
}
|
||||||
|
|
||||||
return descriptors.filter { visibilityFilter(it) &&
|
return descriptors.filter {
|
||||||
TipsManager.checkIsExtensionCallable(receiverValue, it, isInfixCall, bindingContext, dataFlowInfo) }
|
visibilityFilter(it) && it.isExtensionCallable(receiverValue, isInfixCall, bindingContext, dataFlowInfo)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun getClassDescriptors(nameFilter: (String) -> Boolean, kindFilter: (ClassKind) -> Boolean): Collection<ClassDescriptor> {
|
public fun getClassDescriptors(nameFilter: (String) -> Boolean, kindFilter: (ClassKind) -> Boolean): Collection<ClassDescriptor> {
|
||||||
|
|||||||
@@ -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.getDescriptorsFiltered
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.DescriptorKindFilter
|
import org.jetbrains.jet.lang.resolve.scopes.DescriptorKindFilter
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.DescriptorKindExclude
|
import org.jetbrains.jet.lang.resolve.scopes.DescriptorKindExclude
|
||||||
import org.jetbrains.jet.lang.types.JetType
|
import org.jetbrains.jet.plugin.util.extensionsUtils.isExtensionCallable
|
||||||
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
|
|
||||||
|
|
||||||
public object TipsManager{
|
public object TipsManager{
|
||||||
|
|
||||||
@@ -153,88 +148,14 @@ public object TipsManager{
|
|||||||
resolutionScope.getDescriptorsFiltered(kindFilter, nameFilter)
|
resolutionScope.getDescriptorsFiltered(kindFilter, nameFilter)
|
||||||
.stream()
|
.stream()
|
||||||
.filterIsInstance(javaClass<CallableDescriptor>())
|
.filterIsInstance(javaClass<CallableDescriptor>())
|
||||||
.filterTo(this) { checkIsExtensionCallable(receiver, it, isInfixCall, context, dataFlowInfo) }
|
.filterTo(this) { it.isExtensionCallable(receiver, isInfixCall, context, dataFlowInfo) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun CallableDescriptor.isExtensionCallable(receivers: Collection<ReceiverValue>,
|
|
||||||
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,
|
public fun getPackageReferenceVariants(expression: JetSimpleNameExpression,
|
||||||
context: BindingContext,
|
context: BindingContext,
|
||||||
nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
|
nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
|
||||||
val resolutionScope = context[BindingContext.RESOLUTION_SCOPE, expression] ?: return listOf()
|
val resolutionScope = context[BindingContext.RESOLUTION_SCOPE, expression] ?: return listOf()
|
||||||
return resolutionScope.getDescriptorsFiltered(DescriptorKindFilter.PACKAGES, nameFilter)
|
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<TypeParameterDescriptor, Variance>()
|
|
||||||
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<Name> {
|
|
||||||
val typeNames = HashSet<Name>()
|
|
||||||
|
|
||||||
val descriptor = jetType.getConstructor().getDeclarationDescriptor()
|
|
||||||
if (descriptor != null) {
|
|
||||||
typeNames.add(descriptor.getName())
|
|
||||||
}
|
|
||||||
|
|
||||||
for (argument in jetType.getArguments()) {
|
|
||||||
typeNames.addAll(collectUsedTypeNames(argument.getType()))
|
|
||||||
}
|
|
||||||
|
|
||||||
return typeNames
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.resolve.scopes.JetScope;
|
||||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingComponents;
|
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingComponents;
|
||||||
import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
|
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.project.ResolveSessionForBodies;
|
||||||
|
import org.jetbrains.jet.plugin.util.extensionsUtils.ExtensionsUtilsPackage;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
@@ -83,7 +83,7 @@ public abstract class BaseJetVariableMacro extends Macro {
|
|||||||
VariableDescriptor variableDescriptor = (VariableDescriptor) declarationDescriptor;
|
VariableDescriptor variableDescriptor = (VariableDescriptor) declarationDescriptor;
|
||||||
|
|
||||||
if (variableDescriptor.getExtensionReceiverParameter() != null
|
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)) {
|
if (isSuitable(variableDescriptor, scope, project, components)) {
|
||||||
filteredDescriptors.add(variableDescriptor);
|
filteredDescriptors.add(variableDescriptor);
|
||||||
|
|||||||
@@ -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<ReceiverValue>,
|
||||||
|
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<TypeParameterDescriptor, Variance>()
|
||||||
|
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<Name> {
|
||||||
|
val typeNames = HashSet<Name>()
|
||||||
|
|
||||||
|
val descriptor = jetType.getConstructor().getDeclarationDescriptor()
|
||||||
|
if (descriptor != null) {
|
||||||
|
typeNames.add(descriptor.getName())
|
||||||
|
}
|
||||||
|
|
||||||
|
for (argument in jetType.getArguments()) {
|
||||||
|
typeNames.addAll(collectUsedTypeNames(argument.getType()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeNames
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user