Code completion: do not list instance members from context with no instance

#KT-6388 Fixed
 #KT-4422 Fixed
 #KT-5516 Fixed
This commit is contained in:
Valentin Kipyatkov
2014-12-19 21:42:15 +03:00
parent d33e60b876
commit 311a3a75c8
22 changed files with 307 additions and 18 deletions
@@ -38,6 +38,7 @@ import org.jetbrains.jet.lang.types.checker.JetTypeChecker
import org.jetbrains.jet.lexer.JetTokens
import org.jetbrains.jet.plugin.util.CallType
import org.jetbrains.jet.plugin.util.substituteExtensionIfCallable
import org.jetbrains.jet.plugin.util.getImplicitReceiversWithInstance
public class ReferenceVariantsHelper(
private val context: BindingContext,
@@ -72,13 +73,11 @@ public class ReferenceVariantsHelper(
val resolutionScope = context[BindingContext.RESOLUTION_SCOPE, expression] ?: return listOf()
if (parent is JetImportDirective || parent is JetPackageDirective) {
val restrictedFilter = kindFilter.restrictedToKinds(DescriptorKindFilter.PACKAGES_MASK) ?: return listOf()
return resolutionScope.getDescriptorsFiltered(restrictedFilter, nameFilter)
return resolutionScope.getDescriptorsFiltered(kindFilter.restrictedToKinds(DescriptorKindFilter.PACKAGES_MASK), nameFilter)
}
if (parent is JetUserType) {
val restrictedFilter = kindFilter.restrictedToKinds(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK) ?: return listOf()
return resolutionScope.getDescriptorsFiltered(restrictedFilter, nameFilter)
return resolutionScope.getDescriptorsFiltered(kindFilter.restrictedToKinds(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK), nameFilter)
}
val pair = getExplicitReceiverData(expression)
@@ -112,7 +111,8 @@ public class ReferenceVariantsHelper(
else {
val descriptorsSet = HashSet<DeclarationDescriptor>()
val receivers = resolutionScope.getImplicitReceiversHierarchy()
// process instance members that can be called via implicit receiver's instances
val receivers = resolutionScope.getImplicitReceiversWithInstance()
receivers.flatMapTo(descriptorsSet) {
it.getType().getMemberScope().getDescriptorsFiltered(kindFilter exclude DescriptorKindExclude.Extensions, nameFilter)
}
@@ -120,7 +120,10 @@ public class ReferenceVariantsHelper(
val dataFlowInfo = context.getDataFlowInfo(expression)
val receiverValues = receivers.map { it.getValue() }
// process extensions and non-instance members
for (descriptor in resolutionScope.getDescriptorsFiltered(kindFilter, nameFilter)) {
if (descriptor is CallableDescriptor && descriptor.getDispatchReceiverParameter() != null) continue // should already be processed via implicit receivers
if (descriptor is CallableDescriptor && descriptor.getExtensionReceiverParameter() != null) {
descriptorsSet.addAll(descriptor.substituteExtensionIfCallable(receiverValues, context, dataFlowInfo, CallType.NORMAL))
}
@@ -164,7 +167,7 @@ public class ReferenceVariantsHelper(
}
else {
val resolutionScope = context[BindingContext.RESOLUTION_SCOPE, expression] ?: return ReceiversData.Empty
return ReceiversData(resolutionScope.getImplicitReceiversHierarchy().map { it.getValue() }, CallType.NORMAL)
return ReceiversData(resolutionScope.getImplicitReceiversWithInstance().map { it.getValue() }, CallType.NORMAL)
}
}
@@ -185,9 +188,23 @@ public class ReferenceVariantsHelper(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
) {
if (!kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) {
for (callable in resolutionScope.getDescriptorsFiltered(kindFilter.exclude(DescriptorKindExclude.NonExtensions), nameFilter)) {
addAll((callable as CallableDescriptor).substituteExtensionIfCallable(receiver, callType, context, dataFlowInfo))
if (kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) return
val extensionsFilter = kindFilter.exclude(DescriptorKindExclude.NonExtensions)
fun processExtension(descriptor: DeclarationDescriptor) {
addAll((descriptor as CallableDescriptor).substituteExtensionIfCallable(receiver, callType, context, dataFlowInfo))
}
// process member extensions from implicit receivers separately to filter out ones from implicit receivers with no instance
for (implicitReceiver in resolutionScope.getImplicitReceiversWithInstance()) {
for (extension in implicitReceiver.getType().getMemberScope().getDescriptorsFiltered(extensionsFilter, nameFilter)) {
processExtension(extension)
}
}
for (extension in resolutionScope.getDescriptorsFiltered(extensionsFilter, nameFilter)) {
if ((extension as CallableDescriptor).getDispatchReceiverParameter() == null) { // otherwise it should already be processed via implicit receivers
processExtension(extension)
}
}
}
@@ -56,7 +56,7 @@ public fun CallableDescriptor.substituteExtensionIfCallable(receivers: Collectio
}
public fun CallableDescriptor.substituteExtensionIfCallableWithImplicitReceiver(scope: JetScope, context: BindingContext, dataFlowInfo: DataFlowInfo): Collection<CallableDescriptor>
= substituteExtensionIfCallable(scope.getImplicitReceiversHierarchy().map { it.getValue() }, context, dataFlowInfo, CallType.NORMAL)
= substituteExtensionIfCallable(scope.getImplicitReceiversWithInstance().map { it.getValue() }, context, dataFlowInfo, CallType.NORMAL)
public fun CallableDescriptor.substituteExtensionIfCallable(
receiver: ReceiverValue,
@@ -0,0 +1,43 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.util
import org.jetbrains.jet.lang.resolve.scopes.JetScope
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
import java.util.LinkedHashSet
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
import java.util.HashSet
public fun JetScope.getImplicitReceiversWithInstance(): List<ReceiverParameterDescriptor> {
// we use a set to workaround a bug with receiver for class object present twice in the result of getImplicitReceiversHierarchy()
val receivers = LinkedHashSet(getImplicitReceiversHierarchy())
val withInstance = HashSet<DeclarationDescriptor>()
var current: DeclarationDescriptor? = getContainingDeclaration()
while (current != null) {
withInstance.add(current)
val classDescriptor = current as? ClassDescriptor
if (classDescriptor != null && !classDescriptor.isInner()) break
current = current!!.getContainingDeclaration()
}
return receivers.filter {
val owner = it.getContainingDeclaration()
owner is ClassDescriptor && owner.getKind().isSingleton() || owner in withInstance
}
}