Smart completion optimization
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
+2
-1
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user