Refactored ReferenceVariantsHelper to not require KtSimpleNameExpression

This commit is contained in:
Valentin Kipyatkov
2015-10-26 18:04:57 +03:00
parent dc791941d7
commit 59fa639ab4
5 changed files with 51 additions and 34 deletions
@@ -16,11 +16,13 @@
package org.jetbrains.kotlin.resolve.bindingContextUtil
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContext.*
import org.jetbrains.kotlin.resolve.BindingTrace
@@ -75,8 +77,12 @@ public fun BindingTrace.recordScope(scope: LexicalScope, element: KtElement?) {
}
}
public fun BindingContext.getDataFlowInfo(expression: KtExpression?): DataFlowInfo =
expression?.let { this[BindingContext.EXPRESSION_TYPE_INFO, it]?.dataFlowInfo } ?: DataFlowInfo.EMPTY
public fun BindingContext.getDataFlowInfo(position: PsiElement): DataFlowInfo {
for (element in position.parentsWithSelf) {
(element as? KtExpression)?.let { this[BindingContext.EXPRESSION_TYPE_INFO, it] }?.let { return it.dataFlowInfo }
}
return DataFlowInfo.EMPTY
}
public fun KtExpression.isUnreachableCode(context: BindingContext): Boolean = context[BindingContext.UNREACHABLE_CODE, this]!!
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.idea.codeInsight
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
@@ -47,25 +48,34 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.*
public class ReferenceVariantsHelper(
private val context: BindingContext,
class ReferenceVariantsHelper(
private val bindingContext: BindingContext,
private val resolutionFacade: ResolutionFacade,
private val visibilityFilter: (DeclarationDescriptor) -> Boolean
) {
@JvmOverloads
public fun getReferenceVariants(
fun getReferenceVariants(
expression: KtSimpleNameExpression,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
callTypeAndReceiver: CallTypeAndReceiver<*, *> = CallTypeAndReceiver.detect(expression),
filterOutJavaGettersAndSetters: Boolean = false,
useRuntimeReceiverType: Boolean = false
): Collection<DeclarationDescriptor>
= getReferenceVariants(expression, CallTypeAndReceiver.detect(expression),
kindFilter, nameFilter, filterOutJavaGettersAndSetters, useRuntimeReceiverType)
fun getReferenceVariants(
contextElement: PsiElement,
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
filterOutJavaGettersAndSetters: Boolean = false,
useRuntimeReceiverType: Boolean = false
): Collection<DeclarationDescriptor> {
var variants: Collection<DeclarationDescriptor>
= getReferenceVariantsNoVisibilityFilter(expression, kindFilter, nameFilter, callTypeAndReceiver, useRuntimeReceiverType)
= getReferenceVariantsNoVisibilityFilter(contextElement, kindFilter, nameFilter, callTypeAndReceiver, useRuntimeReceiverType)
.filter { !it.isAnnotatedAsHidden() && visibilityFilter(it) }
ShadowedDeclarationsFilter.create(context, resolutionFacade, expression, callTypeAndReceiver)?.let {
ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, contextElement, callTypeAndReceiver)?.let {
variants = it.filter(variants)
}
@@ -79,14 +89,14 @@ public class ReferenceVariantsHelper(
}
}
variants = variants.filter { it.original !in accessorMethodsToRemove }
variants = variants.filter { it !is FunctionDescriptor || it.original !in accessorMethodsToRemove }
}
return variants
}
private fun getReferenceVariantsNoVisibilityFilter(
expression: KtSimpleNameExpression,
contextElement: PsiElement,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
@@ -108,15 +118,15 @@ public class ReferenceVariantsHelper(
}
is CallTypeAndReceiver.TYPE -> {
return getVariantsForUserType(callTypeAndReceiver.receiver, expression, kindFilter, nameFilter)
return getVariantsForUserType(callTypeAndReceiver.receiver, contextElement, kindFilter, nameFilter)
}
is CallTypeAndReceiver.ANNOTATION -> {
return getVariantsForUserType(callTypeAndReceiver.receiver, expression, kindFilter, nameFilter)
return getVariantsForUserType(callTypeAndReceiver.receiver, contextElement, kindFilter, nameFilter)
}
is CallTypeAndReceiver.CALLABLE_REFERENCE -> {
val resolutionScope = expression.getResolutionScope(context, resolutionFacade)
val resolutionScope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
return getVariantsForCallableReference(callTypeAndReceiver.receiver, resolutionScope, kindFilter, nameFilter)
}
@@ -129,19 +139,19 @@ public class ReferenceVariantsHelper(
else -> throw RuntimeException() //TODO: see KT-9394
}
val resolutionScope = expression.getResolutionScope(context, resolutionFacade)
val dataFlowInfo = context.getDataFlowInfo(expression)
val resolutionScope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
val dataFlowInfo = bindingContext.getDataFlowInfo(contextElement)
val containingDeclaration = resolutionScope.ownerDescriptor
val smartCastManager = resolutionFacade.frontendService<SmartCastManager>()
val implicitReceiverTypes = resolutionScope.getImplicitReceiversWithInstance().flatMap {
smartCastManager.getSmartCastVariantsWithLessSpecificExcluded(it.value, context, containingDeclaration, dataFlowInfo)
smartCastManager.getSmartCastVariantsWithLessSpecificExcluded(it.value, bindingContext, containingDeclaration, dataFlowInfo)
}.toSet()
val descriptors = LinkedHashSet<DeclarationDescriptor>()
if (receiverExpression != null) {
val qualifier = context[BindingContext.QUALIFIER, receiverExpression]
val qualifier = bindingContext[BindingContext.QUALIFIER, receiverExpression]
if (qualifier != null) {
descriptors.addAll(qualifier.scope.getDescriptorsFiltered(kindFilter exclude DescriptorKindExclude.Extensions, nameFilter))
}
@@ -149,11 +159,11 @@ public class ReferenceVariantsHelper(
val expressionType = if (useRuntimeReceiverType)
getQualifierRuntimeType(receiverExpression)
else
context.getType(receiverExpression)
bindingContext.getType(receiverExpression)
if (expressionType != null && !expressionType.isError()) {
val receiverValue = ExpressionReceiver(receiverExpression, expressionType)
val explicitReceiverTypes = smartCastManager
.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, context, containingDeclaration, dataFlowInfo)
.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, bindingContext, containingDeclaration, dataFlowInfo)
descriptors.processAll(implicitReceiverTypes, explicitReceiverTypes, resolutionScope, callType, kindFilter, nameFilter)
}
@@ -170,16 +180,16 @@ public class ReferenceVariantsHelper(
private fun getVariantsForUserType(
receiverExpression: KtExpression?,
expression: KtSimpleNameExpression,
contextElement: PsiElement,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> {
if (receiverExpression != null) {
val qualifier = context[BindingContext.QUALIFIER, receiverExpression] ?: return emptyList()
val qualifier = bindingContext[BindingContext.QUALIFIER, receiverExpression] ?: return emptyList()
return qualifier.scope.getDescriptorsFiltered(kindFilter, nameFilter)
}
else {
val scope = expression.getResolutionScope(context, resolutionFacade)
val scope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
return scope.collectDescriptorsFiltered(kindFilter, nameFilter)
}
}
@@ -192,7 +202,7 @@ public class ReferenceVariantsHelper(
): Collection<DeclarationDescriptor> {
val descriptors = LinkedHashSet<DeclarationDescriptor>()
if (qualifierTypeRef != null) {
val type = context[BindingContext.TYPE, qualifierTypeRef] ?: return emptyList()
val type = bindingContext[BindingContext.TYPE, qualifierTypeRef] ?: return emptyList()
descriptors.addNonExtensionMembers(listOf(type), kindFilter, nameFilter, constructorFilter = { true })
@@ -211,7 +221,7 @@ public class ReferenceVariantsHelper(
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> {
if (receiverExpression != null) {
val qualifier = context[BindingContext.QUALIFIER, receiverExpression] ?: return emptyList()
val qualifier = bindingContext[BindingContext.QUALIFIER, receiverExpression] ?: return emptyList()
return qualifier.scope.getDescriptorsFiltered(kindFilter, nameFilter)
}
else {
@@ -285,7 +295,7 @@ public class ReferenceVariantsHelper(
}
private fun MutableSet<DeclarationDescriptor>.addScopeAndSyntheticExtensions(
resolutionScope: LexicalScope,
scope: LexicalScope,
receiverTypes: Collection<KotlinType>,
callType: CallType<*>,
kindFilter: DescriptorKindFilter,
@@ -299,26 +309,26 @@ public class ReferenceVariantsHelper(
}
}
for (descriptor in resolutionScope.collectDescriptorsFiltered(kindFilter exclude DescriptorKindExclude.NonExtensions, nameFilter)) {
for (descriptor in scope.collectDescriptorsFiltered(kindFilter exclude DescriptorKindExclude.NonExtensions, nameFilter)) {
// todo: sometimes resolution scope here is LazyJavaClassMemberScope. see ea.jetbrains.com/browser/ea_problems/72572
process(descriptor as CallableDescriptor)
}
if (kindFilter.acceptsKinds(DescriptorKindFilter.VARIABLES_MASK)) {
for (extension in resolutionScope.collectSyntheticExtensionProperties(receiverTypes)) {
for (extension in scope.collectSyntheticExtensionProperties(receiverTypes)) {
process(extension)
}
}
if (kindFilter.acceptsKinds(DescriptorKindFilter.FUNCTIONS_MASK)) {
for (extension in resolutionScope.collectSyntheticExtensionFunctions(receiverTypes)) {
for (extension in scope.collectSyntheticExtensionFunctions(receiverTypes)) {
process(extension)
}
}
}
private fun getQualifierRuntimeType(receiver: KtExpression): KotlinType? {
val type = context.getType(receiver)
val type = bindingContext.getType(receiver)
if (type != null && TypeUtils.canHaveSubtypes(KotlinTypeChecker.DEFAULT, type)) {
val evaluator = receiver.getContainingFile().getCopyableUserData(KtCodeFragment.RUNTIME_TYPE_EVALUATOR)
val runtimeType = evaluator?.invoke(receiver)
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.util
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
@@ -40,14 +41,14 @@ import java.util.*
public class ShadowedDeclarationsFilter private constructor(
private val bindingContext: BindingContext,
private val resolutionFacade: ResolutionFacade,
private val context: KtExpression,
private val context: PsiElement,
private val explicitReceiverValue: ReceiverValue
) {
companion object {
fun create(
bindingContext: BindingContext,
resolutionFacade: ResolutionFacade,
context: KtExpression,
context: PsiElement,
callTypeAndReceiver: CallTypeAndReceiver<*, *>
): ShadowedDeclarationsFilter? {
val receiverExpression = when (callTypeAndReceiver) {
@@ -316,7 +316,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
private fun createLookupElementFactory(callType: CallType<*>?, receiverTypes: Collection<KotlinType>?): LookupElementFactory {
val contextVariablesProvider = {
nameExpression?.let {
referenceVariantsHelper.getReferenceVariants(it, DescriptorKindFilter.VARIABLES, { true }, CallTypeAndReceiver.DEFAULT)
referenceVariantsHelper.getReferenceVariants(it, CallTypeAndReceiver.DEFAULT, DescriptorKindFilter.VARIABLES, nameFilter = { true })
.map { it as VariableDescriptor }
} ?: emptyList()
}
@@ -112,7 +112,7 @@ public fun Call.resolveCandidates(
val resolutionScope = callElement.getResolutionScope(bindingContext, resolutionFacade)
val inDescriptor = resolutionScope.ownerDescriptor
val dataFlowInfo = bindingContext.getDataFlowInfo(calleeExpression)
val dataFlowInfo = bindingContext.getDataFlowInfo(callElement)
val bindingTrace = DelegatingBindingTrace(bindingContext, "Temporary trace")
val callResolutionContext = BasicCallResolutionContext.create(
bindingTrace, resolutionScope, this, expectedType, dataFlowInfo,