diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt index b3ed380b6e5..6e0e174f622 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt @@ -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 { var variants: Collection - = 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() @@ -95,20 +143,22 @@ public class ReferenceVariantsHelper( expression: JetSimpleNameExpression, kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean, - explicitReceiverData: ExplicitReceiverData?, + callTypeAndReceiver: CallTypeAndReceiver, useRuntimeReceiverType: Boolean ): Collection { - 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() - 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 { 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 { - 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) - } - } } diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/ShadowedDeclarationsFilter.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/ShadowedDeclarationsFilter.kt index 13ad435de60..86c24ea1c12 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/ShadowedDeclarationsFilter.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/ShadowedDeclarationsFilter.kt @@ -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 filter(declarations: Collection): Collection { diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/extensionsUtils.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/extensionsUtils.kt index 288312782ca..2c056c9b8be 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/extensionsUtils.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/extensionsUtils.kt @@ -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 ; diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt index 0a503d777ad..86bf989f69d 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt @@ -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.filterShadowedNonImported(): Collection { - 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() } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinFunctionInsertHandler.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinFunctionInsertHandler.kt index e4e18ce0bdf..88d44c2cd63 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinFunctionInsertHandler.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinFunctionInsertHandler.kt @@ -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() != 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) } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt index 29b3c53b1a9..d4add2a69ca 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt @@ -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()) { diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt index 798b9049c35..9dbf8f701a1 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt @@ -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> { - 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 } } }