From e41732e572dfac8d35cd115d3d791b592b98e86c Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 30 Sep 2015 17:23:18 +0300 Subject: [PATCH] No callable references to synthetic extensions (and ones for get/set) --- .../kotlin/resolve/scopes/JetScope.kt | 2 + .../codeInsight/ReferenceVariantsHelper.kt | 42 ++++++------- .../jetbrains/kotlin/idea/util/CallType.kt | 61 ++++++++++++------- .../kotlin/idea/util/extensionsUtils.kt | 2 +- .../callableReference/SyntheticExtensions.kt | 7 ++- .../callableReference/SyntheticExtensions2.kt | 7 ++- 6 files changed, 68 insertions(+), 53 deletions(-) diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt index 355708e191a66..92a30b0922f12 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt @@ -143,6 +143,8 @@ public class DescriptorKindFilter( return DescriptorKindFilter(mask, excludes) } + public fun intersect(other: DescriptorKindFilter) = DescriptorKindFilter(kindMask and other.kindMask, excludes + other.excludes) + override fun toString(): String { val predefinedFilterName = DEBUG_PREDEFINED_FILTERS_MASK_NAMES.firstOrNull { it.mask == kindMask } ?.name val kindString = predefinedFilterName ?: DEBUG_MASK_BIT_NAMES 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 271e2b71b5758..81ccad67067f5 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 @@ -86,6 +86,11 @@ public class ReferenceVariantsHelper( callTypeAndReceiver: CallTypeAndReceiver<*, *>, useRuntimeReceiverType: Boolean ): Collection { + val callType = callTypeAndReceiver.callType + + @Suppress("NAME_SHADOWING") + val kindFilter = kindFilter.intersect(callType.descriptorKindFilter) + val receiverExpression: JetExpression? when (callTypeAndReceiver) { is CallTypeAndReceiver.IMPORT_DIRECTIVE -> { @@ -93,8 +98,7 @@ public class ReferenceVariantsHelper( } is CallTypeAndReceiver.PACKAGE_DIRECTIVE -> { - val packageKindFilter = kindFilter restrictedToKinds DescriptorKindFilter.PACKAGES_MASK - return getVariantsForImportOrPackageDirective(callTypeAndReceiver.receiver, packageKindFilter, nameFilter) + return getVariantsForImportOrPackageDirective(callTypeAndReceiver.receiver, kindFilter, nameFilter) } is CallTypeAndReceiver.TYPE -> { @@ -124,15 +128,12 @@ public class ReferenceVariantsHelper( return getVariantsForCallableReference(callTypeAndReceiver.receiver, resolutionScope, implicitReceiverTypes, kindFilter, nameFilter) } - val callType = callTypeAndReceiver.callType - val descriptors = LinkedHashSet() if (receiverExpression != null) { val qualifier = context[BindingContext.QUALIFIER, receiverExpression] if (qualifier != null) { - // It's impossible to add extension function for package or class (if it's companion object, expression type is not null) - qualifier.scope.getDescriptorsFiltered(kindFilter exclude DescriptorKindExclude.Extensions, nameFilter).filterTo(descriptors) { callType.canCall(it) } + descriptors.addAll(qualifier.scope.getDescriptorsFiltered(kindFilter exclude DescriptorKindExclude.Extensions, nameFilter)) } val expressionType = if (useRuntimeReceiverType) @@ -163,16 +164,15 @@ public class ReferenceVariantsHelper( kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean ): Collection { - val accurateKindFilter = kindFilter.restrictedToKinds(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK) if (receiverExpression != null) { val qualifier = context[BindingContext.QUALIFIER, receiverExpression] ?: return emptyList() - return qualifier.scope.getDescriptorsFiltered(accurateKindFilter, nameFilter) + return qualifier.scope.getDescriptorsFiltered(kindFilter, nameFilter) } else { val lexicalScope = expression.getParentOfType(strict = true)?.let { context[BindingContext.LEXICAL_SCOPE, it] } ?: return emptyList() - return lexicalScope.getDescriptorsFiltered(accurateKindFilter, nameFilter) + return lexicalScope.getDescriptorsFiltered(kindFilter, nameFilter) } } @@ -183,23 +183,21 @@ public class ReferenceVariantsHelper( kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean ): Collection { - val accurateKindFilter = kindFilter.restrictedToKinds(DescriptorKindFilter.CALLABLES.kindMask) val descriptors = LinkedHashSet() if (qualifierTypeRef != null) { val type = context[BindingContext.TYPE, qualifierTypeRef] ?: return emptyList() - descriptors.addNonExtensionMembers(listOf(type), CallType.CALLABLE_REFERENCE, accurateKindFilter, nameFilter, constructorsForInnerClassesOnly = false) + descriptors.addNonExtensionMembers(listOf(type), kindFilter, nameFilter, constructorsForInnerClassesOnly = false) - descriptors.addScopeAndSyntheticExtensions(resolutionScope, listOf(type), CallType.CALLABLE_REFERENCE, accurateKindFilter, nameFilter) + descriptors.addScopeAndSyntheticExtensions(resolutionScope, listOf(type), CallType.CALLABLE_REFERENCE, kindFilter, nameFilter) } else { // process non-instance members and class constructors - descriptors.addNonExtensionCallablesAndConstructors(resolutionScope, CallType.CALLABLE_REFERENCE, kindFilter, nameFilter, constructorsForInnerClassesOnly = false) + descriptors.addNonExtensionCallablesAndConstructors(resolutionScope, kindFilter, nameFilter, constructorsForInnerClassesOnly = false) - descriptors.addNonExtensionMembers(implicitReceiverTypes, CallType.CALLABLE_REFERENCE, accurateKindFilter, nameFilter, constructorsForInnerClassesOnly = true) + descriptors.addNonExtensionMembers(implicitReceiverTypes, kindFilter, nameFilter, constructorsForInnerClassesOnly = true) - //TODO: should we show synthetic extensions? get/set's? - descriptors.addScopeAndSyntheticExtensions(resolutionScope, implicitReceiverTypes, CallType.CALLABLE_REFERENCE, accurateKindFilter, nameFilter) + descriptors.addScopeAndSyntheticExtensions(resolutionScope, implicitReceiverTypes, CallType.CALLABLE_REFERENCE, kindFilter, nameFilter) } return descriptors } @@ -227,7 +225,7 @@ public class ReferenceVariantsHelper( kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean ) { - addNonExtensionMembers(receiverTypes, callType, kindFilter, nameFilter, constructorsForInnerClassesOnly = true) + addNonExtensionMembers(receiverTypes, kindFilter, nameFilter, constructorsForInnerClassesOnly = true) addMemberExtensions(implicitReceiverTypes, receiverTypes, callType, kindFilter, nameFilter) addScopeAndSyntheticExtensions(resolutionScope, receiverTypes, callType, kindFilter, nameFilter) } @@ -249,24 +247,22 @@ public class ReferenceVariantsHelper( private fun MutableSet.addNonExtensionMembers( receiverTypes: Collection, - callType: CallType<*>, kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean, constructorsForInnerClassesOnly: Boolean ) { for (receiverType in receiverTypes) { - addNonExtensionCallablesAndConstructors(receiverType.memberScope, callType, kindFilter, nameFilter, constructorsForInnerClassesOnly) + addNonExtensionCallablesAndConstructors(receiverType.memberScope, kindFilter, nameFilter, constructorsForInnerClassesOnly) } } private fun MutableSet.addNonExtensionCallablesAndConstructors( scope: JetScope, - callType: CallType<*>, kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean, constructorsForInnerClassesOnly: Boolean ) { - var filterToUse = kindFilter.restrictedToKinds(DescriptorKindFilter.CALLABLES.kindMask).exclude(DescriptorKindExclude.Extensions) + var filterToUse = DescriptorKindFilter(kindFilter.kindMask and DescriptorKindFilter.CALLABLES.kindMask).exclude(DescriptorKindExclude.Extensions) // should process classes if we need constructors if (filterToUse.acceptsKinds(DescriptorKindFilter.FUNCTIONS_MASK)) { @@ -277,9 +273,9 @@ public class ReferenceVariantsHelper( if (descriptor is ClassDescriptor) { if (constructorsForInnerClassesOnly && !descriptor.isInner) continue if (descriptor.modality == Modality.ABSTRACT || descriptor.modality == Modality.SEALED) continue - descriptor.constructors.filterTo(this) { callType.canCall(it) && kindFilter.accepts(it) } + descriptor.constructors.filterTo(this) { kindFilter.accepts(it) } } - else if (callType.canCall(descriptor) && kindFilter.accepts(descriptor)) { + else if (kindFilter.accepts(descriptor)) { this.add(descriptor) } } diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt index fabff27b8a38c..24a78194c0703 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt @@ -16,47 +16,62 @@ package org.jetbrains.kotlin.idea.util +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression import org.jetbrains.kotlin.psi.psiUtil.isImportDirectiveExpression import org.jetbrains.kotlin.psi.psiUtil.isPackageDirectiveExpression +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter -public sealed class CallType { - object DEFAULT : CallType() +public sealed class CallType(val descriptorKindFilter: DescriptorKindFilter) { + object DEFAULT : CallType(DescriptorKindFilter.ALL) - object DOT : CallType() + object DOT : CallType(DescriptorKindFilter.ALL) - object SAFE : CallType() + object SAFE : CallType(DescriptorKindFilter.ALL) - object INFIX : CallType() { - override fun canCall(descriptor: DeclarationDescriptor) - = descriptor is SimpleFunctionDescriptor && descriptor.getValueParameters().size() == 1 - } + object INFIX : CallType(DescriptorKindFilter.FUNCTIONS exclude NonInfixExclude) - object UNARY : CallType() { - override fun canCall(descriptor: DeclarationDescriptor) - = descriptor is SimpleFunctionDescriptor && descriptor.getValueParameters().size() == 0 - } + object UNARY : CallType(DescriptorKindFilter.FUNCTIONS exclude NonUnaryExclude) + + object CALLABLE_REFERENCE : CallType(DescriptorKindFilter.CALLABLES exclude LocalsAndSyntheticExclude/* currently not supported for locals and synthetic */) + + object IMPORT_DIRECTIVE : CallType(DescriptorKindFilter.ALL) + + object PACKAGE_DIRECTIVE : CallType(DescriptorKindFilter.PACKAGES) - object CALLABLE_REFERENCE : CallType() { - // currently callable references to locals and parameters are not supported - override fun canCall(descriptor: DeclarationDescriptor) - = descriptor is FunctionDescriptor || descriptor is PropertyDescriptor + object TYPE : CallType(DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK)) + + private object NonInfixExclude : DescriptorKindExclude { + //TODO: check 'infix' modifier + override fun excludes(descriptor: DeclarationDescriptor) = + !(descriptor is SimpleFunctionDescriptor && descriptor.valueParameters.size() == 1) + + override val fullyExcludedDescriptorKinds: Int + get() = 0 } - //TODO: canCall - object IMPORT_DIRECTIVE : CallType() + private object NonUnaryExclude : DescriptorKindExclude { + //TODO: check 'operator' modifier + override fun excludes(descriptor: DeclarationDescriptor) = + !(descriptor is SimpleFunctionDescriptor && descriptor.valueParameters.isEmpty()) - object PACKAGE_DIRECTIVE : CallType() + override val fullyExcludedDescriptorKinds: Int + get() = 0 + } - object TYPE : CallType() + private object LocalsAndSyntheticExclude : DescriptorKindExclude { + override fun excludes(descriptor: DeclarationDescriptor) + = descriptor !is CallableMemberDescriptor || descriptor.kind == CallableMemberDescriptor.Kind.SYNTHESIZED + + override val fullyExcludedDescriptorKinds: Int + get() = 0 + } - public open fun canCall(descriptor: DeclarationDescriptor): Boolean = true } public sealed class CallTypeAndReceiver>( 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 c44010001ae5d..d26c42b84814c 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 @@ -76,7 +76,7 @@ public fun CallableDescriptor.substituteExtensionIfCallable( receiverTypes: Collection, callType: CallType<*> ): Collection { - if (!callType.canCall(this)) return listOf() + if (!callType.descriptorKindFilter.accepts(this)) return listOf() var types = receiverTypes.asSequence() if (callType == CallType.SAFE) { diff --git a/idea/idea-completion/testData/basic/common/callableReference/SyntheticExtensions.kt b/idea/idea-completion/testData/basic/common/callableReference/SyntheticExtensions.kt index eb366abaf9fc6..3b0583d728081 100644 --- a/idea/idea-completion/testData/basic/common/callableReference/SyntheticExtensions.kt +++ b/idea/idea-completion/testData/basic/common/callableReference/SyntheticExtensions.kt @@ -2,6 +2,7 @@ import java.io.File val v = File:: -// EXIST_JAVA_ONLY: { itemText: "freeSpace", tailText: " (from getFreeSpace())", attributes: "bold" } -// EXIST_JAVA_ONLY: { itemText: "isFile", tailText: " (from isFile())", attributes: "bold" } -// ABSENT: { itemText: "isFile", tailText: "()" } +// EXIST_JAVA_ONLY: { itemText: "getFreeSpace", tailText: "()", attributes: "bold" } +// ABSENT: freeSpace +// EXIST_JAVA_ONLY: { itemText: "isFile", tailText: "()", attributes: "bold" } +// ABSENT: { itemText: "isFile", tailText: " (from isFile())" } diff --git a/idea/idea-completion/testData/basic/common/callableReference/SyntheticExtensions2.kt b/idea/idea-completion/testData/basic/common/callableReference/SyntheticExtensions2.kt index aa3c741bb5312..ec391f7ffd20a 100644 --- a/idea/idea-completion/testData/basic/common/callableReference/SyntheticExtensions2.kt +++ b/idea/idea-completion/testData/basic/common/callableReference/SyntheticExtensions2.kt @@ -4,6 +4,7 @@ class MyFile : File("") { val v = :: } -// EXIST_JAVA_ONLY: { itemText: "freeSpace", tailText: " (from getFreeSpace())", attributes: "" } -// EXIST_JAVA_ONLY: { itemText: "isFile", tailText: " (from isFile())", attributes: "" } -// ABSENT: { itemText: "isFile", tailText: "()" } +// EXIST_JAVA_ONLY: { itemText: "getFreeSpace", tailText: "()", attributes: "" } +// ABSENT: freeSpace +// EXIST_JAVA_ONLY: { itemText: "isFile", tailText: "()", attributes: "" } +// ABSENT: { itemText: "isFile", tailText: " (from isFile())" }