Refactoring to add CallType.IMPORT_DIRECTIVE and CallType.PACKAGE_DIRECTIVE

This commit is contained in:
Valentin Kipyatkov
2015-09-30 13:55:12 +03:00
parent d38ceb50b6
commit 56bb8adfd0
7 changed files with 102 additions and 93 deletions
@@ -51,30 +51,78 @@ import org.jetbrains.kotlin.types.checker.JetTypeChecker
import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.*
public data class CallTypeAndReceiver(
val callType: CallType,
val receiver: JetElement?
) {
companion object {
public fun detect(expression: JetSimpleNameExpression): CallTypeAndReceiver {
val parent = expression.parent
if (parent is JetCallableReferenceExpression) {
return CallTypeAndReceiver(CallType.CALLABLE_REFERENCE, parent.typeReference)
}
val receiverExpression = expression.getReceiverExpression()
if (expression.isImportDirectiveExpression()) {
return CallTypeAndReceiver(CallType.IMPORT_DIRECTIVE, receiverExpression)
}
if (expression.isPackageDirectiveExpression()) {
return CallTypeAndReceiver(CallType.PACKAGE_DIRECTIVE, receiverExpression)
}
if (receiverExpression == null) {
return CallTypeAndReceiver(CallType.NORMAL, null)
}
val callType = when (parent) {
is JetBinaryExpression -> CallType.INFIX
is JetCallExpression -> {
if ((parent.getParent() as JetQualifiedExpression).getOperationSign() == JetTokens.SAFE_ACCESS)
CallType.SAFE
else
CallType.NORMAL
}
is JetQualifiedExpression -> {
if (parent.getOperationSign() == JetTokens.SAFE_ACCESS)
CallType.SAFE
else
CallType.NORMAL
}
is JetUnaryExpression -> CallType.UNARY
is JetUserType -> CallType.NORMAL
else -> error("Unknown parent for expression with receiver: $parent")
}
return CallTypeAndReceiver(callType, receiverExpression)
}
}
}
public class ReferenceVariantsHelper(
private val context: BindingContext,
private val resolutionFacade: ResolutionFacade,
private val visibilityFilter: (DeclarationDescriptor) -> Boolean
) {
public data class ExplicitReceiverData(
val element: JetElement?,
val callType: CallType
)
@JvmOverloads
public fun getReferenceVariants(
expression: JetSimpleNameExpression,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
explicitReceiverData: ExplicitReceiverData? = getExplicitReceiverData(expression),
callTypeAndReceiver: CallTypeAndReceiver = CallTypeAndReceiver.detect(expression),
filterOutJavaGettersAndSetters: Boolean = false,
useRuntimeReceiverType: Boolean = false
): Collection<DeclarationDescriptor> {
var variants: Collection<DeclarationDescriptor>
= getReferenceVariantsNoVisibilityFilter(expression, kindFilter, nameFilter, explicitReceiverData, useRuntimeReceiverType)
= getReferenceVariantsNoVisibilityFilter(expression, kindFilter, nameFilter, callTypeAndReceiver, useRuntimeReceiverType)
.filter { !it.isAnnotatedAsHidden() && visibilityFilter(it) }
variants = ShadowedDeclarationsFilter(context, resolutionFacade, expression, explicitReceiverData).filter(variants)
variants = ShadowedDeclarationsFilter(context, resolutionFacade, expression, callTypeAndReceiver).filter(variants)
if (filterOutJavaGettersAndSetters) {
val accessorMethodsToRemove = HashSet<FunctionDescriptor>()
@@ -95,20 +143,22 @@ public class ReferenceVariantsHelper(
expression: JetSimpleNameExpression,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
explicitReceiverData: ExplicitReceiverData?,
callTypeAndReceiver: CallTypeAndReceiver,
useRuntimeReceiverType: Boolean
): Collection<DeclarationDescriptor> {
if (expression.isImportDirectiveExpression()) {
return getVariantsForImportOrPackageDirective(explicitReceiverData, kindFilter, nameFilter)
val (callType, receiverElement) = callTypeAndReceiver
if (callType == CallType.IMPORT_DIRECTIVE) {
return getVariantsForImportOrPackageDirective(receiverElement as JetExpression?, kindFilter, nameFilter)
}
if (expression.isPackageDirectiveExpression()) {
if (callType == CallType.PACKAGE_DIRECTIVE) {
val packageKindFilter = kindFilter restrictedToKinds DescriptorKindFilter.PACKAGES_MASK
return getVariantsForImportOrPackageDirective(explicitReceiverData, packageKindFilter, nameFilter)
return getVariantsForImportOrPackageDirective(receiverElement as JetExpression?, packageKindFilter, nameFilter)
}
if (expression.parent is JetUserType) {
return getVariantsForUserType(explicitReceiverData, expression, kindFilter, nameFilter)
if (expression.parent is JetUserType) { //TODO: special CallType?
return getVariantsForUserType(receiverElement as JetExpression?, expression, kindFilter, nameFilter)
}
val resolutionScope = resolutionScope(expression) ?: return emptyList()
@@ -120,15 +170,13 @@ public class ReferenceVariantsHelper(
smartCastManager.getSmartCastVariantsWithLessSpecificExcluded(it.value, context, containingDeclaration, dataFlowInfo)
}.toSet()
if (callType == CallType.CALLABLE_REFERENCE) {
return getVariantsForCallableReference(receiverElement as JetTypeReference?, resolutionScope, implicitReceiverTypes, kindFilter, nameFilter)
}
val descriptors = LinkedHashSet<DeclarationDescriptor>()
if (explicitReceiverData != null) {
val (receiverElement, callType) = explicitReceiverData
if (callType == CallType.CALLABLE_REFERENCE) {
return getVariantsForCallableReference(receiverElement as JetTypeReference?, resolutionScope, implicitReceiverTypes, kindFilter, nameFilter)
}
if (receiverElement != null) {
receiverElement as JetExpression
val qualifier = context[BindingContext.QUALIFIER, receiverElement]
@@ -160,14 +208,13 @@ public class ReferenceVariantsHelper(
}
private fun getVariantsForUserType(
explicitReceiverData: ExplicitReceiverData?,
receiverExpression: JetExpression?,
expression: JetSimpleNameExpression,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> {
val accurateKindFilter = kindFilter.restrictedToKinds(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK)
if (explicitReceiverData != null) {
val receiverExpression = explicitReceiverData.element as? JetExpression ?: return emptyList()
if (receiverExpression != null) {
val qualifier = context[BindingContext.QUALIFIER, receiverExpression] ?: return emptyList()
return qualifier.scope.getDescriptorsFiltered(accurateKindFilter, nameFilter)
}
@@ -208,12 +255,11 @@ public class ReferenceVariantsHelper(
}
private fun getVariantsForImportOrPackageDirective(
explicitReceiverData: ExplicitReceiverData?,
receiverExpression: JetExpression?,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> {
if (explicitReceiverData != null) {
val receiverExpression = explicitReceiverData.element as? JetExpression ?: return emptyList()
if (receiverExpression != null) {
val qualifier = context[BindingContext.QUALIFIER, receiverExpression] ?: return emptyList()
return qualifier.scope.getDescriptorsFiltered(kindFilter, nameFilter)
}
@@ -351,39 +397,4 @@ public class ReferenceVariantsHelper(
val parent = expression.parent
return context.getDataFlowInfo(if (parent is JetCallableReferenceExpression) parent else expression)
}
companion object {
public fun getExplicitReceiverData(expression: JetSimpleNameExpression): ExplicitReceiverData? {
val parent = expression.parent
if (parent is JetCallableReferenceExpression) {
return ExplicitReceiverData(parent.typeReference, CallType.CALLABLE_REFERENCE)
}
val receiverExpression = expression.getReceiverExpression() ?: return null
val callType = when (parent) {
is JetBinaryExpression -> CallType.INFIX
is JetCallExpression -> {
if ((parent.getParent() as JetQualifiedExpression).getOperationSign() == JetTokens.SAFE_ACCESS)
CallType.SAFE
else
CallType.NORMAL
}
is JetQualifiedExpression -> {
if (parent.getOperationSign() == JetTokens.SAFE_ACCESS)
CallType.SAFE
else
CallType.NORMAL
}
is JetUnaryExpression -> CallType.UNARY
is JetUserType -> CallType.NORMAL
else -> return null
}
return ExplicitReceiverData(receiverExpression, callType)
}
}
}
@@ -17,7 +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.codeInsight.CallTypeAndReceiver
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
@@ -41,15 +41,14 @@ public class ShadowedDeclarationsFilter(
private val bindingContext: BindingContext,
private val resolutionFacade: ResolutionFacade,
private val context: JetExpression,
explicitReceiverData: ReferenceVariantsHelper.ExplicitReceiverData?
callTypeAndReceiver: CallTypeAndReceiver
) {
private val psiFactory = JetPsiFactory(resolutionFacade.project)
private val dummyExpressionFactory = DummyExpressionFactory(psiFactory)
private val explicitReceiverValue = explicitReceiverData?.let {
val expression = it.element as? JetExpression ?: return@let null
val type = bindingContext.getType(expression) ?: return@let null
ExpressionReceiver(expression, type)
private val explicitReceiverValue = (callTypeAndReceiver.receiver as? JetExpression)?.let {
val type = bindingContext.getType(it) ?: return@let null
ExpressionReceiver(it, type)
} ?: ReceiverValue.NO_RECEIVER
public fun <TDescriptor : DeclarationDescriptor> filter(declarations: Collection<TDescriptor>): Collection<TDescriptor> {
@@ -51,7 +51,12 @@ public enum class CallType {
// currently callable references to locals and parameters are not supported
override fun canCall(descriptor: DeclarationDescriptor)
= descriptor is FunctionDescriptor || descriptor is PropertyDescriptor
}
},
//TODO: canCall
IMPORT_DIRECTIVE,
PACKAGE_DIRECTIVE
;
@@ -29,6 +29,7 @@ import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.getResolveScope
import org.jetbrains.kotlin.idea.codeInsight.CallTypeAndReceiver
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper
import org.jetbrains.kotlin.idea.core.*
@@ -284,8 +285,9 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
}
private fun Collection<CallableDescriptor>.filterShadowedNonImported(): Collection<CallableDescriptor> {
val explicitReceiverData = ReferenceVariantsHelper.getExplicitReceiverData(nameExpression!!)
return ShadowedDeclarationsFilter(bindingContext, resolutionFacade, nameExpression, explicitReceiverData).filterNonImported(this, referenceVariants)
val callTypeAndReceiver = CallTypeAndReceiver.detect(nameExpression!!)
return ShadowedDeclarationsFilter(bindingContext, resolutionFacade, nameExpression, callTypeAndReceiver)
.filterNonImported(this, referenceVariants)
}
protected fun addAllClasses(kindFilter: (ClassKind) -> Boolean) {
@@ -301,7 +303,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
val contextVariablesProvider = {
nameExpression?.let {
referenceVariantsHelper.getReferenceVariants(it, DescriptorKindFilter.VARIABLES, { true }, explicitReceiverData = null)
referenceVariantsHelper.getReferenceVariants(it, DescriptorKindFilter.VARIABLES, { true }, CallTypeAndReceiver(CallType.NORMAL, null))
.map { it as VariableDescriptor }
} ?: emptyList()
}
@@ -317,11 +319,9 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
return CallType.NORMAL to emptyList()
}
val explicitReceiverData = ReferenceVariantsHelper.getExplicitReceiverData(nameExpression)
val receiverElement = explicitReceiverData?.element
val callType = explicitReceiverData?.callType ?: CallType.NORMAL
val (callType, receiverElement) = CallTypeAndReceiver.detect(nameExpression)
if (explicitReceiverData != null && callType == CallType.CALLABLE_REFERENCE && receiverElement != null) {
if (callType == CallType.CALLABLE_REFERENCE && receiverElement != null) {
val type = bindingContext[BindingContext.TYPE, receiverElement as JetTypeReference]
return callType to type.singletonOrEmptyList()
}
@@ -28,10 +28,8 @@ import com.intellij.psi.codeStyle.CodeStyleSettingsManager
import org.jetbrains.kotlin.idea.core.formatter.JetCodeStyleSettings
import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.JetImportDirective
import org.jetbrains.kotlin.psi.JetTypeArgumentList
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.types.JetType
class GenerateLambdaInfo(val lambdaType: JetType, val explicitParameters: Boolean)
@@ -60,11 +58,10 @@ class KotlinFunctionInsertHandler(
val startOffset = context.getStartOffset()
val element = context.getFile().findElementAt(startOffset) ?: return
when {
//TODO: replace with CallType
element.getStrictParentOfType<JetImportDirective>() != null || callType == CallType.CALLABLE_REFERENCE -> return
when (callType) {
CallType.PACKAGE_DIRECTIVE, CallType.IMPORT_DIRECTIVE, CallType.CALLABLE_REFERENCE -> return
callType == CallType.INFIX -> {
CallType.INFIX -> {
if (context.getCompletionChar() == ' ') {
context.setAddCompletionChar(false)
}
@@ -21,7 +21,7 @@ import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.completion.CompletionSorter
import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper
import org.jetbrains.kotlin.idea.codeInsight.CallTypeAndReceiver
import org.jetbrains.kotlin.idea.completion.*
import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptorKindExclude
@@ -91,7 +91,7 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
// special completion for outside parenthesis lambda argument
private fun addFunctionLiteralArgumentCompletions() {
if (nameExpression != null) {
val (receiverElement, callType) = ReferenceVariantsHelper.getExplicitReceiverData(nameExpression) ?: return
val (callType, receiverElement) = CallTypeAndReceiver.detect(nameExpression)
if (callType == CallType.INFIX) {
val call = (receiverElement as JetExpression).getCall(bindingContext)
if (call != null && call.getFunctionLiteralArguments().isEmpty()) {
@@ -22,7 +22,7 @@ import com.intellij.psi.search.PsiShortNamesCache
import com.intellij.psi.stubs.StringStubIndexExtension
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper
import org.jetbrains.kotlin.idea.codeInsight.CallTypeAndReceiver
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
@@ -132,12 +132,9 @@ public class KotlinIndicesHelper(
}
private fun receiverValues(expression: JetSimpleNameExpression, bindingContext: BindingContext): Collection<Pair<ReceiverValue, CallType>> {
val receiverData = ReferenceVariantsHelper.getExplicitReceiverData(expression)
if (receiverData != null) {
val (receiverElement, callType) = receiverData
if (callType == CallType.CALLABLE_REFERENCE) return emptyList() //TODO?
receiverElement as JetExpression
val (callType, receiverElement) = CallTypeAndReceiver.detect(expression)
if (receiverElement != null) {
if (receiverElement !is JetExpression) return emptyList() //TODO?
val expressionType = bindingContext.getType(receiverElement)
if (expressionType == null || expressionType.isError()) return emptyList()
@@ -148,7 +145,7 @@ public class KotlinIndicesHelper(
}
else {
val resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, expression] ?: return emptyList()
return resolutionScope.getImplicitReceiversWithInstance().map { it.getValue() to CallType.NORMAL }
return resolutionScope.getImplicitReceiversWithInstance().map { it.getValue() to callType }
}
}