Refactored ReferenceVariantsHelper to allow specifying receiver

This commit is contained in:
Valentin Kipyatkov
2015-08-26 19:19:01 +03:00
parent 6dde70e358
commit fbb37f0154
6 changed files with 60 additions and 42 deletions
@@ -43,14 +43,18 @@ import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.checker.JetTypeChecker
import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.HashSet
import java.util.LinkedHashSet
import java.util.*
public class ReferenceVariantsHelper(
private val context: BindingContext,
private val resolutionFacade: ResolutionFacade,
private val visibilityFilter: (DeclarationDescriptor) -> Boolean
) {
public data class ExplicitReceiverData(
val expression: JetExpression,
val callType: CallType
)
public data class ReceiversData(
public val receivers: Collection<ReceiverValue>,
public val callType: CallType
@@ -60,18 +64,20 @@ public class ReferenceVariantsHelper(
}
}
@jvmOverloads
public fun getReferenceVariants(
expression: JetSimpleNameExpression,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
explicitReceiverData: ExplicitReceiverData? = getExplicitReceiverData(expression),
filterOutJavaGettersAndSetters: Boolean = false,
useRuntimeReceiverType: Boolean = false
): Collection<DeclarationDescriptor> {
var variants: Collection<DeclarationDescriptor>
= getReferenceVariantsNoVisibilityFilter(expression, kindFilter, useRuntimeReceiverType, nameFilter)
= getReferenceVariantsNoVisibilityFilter(expression, kindFilter, nameFilter, explicitReceiverData, useRuntimeReceiverType)
.filter(visibilityFilter)
variants = ShadowedDeclarationsFilter(context, resolutionFacade).filter(variants, expression)
variants = ShadowedDeclarationsFilter(context, resolutionFacade, expression, explicitReceiverData).filter(variants)
if (filterOutJavaGettersAndSetters) {
val accessorMethodsToRemove = HashSet<FunctionDescriptor>()
@@ -91,8 +97,9 @@ public class ReferenceVariantsHelper(
private fun getReferenceVariantsNoVisibilityFilter(
expression: JetSimpleNameExpression,
kindFilter: DescriptorKindFilter,
useRuntimeReceiverType: Boolean,
nameFilter: (Name) -> Boolean
nameFilter: (Name) -> Boolean,
explicitReceiverData: ExplicitReceiverData?,
useRuntimeReceiverType: Boolean
): Collection<DeclarationDescriptor> {
val parent = expression.getParent()
val resolutionScope = context[BindingContext.RESOLUTION_SCOPE, expression] ?: return listOf()
@@ -115,9 +122,8 @@ public class ReferenceVariantsHelper(
smartCastManager.getSmartCastVariantsWithLessSpecificExcluded(it.value, context, containingDeclaration, dataFlowInfo)
}.toSet()
val pair = getExplicitReceiverData(expression)
if (pair != null) {
val (receiverExpression, callType) = pair
if (explicitReceiverData != null) {
val (receiverExpression, callType) = explicitReceiverData
val qualifier = context[BindingContext.QUALIFIER, receiverExpression]
if (qualifier != null) {
@@ -247,9 +253,9 @@ public class ReferenceVariantsHelper(
public fun getReferenceVariantsReceivers(expression: JetSimpleNameExpression): ReceiversData {
val receiverData = getExplicitReceiverData(expression)
if (receiverData != null) {
val receiverExpression = receiverData.first
val receiverExpression = receiverData.expression
val expressionType = context.getType(receiverExpression) ?: return ReceiversData.Empty
return ReceiversData(listOf(ExpressionReceiver(receiverExpression, expressionType)), receiverData.second)
return ReceiversData(listOf(ExpressionReceiver(receiverExpression, expressionType)), receiverData.callType)
}
else {
val resolutionScope = context[BindingContext.RESOLUTION_SCOPE, expression] ?: return ReceiversData.Empty
@@ -275,7 +281,7 @@ public class ReferenceVariantsHelper(
}
companion object {
public fun getExplicitReceiverData(expression: JetSimpleNameExpression): Pair<JetExpression, CallType>? {
public fun getExplicitReceiverData(expression: JetSimpleNameExpression): ExplicitReceiverData? {
val receiverExpression = expression.getReceiverExpression() ?: return null
val parent = expression.getParent()
val callType = when (parent) {
@@ -299,7 +305,7 @@ public class ReferenceVariantsHelper(
else -> return null
}
return receiverExpression to callType
return ExplicitReceiverData(receiverExpression, callType)
}
}
}
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.idea.util
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
@@ -25,53 +26,54 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
import org.jetbrains.kotlin.resolve.calls.CallResolver
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall
import org.jetbrains.kotlin.resolve.scopes.ChainedScope
import org.jetbrains.kotlin.resolve.scopes.ExplicitImportsScope
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.util.descriptorsEqualWithSubstitution
import java.util.ArrayList
import java.util.HashSet
import java.util.*
public class ShadowedDeclarationsFilter(
private val bindingContext: BindingContext,
private val resolutionFacade: ResolutionFacade
private val resolutionFacade: ResolutionFacade,
private val context: JetExpression,
explicitReceiverData: ReferenceVariantsHelper.ExplicitReceiverData?
) {
private val psiFactory = JetPsiFactory(resolutionFacade.project)
private val dummyExpressionFactory = DummyExpressionFactory(psiFactory)
public fun <TDescriptor : DeclarationDescriptor> filter(declarations: Collection<TDescriptor>, expression: JetSimpleNameExpression): Collection<TDescriptor> {
val call = expression.getCall(bindingContext) ?: return declarations
private val explicitReceiverValue = explicitReceiverData?.let {
val type = bindingContext.getType(it.expression) ?: return@let null
ExpressionReceiver(it.expression, type)
} ?: ReceiverValue.NO_RECEIVER
public fun <TDescriptor : DeclarationDescriptor> filter(declarations: Collection<TDescriptor>): Collection<TDescriptor> {
return declarations
.groupBy { signature(it) }
.values()
.flatMap { group -> filterEqualSignatureGroup(group, call) }
.flatMap { group -> filterEqualSignatureGroup(group) }
}
public fun <TDescriptor : DeclarationDescriptor> filterNonImported(
declarations: Collection<TDescriptor>,
importedDeclarations: Collection<DeclarationDescriptor>,
expression: JetSimpleNameExpression
importedDeclarations: Collection<DeclarationDescriptor>
): Collection<TDescriptor> {
val importedDeclarationsSet = importedDeclarations.toSet()
val nonImportedDeclarations = declarations.filter { it !in importedDeclarationsSet }
val importedDeclarationsBySignature = importedDeclarationsSet.groupBy { signature(it) }
val call = expression.getCall(bindingContext) ?: return nonImportedDeclarations
val notShadowed = HashSet<DeclarationDescriptor>()
// same signature non-imported declarations from different packages do not shadow each other
for ((pair, group) in nonImportedDeclarations.groupBy { signature(it) to packageName(it) }) {
val imported = importedDeclarationsBySignature[pair.first]
val all = if (imported != null) group + imported else group
notShadowed.addAll(filterEqualSignatureGroup(all, call, descriptorsToImport = group))
notShadowed.addAll(filterEqualSignatureGroup(all, descriptorsToImport = group))
}
return declarations.filter { it in notShadowed }
}
@@ -88,7 +90,6 @@ public class ShadowedDeclarationsFilter(
private fun <TDescriptor : DeclarationDescriptor> filterEqualSignatureGroup(
descriptors: Collection<TDescriptor>,
call: Call,
descriptorsToImport: Collection<TDescriptor> = emptyList()
): Collection<TDescriptor> {
if (descriptors.size() == 1) return descriptors
@@ -135,7 +136,7 @@ public class ShadowedDeclarationsFilter(
arguments.add(DummyArgument(i))
}
val newCall = object : DelegatingCall(call) {
val newCall = object : Call {
//TODO: compiler crash (KT-8011)
//val arguments = parameters.indices.map { DummyArgument(it) }
val callee = psiFactory.createExpressionByPattern("$0", name)
@@ -151,17 +152,26 @@ public class ShadowedDeclarationsFilter(
override fun getTypeArguments() = emptyList<JetTypeProjection>()
override fun getTypeArgumentList() = null
override fun getDispatchReceiver() = ReceiverValue.NO_RECEIVER
override fun getCallOperationNode() = null
override fun getExplicitReceiver() = explicitReceiverValue
override fun getCallElement() = callee
override fun getCallType() = Call.CallType.DEFAULT
}
val calleeExpression = call.getCalleeExpression() ?: return descriptors
var resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, calleeExpression] ?: return descriptors
var resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, context] ?: return descriptors
if (descriptorsToImport.isNotEmpty()) {
resolutionScope = ChainedScope(resolutionScope.getContainingDeclaration(), "Scope with explicitly imported descriptors",
ExplicitImportsScope(descriptorsToImport), resolutionScope)
}
val dataFlowInfo = bindingContext.getDataFlowInfo(calleeExpression)
val dataFlowInfo = bindingContext.getDataFlowInfo(context)
val context = BasicCallResolutionContext.create(bindingTrace, resolutionScope, newCall, TypeUtils.NO_EXPECTED_TYPE, dataFlowInfo,
ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
CallChecker.DoNothing, false)
@@ -328,7 +328,8 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
}
private fun Collection<CallableDescriptor>.filterShadowedNonImported(): Collection<CallableDescriptor> {
return ShadowedDeclarationsFilter(bindingContext, resolutionFacade).filterNonImported(this, referenceVariants, nameExpression!!)
val explicitReceiverData = ReferenceVariantsHelper.getExplicitReceiverData(nameExpression!!)
return ShadowedDeclarationsFilter(bindingContext, resolutionFacade, nameExpression, explicitReceiverData).filterNonImported(this, referenceVariants)
}
protected fun addAllClasses(kindFilter: (ClassKind) -> Boolean) {
@@ -90,9 +90,9 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
// special completion for outside parenthesis lambda argument
private fun addFunctionLiteralArgumentCompletions() {
if (nameExpression != null) {
val receiverData = ReferenceVariantsHelper.getExplicitReceiverData(nameExpression)
if (receiverData != null && receiverData.second == CallType.INFIX) {
val call = receiverData.first.getCall(bindingContext)
val (receiverExpression, callType) = ReferenceVariantsHelper.getExplicitReceiverData(nameExpression) ?: return
if (callType == CallType.INFIX) {
val call = receiverExpression.getCall(bindingContext)
if (call != null && call.getFunctionLiteralArguments().isEmpty()) {
val dummyArgument = object : FunctionLiteralArgument {
override fun getFunctionLiteral() = throw UnsupportedOperationException()
@@ -45,8 +45,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
import java.util.HashSet
import java.util.LinkedHashSet
import java.util.*
public class KotlinIndicesHelper(
private val resolutionFacade: ResolutionFacade,
@@ -133,9 +132,9 @@ public class KotlinIndicesHelper(
}
private fun receiverValues(expression: JetSimpleNameExpression, bindingContext: BindingContext): Collection<Pair<ReceiverValue, CallType>> {
val receiverPair = ReferenceVariantsHelper.getExplicitReceiverData(expression)
if (receiverPair != null) {
val (receiverExpression, callType) = receiverPair
val receiverData = ReferenceVariantsHelper.getExplicitReceiverData(expression)
if (receiverData != null) {
val (receiverExpression, callType) = receiverData
val expressionType = bindingContext.getType(receiverExpression)
if (expressionType == null || expressionType.isError()) return emptyList()
@@ -413,8 +413,10 @@ public class JetFunctionParameterInfoHandler implements ParameterInfoHandlerWith
}
};
Collection<DeclarationDescriptor> variants = new ReferenceVariantsHelper(bindingContext, resolutionFacade, visibilityFilter).getReferenceVariants(
callNameExpression, new DescriptorKindFilter(DescriptorKindFilter.FUNCTIONS_MASK | DescriptorKindFilter.CLASSIFIERS_MASK,
Collections.<DescriptorKindExclude>emptyList()), nameFilter, false, false);
callNameExpression,
new DescriptorKindFilter(DescriptorKindFilter.FUNCTIONS_MASK | DescriptorKindFilter.CLASSIFIERS_MASK, Collections.<DescriptorKindExclude>emptyList()),
nameFilter
);
Collection<Pair<? extends DeclarationDescriptor, ResolutionFacade>> itemsToShow = new ArrayList<Pair<? extends DeclarationDescriptor, ResolutionFacade>>();
for (DeclarationDescriptor variant : variants) {