Skip to content

Commit

Permalink
No callable references to synthetic extensions (and ones for get/set)
Browse files Browse the repository at this point in the history
  • Loading branch information
valentinkip committed Oct 3, 2015
1 parent 2471647 commit e41732e
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 53 deletions.
Expand Up @@ -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
Expand Down
Expand Up @@ -86,15 +86,19 @@ 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 -> {
return getVariantsForImportOrPackageDirective(callTypeAndReceiver.receiver, kindFilter, nameFilter)
}

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 -> {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
}
}

Expand All @@ -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
}
Expand Down Expand Up @@ -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)
}
Expand All @@ -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)) {
Expand All @@ -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)
}
}
Expand Down
61 changes: 38 additions & 23 deletions idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt
Expand Up @@ -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>() {
override fun canCall(descriptor: DeclarationDescriptor)
= descriptor is SimpleFunctionDescriptor && descriptor.getValueParameters().size() == 0
}
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 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
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
}

//TODO: canCall
object IMPORT_DIRECTIVE : CallType<JetExpression?>()
private object NonUnaryExclude : DescriptorKindExclude {
//TODO: check 'operator' modifier
override fun excludes(descriptor: DeclarationDescriptor) =
!(descriptor is SimpleFunctionDescriptor && descriptor.valueParameters.isEmpty())

object PACKAGE_DIRECTIVE : CallType<JetExpression?>()
override val fullyExcludedDescriptorKinds: Int
get() = 0
}

object TYPE : CallType<JetExpression?>()
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<TReceiver : JetElement?, TCallType : CallType<TReceiver>>(
Expand Down
Expand Up @@ -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) {
Expand Down
Expand Up @@ -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())" }
Expand Up @@ -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())" }

0 comments on commit e41732e

Please sign in to comment.