Refactored ReferenceVariantsHelper to allow specifying receiver
This commit is contained in:
+19
-13
@@ -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) {
|
||||
|
||||
+3
-3
@@ -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()
|
||||
|
||||
+4
-2
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user