Smart completion optimization

This commit is contained in:
Valentin Kipyatkov
2014-11-02 12:47:17 +03:00
parent 6f2da4930a
commit f31832dea9
5 changed files with 79 additions and 65 deletions
@@ -19,11 +19,12 @@ package org.jetbrains.jet.lang.resolve.scopes;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.TraceBasedRedeclarationHandler;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
@@ -31,7 +32,6 @@ import org.jetbrains.jet.utils.Printer;
import java.util.Collection;
import java.util.List;
import java.util.Set;
public final class JetScopeUtils {
private JetScopeUtils() {}
@@ -51,28 +51,6 @@ public final class JetScopeUtils {
);
}
/**
* Get all extension descriptors among visible descriptors for current scope.
*
* @param scope Scope for query extensions.
* @return extension descriptors.
*/
@NotNull
public static Collection<CallableDescriptor> getAllExtensions(@NotNull JetScope scope) {
Set<CallableDescriptor> result = Sets.newHashSet();
for (DeclarationDescriptor descriptor : scope.getDescriptors(JetScope.EXTENSIONS_MASK, JetScope.ALL_NAME_FILTER)) {
if (descriptor instanceof CallableDescriptor) {
CallableDescriptor callDescriptor = (CallableDescriptor) descriptor;
if (callDescriptor.getExtensionReceiverParameter() != null) {
result.add(callDescriptor);
}
}
}
return result;
}
public static JetScope makeScopeForPropertyAccessor(
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull JetScope parentScope,
@@ -23,7 +23,6 @@ import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.resolve.calls.smartcasts.SmartCastUtils
import org.jetbrains.jet.lang.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.jet.lang.resolve.scopes.JetScope
import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils
@@ -31,18 +30,21 @@ import java.util.*
import org.jetbrains.jet.lang.resolve.bindingContextUtil.getDataFlowInfo
import org.jetbrains.jet.lang.resolve.descriptorUtil.isExtension
import org.jetbrains.jet.lang.resolve.name.Name
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue
public object TipsManager{
public fun getReferenceVariants(expression: JetSimpleNameExpression,
context: BindingContext,
kindFilterMask: Int,
nameFilter: (Name) -> Boolean,
visibilityFilter: (DeclarationDescriptor) -> Boolean): Collection<DeclarationDescriptor> {
return getReferenceVariants(expression, context, nameFilter).filter(visibilityFilter)
return getReferenceVariants(expression, context, kindFilterMask, nameFilter).filter(visibilityFilter)
}
private fun getReferenceVariants(expression: JetSimpleNameExpression,
context: BindingContext,
kindFilterMask: Int,
nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
val receiverExpression = expression.getReceiverExpression()
val parent = expression.getParent()
@@ -64,7 +66,7 @@ public object TipsManager{
if (qualifier != null) {
//TODO: filter out extensions!
// It's impossible to add extension function for package or class (if it's class object, expression type is not null)
qualifier.scope.getDescriptors(JetScope.NON_EXTENSIONS_MASK, nameFilter).filterTo(descriptors, ::filterIfInfix)
qualifier.scope.getDescriptors(kindFilterMask and JetScope.NON_EXTENSIONS_MASK, nameFilter).filterTo(descriptors, ::filterIfInfix)
}
val expressionType = context[BindingContext.EXPRESSION_TYPE, receiverExpression]
@@ -74,12 +76,10 @@ public object TipsManager{
for (variant in SmartCastUtils.getSmartCastVariants(receiverValue, context, dataFlowInfo)) {
//TODO: filter out nested classes!
variant.getMemberScope().getDescriptors().filterTo(descriptors) { filterIfInfix(it) && !it.isExtension }
variant.getMemberScope().getDescriptors(kindFilterMask, nameFilter).filterTo(descriptors) { filterIfInfix(it) && !it.isExtension }
}
JetScopeUtils.getAllExtensions(resolutionScope).filterTo(descriptors) {
ExpressionTypingUtils.checkIsExtensionCallable(receiverValue, it, isInfixCall, context, dataFlowInfo)
}
descriptors.addAll(getCallableExtensions(resolutionScope, listOf(receiverValue), context, dataFlowInfo, isInfixCall, kindFilterMask, nameFilter))
}
return descriptors
@@ -87,23 +87,60 @@ public object TipsManager{
}
if (parent is JetImportDirective || parent is JetPackageDirective) {
return excludeNonPackageDescriptors(resolutionScope.getDescriptors(JetScope.PACKAGE, nameFilter))
return excludeNonPackageDescriptors(resolutionScope.getDescriptors(kindFilterMask and JetScope.PACKAGE, nameFilter))
}
else {
val descriptorsSet = HashSet<DeclarationDescriptor>()
for (receiverDescriptor in resolutionScope.getImplicitReceiversHierarchy()) {
receiverDescriptor.getType().getMemberScope().getDescriptors().filterTo(descriptorsSet) { !it.isExtension }
val receivers = resolutionScope.getImplicitReceiversHierarchy()
for (receiver in receivers) {
receiver.getType().getMemberScope().getDescriptors(kindFilterMask and JetScope.NON_EXTENSIONS_MASK, nameFilter)
.filterTo(descriptorsSet) { !it.isExtension }
}
descriptorsSet.addAll(resolutionScope.getDescriptors(JetScope.ALL_KINDS_MASK, nameFilter))
val dataFlowInfo = context.getDataFlowInfo(expression)
val receiverValues = receivers.map { it.getValue() }
descriptorsSet.excludeNotCallableExtensions(resolutionScope, context, context.getDataFlowInfo(expression))
resolutionScope.getDescriptors(kindFilterMask, nameFilter).filterTo(descriptorsSet) {
if (it is CallableDescriptor && it.getExtensionReceiverParameter() != null) {
it.isExtensionCallable(receiverValues, context, dataFlowInfo, false)
}
else
true
}
return descriptorsSet
}
}
public fun getCallableExtensions(
resolutionScope: JetScope,
receivers: Collection<ReceiverValue>,
context: BindingContext,
dataFlowInfo: DataFlowInfo,
isInfixCall: Boolean,
kindFilterMask: Int,
nameFilter: (Name) -> Boolean): Collection<CallableDescriptor> {
val mask = kindFilterMask and JetScope.EXTENSIONS_MASK
if (mask == 0) return listOf()
return resolutionScope.getDescriptors(mask, nameFilter)
.stream()
.filterIsInstance(javaClass<CallableDescriptor>())
.filter {
it.getExtensionReceiverParameter() != null && it.isExtensionCallable(receivers, context, dataFlowInfo, isInfixCall)
}
.toList()
}
public fun CallableDescriptor.isExtensionCallable(receivers: Collection<ReceiverValue>,
context: BindingContext,
dataFlowInfo: DataFlowInfo,
isInfixCall: Boolean): Boolean
= receivers.any { ExpressionTypingUtils.checkIsExtensionCallable(it, this, isInfixCall, context, dataFlowInfo) }
public fun CallableDescriptor.isExtensionCallableWithImplicitReceiver(scope: JetScope, context: BindingContext, dataFlowInfo: DataFlowInfo): Boolean
= isExtensionCallable(scope.getImplicitReceiversHierarchy().map { it.getValue() }, context, dataFlowInfo, false)
public fun getPackageReferenceVariants(expression: JetSimpleNameExpression,
context: BindingContext,
nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
@@ -111,24 +148,6 @@ public object TipsManager{
return excludeNonPackageDescriptors(resolutionScope.getDescriptors(JetScope.PACKAGE, nameFilter))
}
public fun excludeNotCallableExtensions(descriptors: Collection<DeclarationDescriptor>,
scope: JetScope,
context: BindingContext,
dataFlowInfo: DataFlowInfo): Collection<DeclarationDescriptor> {
val set = HashSet(descriptors)
set.excludeNotCallableExtensions(scope, context, dataFlowInfo)
return set
}
private fun MutableSet<DeclarationDescriptor>.excludeNotCallableExtensions(scope: JetScope,
context: BindingContext,
dataFlowInfo: DataFlowInfo) {
val implicitReceivers = scope.getImplicitReceiversHierarchy()
removeAll(JetScopeUtils.getAllExtensions(scope).filter { callable ->
implicitReceivers.none { ExpressionTypingUtils.checkIsExtensionCallable(it.getValue(), callable, false, context, dataFlowInfo) }
})
}
private fun excludeNonPackageDescriptors(descriptors: Collection<DeclarationDescriptor>): Collection<DeclarationDescriptor> {
return descriptors.filter{
if (it is PackageViewDescriptor) {
@@ -32,6 +32,7 @@ import org.jetbrains.jet.plugin.references.JetSimpleNameReference
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
import org.jetbrains.jet.plugin.caches.KotlinIndicesHelper
import com.intellij.openapi.project.Project
import org.jetbrains.jet.lang.resolve.scopes.JetScope
class CompletionSessionConfiguration(
val completeNonImportedDeclarations: Boolean,
@@ -86,8 +87,12 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess
protected abstract fun doComplete()
protected fun getReferenceVariants(): Collection<DeclarationDescriptor> {
return TipsManager.getReferenceVariants(jetReference!!.expression, bindingContext!!, prefixMatcher.asNameFilter(), { isVisibleDescriptor(it) })
protected fun getReferenceVariants(kindFilterMask: Int): Collection<DeclarationDescriptor> {
return TipsManager.getReferenceVariants(jetReference!!.expression,
bindingContext!!,
kindFilterMask,
prefixMatcher.asNameFilter(),
{ isVisibleDescriptor(it) })
}
protected fun shouldRunTopLevelCompletion(): Boolean {
@@ -136,12 +141,12 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
addAllTypes()
}
else {
addReferenceVariants { isPartOfTypeDeclaration(it) }
addReferenceVariants(JetScope.TYPE or JetScope.PACKAGE) { isPartOfTypeDeclaration(it) }
JavaCompletionContributor.advertiseSecondCompletion(project, resultSet)
}
}
else {
addReferenceVariants()
addReferenceVariants(JetScope.ALL_KINDS_MASK)
}
}
@@ -196,14 +201,20 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
return false
}
private fun addReferenceVariants(filterCondition: (DeclarationDescriptor) -> Boolean = { true }) {
collector.addDescriptorElements(getReferenceVariants().filter { filterCondition(it) }, suppressAutoInsertion = false)
private fun addReferenceVariants(kindFilterMask: Int, filterCondition: (DeclarationDescriptor) -> Boolean = { true }) {
collector.addDescriptorElements(getReferenceVariants(kindFilterMask).filter { filterCondition(it) }, suppressAutoInsertion = false)
}
}
class SmartCompletionSession(configuration: CompletionSessionConfiguration, parameters: CompletionParameters, resultSet: CompletionResultSet)
: CompletionSessionBase(configuration, parameters, resultSet) {
// we do not include SAM-constructors because they are handled separately and adding them requires iterating of java classes
private val DESCRIPTOR_KIND_MASK = JetScope.ORDINARY_FUNCTION or
JetScope.EXTENSION_FUNCTION or
JetScope.VARIABLES_AND_PROPERTIES_MASK or
JetScope.ENUM_ENTRY
override fun doComplete() {
if (jetReference != null) {
val completion = SmartCompletion(jetReference.expression, resolveSession, { isVisibleDescriptor(it) }, parameters.getOriginalFile() as JetFile)
@@ -213,7 +224,7 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
val filter = result.declarationFilter
if (filter != null) {
getReferenceVariants().forEach {
getReferenceVariants(DESCRIPTOR_KIND_MASK).forEach {
if (prefixMatcher.prefixMatches(it.getName().asString())) {
collector.addElements(filter(it))
}
@@ -74,20 +74,25 @@ public abstract class BaseJetVariableMacro extends Macro {
ExpressionTypingComponents components =
new InjectorForMacros(project, resolveSession.getModuleDescriptor()).getExpressionTypingComponents();
DataFlowInfo dataFlowInfo = getDataFlowInfo(bindingContext, contextExpression);
List<VariableDescriptor> filteredDescriptors = new ArrayList<VariableDescriptor>();
for (DeclarationDescriptor declarationDescriptor : scope.getDescriptors(JetScope.VARIABLES_AND_PROPERTIES_MASK, JetScope.ALL_NAME_FILTER)) {
if (declarationDescriptor instanceof VariableDescriptor) {
VariableDescriptor variableDescriptor = (VariableDescriptor) declarationDescriptor;
if (variableDescriptor.getExtensionReceiverParameter() != null
&& !TipsManager.INSTANCE$.isExtensionCallableWithImplicitReceiver(variableDescriptor, scope, bindingContext, dataFlowInfo)) continue;
if (isSuitable(variableDescriptor, scope, project, components)) {
filteredDescriptors.add(variableDescriptor);
}
}
}
DataFlowInfo dataFlowInfo = getDataFlowInfo(bindingContext, contextExpression);
List<JetNamedDeclaration> declarations = new ArrayList<JetNamedDeclaration>();
for (DeclarationDescriptor declarationDescriptor : TipsManager.INSTANCE$.excludeNotCallableExtensions(filteredDescriptors, scope, bindingContext, dataFlowInfo)) {
for (DeclarationDescriptor declarationDescriptor : filteredDescriptors) {
PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(declarationDescriptor);
assert declaration == null || declaration instanceof PsiNamedElement;
@@ -407,7 +407,8 @@ public class JetFunctionParameterInfoHandler implements ParameterInfoHandlerWith
return name.equals(refName);
}
};
Collection<DeclarationDescriptor> variants = TipsManager.INSTANCE$.getReferenceVariants(callNameExpression, bindingContext, nameFilter, visibilityFilter);
Collection<DeclarationDescriptor> variants = TipsManager.INSTANCE$.getReferenceVariants(
callNameExpression, bindingContext, JetScope.FUNCTIONS_MASK | JetScope.TYPE, nameFilter, visibilityFilter);
Collection<Pair<? extends DeclarationDescriptor, ResolveSessionForBodies>> itemsToShow = new ArrayList<Pair<? extends DeclarationDescriptor, ResolveSessionForBodies>>();
for (DeclarationDescriptor variant : variants) {