Refactoring: move main completion resolver out of Idea plugin.

This commit is contained in:
Nikolay Krasko
2011-12-21 16:20:51 +04:00
parent 529bcaf921
commit 9c5ff3fa7f
2 changed files with 139 additions and 107 deletions
@@ -0,0 +1,134 @@
package org.jetbrains.jet.compiler;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetQualifiedExpression;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintResolutionListener;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemSolution;
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.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.NamespaceType;
import org.jetbrains.jet.lang.types.Variance;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintType.RECEIVER;
/**
* @author Nikolay Krasko
*/
public final class TipsManager {
private TipsManager() {
}
@NotNull
public static Collection<DeclarationDescriptor> getReferenceVariants(JetSimpleNameExpression expression, BindingContext context) {
PsiElement parent = expression.getParent();
if (parent instanceof JetQualifiedExpression) {
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) parent;
JetExpression receiverExpression = qualifiedExpression.getReceiverExpression();
final JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, receiverExpression);
final JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, receiverExpression);
if (expressionType != null && resolutionScope != null) {
return includeExternalCallableExtensions(
expressionType.getMemberScope().getAllDescriptors(),
resolutionScope, new ExpressionReceiver(receiverExpression, expressionType));
}
}
else {
JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, expression);
if (resolutionScope != null) {
return excludeNotCallableExtensions(resolutionScope.getAllDescriptors(), resolutionScope);
}
}
return Collections.emptyList();
}
private static Collection<DeclarationDescriptor> excludeNotCallableExtensions(
@NotNull Collection<DeclarationDescriptor> descriptors, @NotNull final JetScope scope
) {
final Set<DeclarationDescriptor> descriptorsSet = Sets.newHashSet(descriptors);
descriptorsSet.removeAll(
Collections2.filter(JetScopeUtils.getAllExtensions(scope), new Predicate<CallableDescriptor>() {
@Override
public boolean apply(CallableDescriptor callableDescriptor) {
return !checkReceiverResolution(scope.getImplicitReceiver(), callableDescriptor);
}
}));
return Lists.newArrayList(descriptorsSet);
}
private static Collection<DeclarationDescriptor> includeExternalCallableExtensions(
@NotNull Collection<DeclarationDescriptor> descriptors,
@NotNull final JetScope externalScope,
@NotNull final ReceiverDescriptor receiverDescriptor
) {
// It's impossible to add extension function for namespace
if (receiverDescriptor.getType() instanceof NamespaceType) {
return descriptors;
}
Set<DeclarationDescriptor> descriptorsSet = Sets.newHashSet(descriptors);
descriptorsSet.addAll(
Collections2.filter(JetScopeUtils.getAllExtensions(externalScope),
new Predicate<CallableDescriptor>() {
@Override
public boolean apply(CallableDescriptor callableDescriptor) {
return checkReceiverResolution(receiverDescriptor, callableDescriptor);
}
}));
return descriptorsSet;
}
/*
* Checks if receiver declaration could be resolved to call expected receiver.
*/
private static boolean checkReceiverResolution (
@NotNull ReceiverDescriptor expectedReceiver,
@NotNull CallableDescriptor receiverArgument
) {
ConstraintSystem constraintSystem = new ConstraintSystemImpl(ConstraintResolutionListener.DO_NOTHING);
for (TypeParameterDescriptor typeParameterDescriptor : receiverArgument.getTypeParameters()) {
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT);
}
ReceiverDescriptor receiverParameter = receiverArgument.getReceiverParameter();
if (expectedReceiver.exists() && receiverParameter.exists()) {
constraintSystem.addSubtypingConstraint(
RECEIVER.assertSubtyping(expectedReceiver.getType(), receiverParameter.getType()));
}
else if (expectedReceiver.exists() || receiverParameter.exists()) {
// Only one of receivers exist
return false;
}
ConstraintSystemSolution solution = constraintSystem.solve();
return solution.getStatus().isSuccessful();
}
}
@@ -1,9 +1,6 @@
package org.jetbrains.jet.plugin.references;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.util.Iconable;
@@ -13,29 +10,17 @@ import com.intellij.psi.PsiElement;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.compiler.TipsManager;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintResolutionListener;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemSolution;
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.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.NamespaceType;
import org.jetbrains.jet.lang.types.Variance;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler;
import org.jetbrains.jet.resolve.DescriptorRenderer;
import java.util.List;
import java.util.Set;
import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintType.RECEIVER;
/**
* @author yole
@@ -70,33 +55,10 @@ class JetSimpleNameReference extends JetPsiReference {
@NotNull
@Override
public Object[] getVariants() {
PsiElement parent = myExpression.getParent();
if (parent instanceof JetQualifiedExpression) {
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) parent;
JetExpression receiverExpression = qualifiedExpression.getReceiverExpression();
JetFile file = (JetFile) myExpression.getContainingFile();
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(
(JetFile) myExpression.getContainingFile());
final JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, receiverExpression);
final JetScope resolutionScope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, receiverExpression);
if (expressionType != null && resolutionScope != null) {
return collectLookupElements(bindingContext,
includeExternalCallableExtensions(expressionType.getMemberScope().getAllDescriptors(),
resolutionScope, new ExpressionReceiver(receiverExpression, expressionType)));
}
}
else {
JetFile file = (JetFile) myExpression.getContainingFile();
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
JetScope resolutionScope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, myExpression);
if (resolutionScope != null) {
return collectLookupElements(bindingContext,
excludeNotCallableExtensions(resolutionScope.getAllDescriptors(), resolutionScope));
}
}
return EMPTY_ARRAY;
return collectLookupElements(bindingContext, TipsManager.getReferenceVariants(myExpression, bindingContext));
}
@Override
@@ -105,46 +67,7 @@ class JetSimpleNameReference extends JetPsiReference {
return myExpression.getReferencedNameElement().replace(element);
}
private Iterable<DeclarationDescriptor> excludeNotCallableExtensions(
@NotNull Iterable<DeclarationDescriptor> descriptors, @NotNull final JetScope scope
) {
final Set<DeclarationDescriptor> descriptorsSet = Sets.newHashSet(descriptors);
descriptorsSet.removeAll(
Collections2.filter(JetScopeUtils.getAllExtensions(scope), new Predicate<CallableDescriptor>() {
@Override
public boolean apply(CallableDescriptor callableDescriptor) {
return !checkReceiverResolution(scope.getImplicitReceiver(), callableDescriptor);
}
}));
return descriptorsSet;
}
private Iterable<DeclarationDescriptor> includeExternalCallableExtensions(
@NotNull Iterable<DeclarationDescriptor> descriptors,
@NotNull final JetScope externalScope,
@NotNull final ReceiverDescriptor receiverDescriptor
) {
// It's impossible to add extension function for namespace
if (receiverDescriptor.getType() instanceof NamespaceType) {
return descriptors;
}
Set<DeclarationDescriptor> descriptorsSet = Sets.newHashSet(descriptors);
descriptorsSet.addAll(Collections2.filter(JetScopeUtils.getAllExtensions(externalScope),
new Predicate<CallableDescriptor>() {
@Override
public boolean apply(CallableDescriptor callableDescriptor) {
return checkReceiverResolution(receiverDescriptor, callableDescriptor);
}
}));
return descriptorsSet;
}
private Object[] collectLookupElements(BindingContext bindingContext, Iterable<DeclarationDescriptor> descriptors) {
private static Object[] collectLookupElements(BindingContext bindingContext, Iterable<DeclarationDescriptor> descriptors) {
List<LookupElement> result = Lists.newArrayList();
for (final DeclarationDescriptor descriptor : descriptors) {
@@ -198,29 +121,4 @@ class JetSimpleNameReference extends JetPsiReference {
}
return result.toArray();
}
/*
* Checks if receiver declaration could be resolved to call expected receiver.
*/
private static boolean checkReceiverResolution (
@NotNull ReceiverDescriptor expectedReceiver,
@NotNull CallableDescriptor receiverArgument
) {
ConstraintSystem constraintSystem = new ConstraintSystemImpl(ConstraintResolutionListener.DO_NOTHING);
for (TypeParameterDescriptor typeParameterDescriptor : receiverArgument.getTypeParameters()) {
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT);
}
ReceiverDescriptor receiverParameter = receiverArgument.getReceiverParameter();
if (expectedReceiver.exists() && receiverParameter.exists()) {
constraintSystem.addSubtypingConstraint(RECEIVER.assertSubtyping(expectedReceiver.getType(), receiverParameter.getType()));
}
else if (expectedReceiver.exists() || receiverParameter.exists()) {
// Only one of receivers exist
return false;
}
ConstraintSystemSolution solution = constraintSystem.solve();
return solution.getStatus().isSuccessful();
}
}