No callable references to synthetic extensions (and ones for get/set)

This commit is contained in:
Valentin Kipyatkov
2015-09-30 17:23:18 +03:00
parent 2471647952
commit e41732e572
6 changed files with 69 additions and 54 deletions
@@ -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
@@ -86,6 +86,11 @@ public class ReferenceVariantsHelper(
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
useRuntimeReceiverType: Boolean
): Collection<DeclarationDescriptor> {
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<DeclarationDescriptor>()
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<DeclarationDescriptor> {
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<JetTypeReference>(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<DeclarationDescriptor> {
val accurateKindFilter = kindFilter.restrictedToKinds(DescriptorKindFilter.CALLABLES.kindMask)
val descriptors = LinkedHashSet<DeclarationDescriptor>()
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<DeclarationDescriptor>.addNonExtensionMembers(
receiverTypes: Collection<JetType>,
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<DeclarationDescriptor>.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)
}
}
@@ -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<TReceiver : JetElement?> {
object DEFAULT : CallType<Nothing?>()
public sealed class CallType<TReceiver : JetElement?>(val descriptorKindFilter: DescriptorKindFilter) {
object DEFAULT : CallType<Nothing?>(DescriptorKindFilter.ALL)
object DOT : CallType<JetExpression>()
object DOT : CallType<JetExpression>(DescriptorKindFilter.ALL)
object SAFE : CallType<JetExpression>()
object SAFE : CallType<JetExpression>(DescriptorKindFilter.ALL)
object INFIX : CallType<JetExpression>() {
override fun canCall(descriptor: DeclarationDescriptor)
= descriptor is SimpleFunctionDescriptor && descriptor.getValueParameters().size() == 1
object INFIX : CallType<JetExpression>(DescriptorKindFilter.FUNCTIONS exclude NonInfixExclude)
object UNARY : CallType<JetExpression>(DescriptorKindFilter.FUNCTIONS exclude NonUnaryExclude)
object CALLABLE_REFERENCE : CallType<JetTypeReference?>(DescriptorKindFilter.CALLABLES exclude LocalsAndSyntheticExclude/* currently not supported for locals and synthetic */)
object IMPORT_DIRECTIVE : CallType<JetExpression?>(DescriptorKindFilter.ALL)
object PACKAGE_DIRECTIVE : CallType<JetExpression?>(DescriptorKindFilter.PACKAGES)
object TYPE : CallType<JetExpression?>(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
}
object UNARY : CallType<JetExpression>() {
override fun canCall(descriptor: DeclarationDescriptor)
= descriptor is SimpleFunctionDescriptor && descriptor.getValueParameters().size() == 0
private object NonUnaryExclude : DescriptorKindExclude {
//TODO: check 'operator' modifier
override fun excludes(descriptor: DeclarationDescriptor) =
!(descriptor is SimpleFunctionDescriptor && descriptor.valueParameters.isEmpty())
override val fullyExcludedDescriptorKinds: Int
get() = 0
}
object CALLABLE_REFERENCE : CallType<JetTypeReference?>() {
// currently callable references to locals and parameters are not supported
override fun canCall(descriptor: DeclarationDescriptor)
= descriptor is FunctionDescriptor || descriptor is PropertyDescriptor
private object LocalsAndSyntheticExclude : DescriptorKindExclude {
override fun excludes(descriptor: DeclarationDescriptor)
= descriptor !is CallableMemberDescriptor || descriptor.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
override val fullyExcludedDescriptorKinds: Int
get() = 0
}
//TODO: canCall
object IMPORT_DIRECTIVE : CallType<JetExpression?>()
object PACKAGE_DIRECTIVE : CallType<JetExpression?>()
object TYPE : CallType<JetExpression?>()
public open fun canCall(descriptor: DeclarationDescriptor): Boolean = true
}
public sealed class CallTypeAndReceiver<TReceiver : JetElement?, TCallType : CallType<TReceiver>>(
@@ -76,7 +76,7 @@ public fun CallableDescriptor.substituteExtensionIfCallable(
receiverTypes: Collection<JetType>,
callType: CallType<*>
): Collection<CallableDescriptor> {
if (!callType.canCall(this)) return listOf()
if (!callType.descriptorKindFilter.accepts(this)) return listOf()
var types = receiverTypes.asSequence()
if (callType == CallType.SAFE) {
@@ -2,6 +2,7 @@ import java.io.File
val v = File::<caret>
// 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())" }
@@ -4,6 +4,7 @@ class MyFile : File("") {
val v = ::<caret>
}
// 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())" }