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