Use lazy resolve in completion

This commit is contained in:
Nikolay Krasko
2012-08-13 16:06:28 +04:00
parent 4c39a49bd1
commit 365bb3ad8a
9 changed files with 409 additions and 115 deletions
@@ -51,12 +51,15 @@ public final class TipsManager {
}
@NotNull
public static Collection<DeclarationDescriptor> getReferenceVariants(JetSimpleNameExpression expression, BindingContext context) {
public static Collection<DeclarationDescriptor> getReferenceVariants(
@NotNull final JetSimpleNameExpression expression,
@NotNull final BindingContext context
) {
JetExpression receiverExpression = expression.getReceiverExpression();
if (receiverExpression != null) {
// Process as call expression
final JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, expression);
final JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, receiverExpression);
JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, expression);
JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, receiverExpression);
if (expressionType != null && resolutionScope != null) {
if (!(expressionType instanceof NamespaceType)) {
@@ -116,7 +119,7 @@ public final class TipsManager {
}
@NotNull
public static Collection<DeclarationDescriptor> getReferenceVariants(JetNamespaceHeader expression, BindingContext context) {
public static Collection<DeclarationDescriptor> getPackageReferenceVariants(JetSimpleNameExpression expression, BindingContext context) {
JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, expression);
if (resolutionScope != null) {
return excludeNonPackageDescriptors(resolutionScope.getAllDescriptors());
@@ -0,0 +1,201 @@
/*
* Copyright 2010-2012 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.lang.resolve.lazy;
import com.google.common.base.Predicates;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.di.InjectorForBodyResolve;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
/**
* @author Nikolay Krasko
*/
public class LazyBindingContextUtils {
private static final Logger LOG = Logger.getInstance("#" + LazyBindingContextUtils.class.getName());
private LazyBindingContextUtils() {
}
private static class EmptyBodyResolveContext implements BodiesResolveContext {
@Override
public Map<JetClass, MutableClassDescriptor> getClasses() {
return Collections.emptyMap();
}
@Override
public Map<JetObjectDeclaration, MutableClassDescriptor> getObjects() {
return Collections.emptyMap();
}
@Override
public Map<JetProperty, PropertyDescriptor> getProperties() {
return Collections.emptyMap();
}
@Override
public Map<JetNamedFunction, SimpleFunctionDescriptor> getFunctions() {
return Collections.emptyMap();
}
@Override
public Map<JetDeclaration, JetScope> getDeclaringScopes() {
return Collections.emptyMap();
}
@Override
public Map<JetScript, ScriptDescriptor> getScripts() {
return Collections.emptyMap();
}
@Override
public Map<JetScript, WritableScope> getScriptScopes() {
return Collections.emptyMap();
}
@Override
public void setTopDownAnalysisParameters(TopDownAnalysisParameters parameters) {
}
@Override
public boolean completeAnalysisNeeded(@NotNull PsiElement element) {
return true;
}
}
public static @NotNull BindingContext getExpressionBindingContext(@NotNull ResolveSession resolveSession, @NotNull JetExpression expression) {
final DelegatingBindingTrace trace = new DelegatingBindingTrace(resolveSession.getBindingContext());
JetFile file = (JetFile) expression.getContainingFile();
// Resolve enclosing function body
JetNamedFunction namedFunction = PsiTreeUtil.getTopmostParentOfType(expression, JetNamedFunction.class);
if (namedFunction != null) {
TopDownAnalysisParameters parameters = new TopDownAnalysisParameters(
Predicates.<PsiFile>alwaysTrue(), false, true, Collections.<AnalyzerScriptParameter>emptyList());
InjectorForBodyResolve bodyResolve = new InjectorForBodyResolve(file.getProject(), parameters, trace, new EmptyBodyResolveContext());
final BodyResolver bodyResolver = bodyResolve.getBodyResolver();
if (namedFunction.getParent() instanceof JetFile ||
namedFunction.getParent() instanceof JetClassBody ||
namedFunction.getParent() instanceof JetClassObject) {
JetScope scope = resolveSession.getResolutionScope(namedFunction);
FunctionDescriptor functionDescriptor = (FunctionDescriptor) resolveSession.resolveToDescriptor(namedFunction);
bodyResolver.resolveFunctionBody(trace, namedFunction, functionDescriptor, scope);
}
else {
LOG.warn(String.format("Not expected parent for function: %s in %s",
namedFunction.getName(), namedFunction.getContainingFile()));
}
}
if (trace.getBindingContext().get(BindingContext.RESOLUTION_SCOPE, expression) == null) {
JetScope scope = getExpressionMemberScope(resolveSession, expression);
if (scope != null) {
trace.record(BindingContext.RESOLUTION_SCOPE, expression, scope);
}
}
return trace.getBindingContext();
}
private static JetScope getExpressionOuterScope(@NotNull ResolveSession resolveSession, @NotNull JetExpression expression) {
JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, JetDeclaration.class);
// DeclarationDescriptor descriptor = resolveToDescriptor(parentDeclaration);
return resolveSession.getResolutionScope(parentDeclaration);
}
public static JetScope getExpressionMemberScope(@NotNull ResolveSession resolveSession, @NotNull JetExpression expression) {
DelegatingBindingTrace trace = new DelegatingBindingTrace(resolveSession.getBindingContext());
if (expression instanceof JetReferenceExpression) {
// In some type declaration
if (expression.getParent() instanceof JetUserType) {
JetUserType qualifier = ((JetUserType) expression.getParent()).getQualifier();
if (qualifier != null) {
Collection<? extends DeclarationDescriptor> descriptors = resolveSession.getInjector().getQualifiedExpressionResolver()
.lookupDescriptorsForUserType(qualifier, getExpressionOuterScope(resolveSession, expression), trace);
for (DeclarationDescriptor descriptor : descriptors) {
if (descriptor instanceof LazyPackageDescriptor) {
return ((LazyPackageDescriptor) descriptor).getMemberScope();
}
}
}
}
// Inside import
if (PsiTreeUtil.getParentOfType(expression, JetImportDirective.class, false) != null) {
if (expression.getParent() instanceof JetDotQualifiedExpression) {
JetExpression element = ((JetDotQualifiedExpression) expression.getParent()).getReceiverExpression();
NamespaceDescriptor filePackage = resolveSession.getPackageDescriptorByFqName(
new FqName(((JetFile) expression.getContainingFile()).getPackageName()));
NamespaceDescriptor rootPackage = resolveSession.getPackageDescriptorByFqName(FqName.ROOT);
Collection<? extends DeclarationDescriptor> descriptors;
if (element instanceof JetDotQualifiedExpression) {
descriptors = resolveSession.getInjector().getQualifiedExpressionResolver().lookupDescriptorsForQualifiedExpression(
(JetDotQualifiedExpression) element, rootPackage.getMemberScope(), filePackage.getMemberScope(), trace, false, false);
}
else {
descriptors = resolveSession.getInjector().getQualifiedExpressionResolver().lookupDescriptorsForSimpleNameReference(
(JetSimpleNameExpression) element, rootPackage.getMemberScope(), filePackage.getMemberScope(), trace, false, false, false);
}
for (DeclarationDescriptor descriptor : descriptors) {
if (descriptor instanceof NamespaceDescriptor) {
return ((NamespaceDescriptor) descriptor).getMemberScope();
}
}
}
else {
return resolveSession.getPackageDescriptorByFqName(FqName.ROOT).getMemberScope();
}
}
// Inside package declaration
JetNamespaceHeader namespaceHeader = PsiTreeUtil.getParentOfType(expression, JetNamespaceHeader.class, false);
if (namespaceHeader != null) {
NamespaceDescriptor packageDescriptor = resolveSession.getPackageDescriptorByFqName(
namespaceHeader.getParentFqName((JetReferenceExpression)expression));
if (packageDescriptor != null) {
return packageDescriptor.getMemberScope();
}
}
}
return null;
}
}
@@ -18,6 +18,7 @@ package org.jetbrains.jet.plugin.caches;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.Sets;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.PsiClass;
@@ -39,6 +40,8 @@ import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
import org.jetbrains.jet.lang.resolve.ImportPath;
import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver;
import org.jetbrains.jet.lang.resolve.lazy.LazyBindingContextUtils;
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType;
@@ -155,22 +158,25 @@ public class JetShortNamesCache extends PsiShortNamesCache {
@NotNull JetSimpleNameExpression expression,
@NotNull GlobalSearchScope scope
) {
HashSet<FunctionDescriptor> result = new HashSet<FunctionDescriptor>();
JetFile jetFile = (JetFile) expression.getContainingFile();
BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(jetFile).getBindingContext();
final ResolveSession resolveSessionForFile = WholeProjectAnalyzerFacade.getLazyResolveSessionForFile(jetFile);
LazyBindingContextUtils.getExpressionBindingContext(resolveSessionForFile, expression);
BindingContext context = WholeProjectAnalyzerFacade.getLazyResolveContext(jetFile, expression);
JetScope jetScope = context.get(BindingContext.RESOLUTION_SCOPE, expression);
if (jetScope == null) {
return result;
return Collections.emptyList();
}
Set<FunctionDescriptor> result = Sets.newHashSet();
Collection<PsiMethod> topLevelFunctionPrototypes = JetFromJavaDescriptorHelper.getTopLevelFunctionPrototypesByName(name, project, scope);
for (PsiMethod method : topLevelFunctionPrototypes) {
FqName functionFQN = JetFromJavaDescriptorHelper.getJetTopLevelDeclarationFQN(method);
if (functionFQN != null) {
JetImportDirective importDirective = JetPsiFactory.createImportDirective(project, new ImportPath(functionFQN, false));
Collection<? extends DeclarationDescriptor> declarationDescriptors = new QualifiedExpressionResolver().analyseImportReference(importDirective, jetScope, new BindingTraceContext());
Collection<? extends DeclarationDescriptor> declarationDescriptors = new QualifiedExpressionResolver().analyseImportReference(
importDirective, jetScope, new BindingTraceContext());
for (DeclarationDescriptor declarationDescriptor : declarationDescriptors) {
if (declarationDescriptor instanceof FunctionDescriptor) {
result.add((FunctionDescriptor) declarationDescriptor);
@@ -181,10 +187,8 @@ public class JetShortNamesCache extends PsiShortNamesCache {
Collection<JetNamedFunction> jetNamedFunctions = JetShortFunctionNameIndex.getInstance().get(name, project, scope);
for (JetNamedFunction jetNamedFunction : jetNamedFunctions) {
SimpleFunctionDescriptor functionDescriptor = context.get(BindingContext.FUNCTION, jetNamedFunction);
if (functionDescriptor != null) {
result.add(functionDescriptor);
}
FunctionDescriptor functionDescriptor = (FunctionDescriptor) resolveSessionForFile.resolveToDescriptor(jetNamedFunction);
result.add(functionDescriptor);
}
return result;
@@ -224,7 +228,7 @@ public class JetShortNamesCache extends PsiShortNamesCache {
JetFile jetFile = (JetFile) expression.getContainingFile();
BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(jetFile).getBindingContext();
BindingContext context = WholeProjectAnalyzerFacade.getLazyResolveContext(jetFile, expression);
JetExpression receiverExpression = expression.getReceiverExpression();
if (receiverExpression != null) {
@@ -273,7 +277,7 @@ public class JetShortNamesCache extends PsiShortNamesCache {
@NotNull Condition<String> acceptedShortNameCondition,
@NotNull JetFile jetFile
) {
BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(jetFile).getBindingContext();
BindingContext context = WholeProjectAnalyzerFacade.getLazyResolveContext(jetFile, null);
Collection<ClassDescriptor> classDescriptors = new ArrayList<ClassDescriptor>();
for (String fqName : JetFullClassNameIndex.getInstance().getAllKeys(project)) {
@@ -21,18 +21,23 @@ import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiFile;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.asJava.JetLightClass;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
import org.jetbrains.jet.plugin.caches.JetCacheManager;
import org.jetbrains.jet.plugin.caches.JetShortNamesCache;
import org.jetbrains.jet.plugin.completion.handlers.JetJavaClassInsertHandler;
import org.jetbrains.jet.plugin.project.JsModuleDetector;
import org.jetbrains.jet.plugin.project.WholeProjectAnalyzerFacade;
import org.jetbrains.jet.plugin.stubindex.JetFullClassNameIndex;
import java.util.Collection;
@@ -40,34 +45,7 @@ import java.util.Collection;
* @author Nikolay Krasko
*/
public class JetClassCompletionContributor extends CompletionContributor {
public JetClassCompletionContributor() {
// Should be removed in new idea
//extend(CompletionType.CLASS_NAME, PlatformPatterns.psiElement(),
// new CompletionProvider<CompletionParameters>() {
// @Override
// protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context,
// final @NotNull CompletionResultSet result) {
// final CompletionResultSet jetResult = JetCompletionSorting.addJetSorting(parameters, result);
//
// final PsiElement position = parameters.getPosition();
// if (!(position.getContainingFile() instanceof JetFile)) {
// return;
// }
//
// final PsiReference ref = position.getContainingFile().findReferenceAt(parameters.getOffset());
// if (ref instanceof JetSimpleNameReference) {
// addClasses(parameters, result, new Consumer<LookupElement>() {
// @Override
// public void consume(LookupElement lookupElement) {
// jetResult.addElement(lookupElement);
// }
// });
// }
//
// result.stopHere();
// }
// });
}
public JetClassCompletionContributor() {}
/**
* Jet classes will be added as java completions for unification
@@ -75,17 +53,14 @@ public class JetClassCompletionContributor extends CompletionContributor {
static void addClasses(
@NotNull final CompletionParameters parameters,
@NotNull final CompletionResultSet result,
@NotNull final BindingContext jetContext,
@NotNull final Consumer<LookupElement> consumer
) {
CompletionResultSet tempResult = result.withPrefixMatcher(CompletionUtil.findReferenceOrAlphanumericPrefix(parameters));
// TODO: Make icon for standard types
final Collection<DeclarationDescriptor> jetOnlyClasses = JetShortNamesCache.getJetOnlyTypes();
final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(
(JetFile)parameters.getPosition().getContainingFile()).getBindingContext();
for (DeclarationDescriptor jetOnlyClass : jetOnlyClasses) {
consumer.consume(DescriptorLookupConverter.createLookupElement(bindingContext, jetOnlyClass));
consumer.consume(DescriptorLookupConverter.createLookupElement(jetContext, jetOnlyClass));
}
if (!JsModuleDetector.isJsModule((JetFile)parameters.getOriginalFile())) {
@@ -99,8 +74,8 @@ public class JetClassCompletionContributor extends CompletionContributor {
if (lookupElement instanceof JavaPsiClassReferenceElement) {
JavaPsiClassReferenceElement javaPsiReferenceElement = (JavaPsiClassReferenceElement) lookupElement;
PsiClass object = javaPsiReferenceElement.getObject();
if (addAsJetLookupElement(object, bindingContext, consumer)) {
PsiClass psiClass = javaPsiReferenceElement.getObject();
if (addAsJetLookupElement(parameters, psiClass, consumer)) {
return;
}
@@ -124,20 +99,30 @@ public class JetClassCompletionContributor extends CompletionContributor {
(JetFile) parameters.getOriginalFile());
for (ClassDescriptor descriptor : descriptors) {
consumer.consume(DescriptorLookupConverter.createLookupElement(bindingContext, descriptor));
consumer.consume(DescriptorLookupConverter.createLookupElement(jetContext, descriptor));
}
}
}
private static boolean addAsJetLookupElement(PsiClass aClass, BindingContext bindingContext, Consumer<LookupElement> consumer) {
private static boolean addAsJetLookupElement(CompletionParameters parameters, PsiClass aClass, Consumer<LookupElement> consumer) {
if (aClass instanceof JetLightClass) {
ClassDescriptor descriptor = bindingContext.get(
BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, ((JetLightClass)aClass).getFqName());
Project project = parameters.getPosition().getProject();
PsiFile completionFile = parameters.getPosition().getContainingFile();
if (descriptor != null) {
LookupElement element = DescriptorLookupConverter.createLookupElement(bindingContext, descriptor);
consumer.consume(element);
return true;
Collection<JetClassOrObject> classOrObjects =
JetFullClassNameIndex.getInstance().get(aClass.getQualifiedName(), project, GlobalSearchScope.allScope(project));
for (JetClassOrObject classOrObject : classOrObjects) {
if (classOrObject.getContainingFile().getOriginalFile().equals(aClass.getContainingFile())) {
PsiFile fileOfClass = completionFile.getOriginalFile().equals(aClass.getContainingFile()) ? completionFile : aClass.getContainingFile();
ResolveSession resolveSessionForFile = WholeProjectAnalyzerFacade.getLazyResolveSessionForFile((JetFile) fileOfClass);
ClassDescriptor descriptor = resolveSessionForFile.getClassDescriptor(classOrObject);
LookupElement element = DescriptorLookupConverter.createLookupElement(resolveSessionForFile.getBindingContext(), descriptor);
consumer.consume(element);
return true;
}
}
}
@@ -77,20 +77,18 @@ public class JetCompletionContributor extends CompletionContributor {
JetSimpleNameReference jetReference = getJetReference(parameters);
if (jetReference != null) {
BindingContext jetContext =
WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile)position.getContainingFile())
.getBindingContext();
BindingContext jetContext = WholeProjectAnalyzerFacade.getLazyResolveContext(
(JetFile) position.getContainingFile(), jetReference.getExpression());
JetScope scope = jetContext.get(BindingContext.RESOLUTION_SCOPE, jetReference.getExpression());
session.inDescriptor = scope != null ? scope.getContainingDeclaration() : null;
completeForReference(parameters, result, position, jetReference, session);
completeForReference(parameters, result, position, jetReference, session, jetContext);
if (!session.isSomethingAdded && session.customInvocationCount == 0) {
// Rerun completion if nothing was found
session.customInvocationCount = 1;
completeForReference(parameters, result, position, jetReference, session);
completeForReference(parameters, result, position, jetReference, session, jetContext);
}
}
@@ -105,18 +103,18 @@ public class JetCompletionContributor extends CompletionContributor {
@NotNull CompletionResultSet result,
@NotNull PsiElement position,
@NotNull JetSimpleNameReference jetReference,
@NotNull CompletionSession session
) {
@NotNull CompletionSession session,
BindingContext jetContext) {
if (isOnlyKeywordCompletion(position)) {
return;
}
if (shouldRunTypeCompletionOnly(position, jetReference)) {
if (session.customInvocationCount > 0) {
addClasses(parameters, result, session);
addClasses(parameters, result, session, jetContext);
}
else {
for (LookupElement variant : getReferenceVariants(jetReference, result, session)) {
for (LookupElement variant : getReferenceVariants(jetReference, result, session, jetContext)) {
if (isTypeDeclaration(variant)) {
addCheckedCompletionToResult(result, variant, session);
}
@@ -126,7 +124,7 @@ public class JetCompletionContributor extends CompletionContributor {
return;
}
for (LookupElement variant : getReferenceVariants(jetReference, result, session)) {
for (LookupElement variant : getReferenceVariants(jetReference, result, session, jetContext)) {
addCheckedCompletionToResult(result, variant, session);
}
@@ -144,7 +142,7 @@ public class JetCompletionContributor extends CompletionContributor {
}
if (shouldRunTopLevelCompletion(parameters, session)) {
addClasses(parameters, result, session);
addClasses(parameters, result, session, jetContext);
addJetTopLevelFunctions(jetReference.getExpression(), result, position, session);
}
@@ -157,12 +155,12 @@ public class JetCompletionContributor extends CompletionContributor {
return PsiTreeUtil.getParentOfType(position, JetModifierList.class) != null;
}
private static void addJetExtensions(JetSimpleNameExpression expression, CompletionResultSet result, PsiElement position) {
private static void addJetExtensions(@NotNull JetSimpleNameExpression expression, @NotNull CompletionResultSet result, @NotNull PsiElement position) {
final PrefixMatcher prefixMatcher = result.getPrefixMatcher();
JetShortNamesCache namesCache = JetCacheManager.getInstance(position.getProject()).getNamesCache();
Condition<String> matchPrefixCondition = new Condition<String>() {
@Override
public boolean value(String callableName) {
public boolean value(@NotNull String callableName) {
return prefixMatcher.prefixMatches(callableName);
}
};
@@ -170,8 +168,8 @@ public class JetCompletionContributor extends CompletionContributor {
Collection<DeclarationDescriptor> jetCallableExtensions = namesCache.getJetCallableExtensions(
matchPrefixCondition, expression, GlobalSearchScope.allScope(position.getProject()));
BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile)position.getContainingFile())
.getBindingContext();
BindingContext context = WholeProjectAnalyzerFacade.getLazyResolveContext(
(JetFile) position.getContainingFile(), expression);
for (DeclarationDescriptor jetCallableExtension : jetCallableExtensions) {
result.addElement(DescriptorLookupConverter.createLookupElement(context, jetCallableExtension));
@@ -192,11 +190,10 @@ public class JetCompletionContributor extends CompletionContributor {
return false;
}
private static void addJetTopLevelFunctions(JetSimpleNameExpression expression,
private static void addJetTopLevelFunctions(@NotNull JetSimpleNameExpression expression,
@NotNull CompletionResultSet result,
@NotNull PsiElement position,
@NotNull CompletionSession session) {
String actualPrefix = result.getPrefixMatcher().getPrefix();
Project project = position.getProject();
@@ -205,8 +202,8 @@ public class JetCompletionContributor extends CompletionContributor {
GlobalSearchScope scope = GlobalSearchScope.allScope(project);
Collection<String> functionNames = namesCache.getAllTopLevelFunctionNames();
BindingContext resolutionContext =
WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile)position.getContainingFile()).getBindingContext();
BindingContext resolutionContext = WholeProjectAnalyzerFacade.getLazyResolveContext(
(JetFile) position.getContainingFile(), expression);
for (String name : functionNames) {
if (name.contains(actualPrefix)) {
@@ -223,9 +220,9 @@ public class JetCompletionContributor extends CompletionContributor {
private static void addClasses(
@NotNull CompletionParameters parameters,
@NotNull final CompletionResultSet result,
@NotNull final CompletionSession session
) {
JetClassCompletionContributor.addClasses(parameters, result, new Consumer<LookupElement>() {
@NotNull final CompletionSession session,
BindingContext jetContext) {
JetClassCompletionContributor.addClasses(parameters, result, jetContext, new Consumer<LookupElement>() {
@Override
public void consume(@NotNull LookupElement element) {
addCompletionToResult(result, element, session);
@@ -233,7 +230,7 @@ public class JetCompletionContributor extends CompletionContributor {
});
}
private static boolean shouldRunTypeCompletionOnly(PsiElement position, JetSimpleNameReference jetReference) {
private static boolean shouldRunTypeCompletionOnly(PsiElement position, @NotNull JetSimpleNameReference jetReference) {
// Check that completion in the type annotation context and if there's a qualified
// expression we are at first of it
JetTypeReference typeReference = PsiTreeUtil.getParentOfType(position, JetTypeReference.class);
@@ -245,7 +242,7 @@ public class JetCompletionContributor extends CompletionContributor {
return false;
}
private static boolean shouldRunTopLevelCompletion(@NotNull CompletionParameters parameters, CompletionSession session) {
private static boolean shouldRunTopLevelCompletion(@NotNull CompletionParameters parameters, @NotNull CompletionSession session) {
if (session.customInvocationCount == 0) {
return false;
}
@@ -263,7 +260,7 @@ public class JetCompletionContributor extends CompletionContributor {
return false;
}
private static boolean shouldRunExtensionsCompletion(CompletionParameters parameters, String prefix, CompletionSession session) {
private static boolean shouldRunExtensionsCompletion(@NotNull CompletionParameters parameters, @NotNull String prefix, @NotNull CompletionSession session) {
if (session.customInvocationCount == 0 && prefix.length() < 3) {
return false;
}
@@ -312,7 +309,7 @@ public class JetCompletionContributor extends CompletionContributor {
session.isSomethingAdded = true;
}
private static boolean isVisibleElement(LookupElement element, CompletionSession session) {
private static boolean isVisibleElement(@NotNull LookupElement element, @NotNull CompletionSession session) {
if (session.inDescriptor != null) {
if (element.getObject() instanceof JetLookupObject) {
JetLookupObject jetObject = (JetLookupObject)element.getObject();
@@ -324,14 +321,16 @@ public class JetCompletionContributor extends CompletionContributor {
return true;
}
private static boolean isVisibleDescriptor(DeclarationDescriptor descriptor, CompletionSession session) {
private static boolean isVisibleDescriptor(DeclarationDescriptor descriptor, @NotNull CompletionSession session) {
if (session.customInvocationCount >= 2) {
// Show everything if user insist on showing completion list
return true;
}
if (descriptor instanceof DeclarationDescriptorWithVisibility) {
return Visibilities.isVisible((DeclarationDescriptorWithVisibility)descriptor, session.inDescriptor);
if (session.inDescriptor != null) {
return Visibilities.isVisible((DeclarationDescriptorWithVisibility)descriptor, session.inDescriptor);
}
}
return true;
@@ -341,13 +340,10 @@ public class JetCompletionContributor extends CompletionContributor {
private static LookupElement[] getReferenceVariants(
@NotNull JetSimpleNameReference reference,
@NotNull final CompletionResultSet result,
@NotNull final CompletionSession session
@NotNull final CompletionSession session,
BindingContext jetContext
) {
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(
(JetFile)reference.getExpression().getContainingFile())
.getBindingContext();
Collection<DeclarationDescriptor> descriptors = TipsManager.getReferenceVariants(reference.getExpression(), bindingContext);
Collection<DeclarationDescriptor> descriptors = TipsManager.getReferenceVariants(reference.getExpression(), jetContext);
Collection<DeclarationDescriptor> checkedDescriptors = Collections2.filter(descriptors, new Predicate<DeclarationDescriptor>() {
@Override
@@ -360,6 +356,6 @@ public class JetCompletionContributor extends CompletionContributor {
}
});
return DescriptorLookupConverter.collectLookupElements(bindingContext, checkedDescriptors);
return DescriptorLookupConverter.collectLookupElements(jetContext, checkedDescriptors);
}
}
@@ -24,7 +24,10 @@ import com.intellij.psi.PsiElement;
import com.intellij.util.Consumer;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.project.WholeProjectAnalyzerFacade;
/**
* Special contributor for getting completion of type for extensions receiver.
@@ -38,8 +41,11 @@ public class JetExtensionReceiverTypeContributor extends CompletionContributor {
ProcessingContext context,
final @NotNull CompletionResultSet result
) {
BindingContext jetContext = WholeProjectAnalyzerFacade
.getLazyResolveContext((JetFile) parameters.getPosition().getContainingFile(), null);
if (parameters.getInvocationCount() > 0 || parameters.getCompletionType() == CompletionType.CLASS_NAME) {
JetClassCompletionContributor.addClasses(parameters, result, new Consumer<LookupElement>() {
JetClassCompletionContributor.addClasses(parameters, result, jetContext, new Consumer<LookupElement>() {
@Override
public void consume(@NotNull LookupElement element) {
result.addElement(element);
@@ -71,12 +71,11 @@ public class JetPackagesContributor extends CompletionContributor {
int prefixLength = parameters.getOffset() - simpleNameReference.getExpression().getTextOffset();
result = result.withPrefixMatcher(new PlainPrefixMatcher(name.substring(0, prefixLength)));
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(
(JetFile)namespaceHeader.getContainingFile())
.getBindingContext();
BindingContext bindingContext = WholeProjectAnalyzerFacade.getLazyResolveContext(
(JetFile) namespaceHeader.getContainingFile(), simpleNameReference.getExpression());
for (LookupElement variant : DescriptorLookupConverter.collectLookupElements(
bindingContext, TipsManager.getReferenceVariants(namespaceHeader, bindingContext))) {
bindingContext, TipsManager.getPackageReferenceVariants(simpleNameReference.getExpression(), bindingContext))) {
if (!variant.getLookupString().contains(DUMMY_IDENTIFIER)) {
result.addElement(variant);
}
@@ -92,5 +91,6 @@ public class JetPackagesContributor extends CompletionContributor {
public void beforeCompletion(@NotNull CompletionInitializationContext context) {
// Will need to filter this dummy identifier to avoid showing it in completion
context.setDummyIdentifier(DUMMY_IDENTIFIER);
// context.setDummyIdentifier(CompletionInitializationContext.DUMMY_IDENTIFIER);
}
}
@@ -18,33 +18,43 @@ package org.jetbrains.jet.plugin.project;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.impl.PsiModificationTrackerImpl;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.analyzer.AnalyzeExhaust;
import org.jetbrains.jet.di.InjectorForJavaDescriptorResolver;
import org.jetbrains.jet.lang.BuiltinsScopeExtensionMode;
import org.jetbrains.jet.lang.DefaultModuleConfiguration;
import org.jetbrains.jet.lang.ModuleConfiguration;
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter;
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
import org.jetbrains.jet.lang.resolve.BodiesResolveContext;
import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace;
import org.jetbrains.jet.lang.resolve.java.JetFilesProvider;
import org.jetbrains.jet.lang.psi.JetImportDirective;
import org.jetbrains.jet.lang.psi.JetPsiFactory;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.java.*;
import org.jetbrains.jet.lang.resolve.lazy.FileBasedDeclarationProviderFactory;
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import java.util.Collection;
import java.util.Collections;
import java.util.*;
/**
* @author Pavel Talanov
@@ -55,6 +65,7 @@ public final class AnalyzerFacadeWithCache {
private final static Key<CachedValue<AnalyzeExhaust>> ANALYZE_EXHAUST_HEADERS = Key.create("ANALYZE_EXHAUST_HEADERS");
private final static Key<CachedValue<AnalyzeExhaust>> ANALYZE_EXHAUST_FULL = Key.create("ANALYZE_EXHAUST_FULL");
private final static Key<CachedValue<ResolveSession>> ANALYZE_EXHAUST_LAZY_FULL = Key.create("ANALYZE_EXHAUST_FULL");
private static final Object lock = new Object();
public static final Function<JetFile, Collection<JetFile>> SINGLE_DECLARATION_PROVIDER = new Function<JetFile, Collection<JetFile>>() {
@@ -67,7 +78,6 @@ public final class AnalyzerFacadeWithCache {
private AnalyzerFacadeWithCache() {
}
/**
* Analyze project with string cache for given file. Given file will be fully analyzed.
*
@@ -88,8 +98,6 @@ public final class AnalyzerFacadeWithCache {
@Override
public Result<AnalyzeExhaust> compute() {
try {
// System.out.println("===============ReCache - In-Block==============");
// Collect context for headers first
AnalyzeExhaust analyzeExhaustHeaders = analyzeHeadersWithCacheOnFile(file, declarationProvider);
@@ -149,7 +157,6 @@ public final class AnalyzerFacadeWithCache {
CachedValuesManager.getManager(fileToCache.getProject()).createCachedValue(new CachedValueProvider<AnalyzeExhaust>() {
@Override
public Result<AnalyzeExhaust> compute() {
// System.out.println("===============ReCache - OUT-OF-BLOCK==============");
AnalyzeExhaust exhaust = AnalyzerFacadeProvider.getAnalyzerFacadeForFile(fileToCache)
.analyzeFiles(fileToCache.getProject(),
declarationProvider.fun(fileToCache),
@@ -169,4 +176,80 @@ public final class AnalyzerFacadeWithCache {
DiagnosticUtils.throwIfRunningOnServer(e);
LOG.error(e);
}
private static final Object lazyLock = new Object();
@NotNull
public static ResolveSession getLazyResolveSession(@NotNull final JetFile file) {
synchronized (lazyLock) {
final Project fileProject = file.getProject();
CachedValue<ResolveSession> bindingContextCachedValue = file.getUserData(ANALYZE_EXHAUST_LAZY_FULL);
if (bindingContextCachedValue == null) {
bindingContextCachedValue =
CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider<ResolveSession>() {
@Override
public Result<ResolveSession> compute() {
ModuleDescriptor javaModule = new ModuleDescriptor(Name.special("<java module>"));
InjectorForJavaDescriptorResolver injector = new InjectorForJavaDescriptorResolver(
fileProject, new BindingTraceContext(), javaModule, BuiltinsScopeExtensionMode.ALL);
List<JetFile> files = JetFilesProvider.getInstance(fileProject).allInScope(GlobalSearchScope.allScope(fileProject));
// Given file can differ from the original because it can be a virtual copy with some modifications
JetFile originalFile = (JetFile) file.getOriginalFile();
files.remove(originalFile);
files.add(file);
final PsiClassFinder psiClassFinder = injector.getPsiClassFinder();
// TODO: Replace with stub declaration provider
final FileBasedDeclarationProviderFactory declarationProviderFactory = new FileBasedDeclarationProviderFactory(files, new Predicate<FqName>() {
@Override
public boolean apply(FqName fqName) {
return psiClassFinder.findPsiPackage(fqName) != null || new FqName("jet").equals(fqName);
}
});
final JavaDescriptorResolver javaDescriptorResolver = injector.getJavaDescriptorResolver();
ModuleConfiguration moduleConfiguration = new ModuleConfiguration() {
@Override
public void addDefaultImports(@NotNull Collection<JetImportDirective> directives) {
final Collection<ImportPath> defaultImports = Lists.newArrayList(JavaBridgeConfiguration.DEFAULT_JAVA_IMPORTS);
defaultImports.addAll(Arrays.asList(DefaultModuleConfiguration.DEFAULT_JET_IMPORTS));
for (ImportPath defaultJetImport : defaultImports) {
directives.add(JetPsiFactory.createImportDirective(fileProject, defaultJetImport));
}
}
@Override
public void extendNamespaceScope(
@NotNull BindingTrace trace,
@NotNull NamespaceDescriptor namespaceDescriptor,
@NotNull WritableScope namespaceMemberScope
) {
FqName fqName = DescriptorUtils.getFQName(namespaceDescriptor).toSafe();
if (new FqName("jet").equals(fqName)) {
namespaceMemberScope.importScope(JetStandardLibrary.getInstance().getLibraryScope());
}
if (psiClassFinder.findPsiPackage(fqName) != null) {
JavaPackageScope javaPackageScope = javaDescriptorResolver.getJavaPackageScope(fqName, namespaceDescriptor);
namespaceMemberScope.importScope(javaPackageScope);
}
}
};
ModuleDescriptor lazyModule = new ModuleDescriptor(Name.special("<lazy module>"));
ResolveSession resolveSession = new ResolveSession(fileProject, lazyModule, moduleConfiguration, declarationProviderFactory);
return new Result<ResolveSession>(resolveSession, PsiModificationTracker.MODIFICATION_COUNT);
}
}, false);
file.putUserData(ANALYZE_EXHAUST_LAZY_FULL, bindingContextCachedValue);
}
return bindingContextCachedValue.getValue();
}
}
}
@@ -17,20 +17,23 @@
package org.jetbrains.jet.plugin.project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.analyzer.AnalyzeExhaust;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.JetFilesProvider;
import org.jetbrains.jet.lang.resolve.lazy.LazyBindingContextUtils;
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
import static org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache.analyzeFileWithCache;
import static org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache.getLazyResolveSession;
/**
* @author abreslav
*/
public final class WholeProjectAnalyzerFacade {
/**
* Forbid creating
*/
private WholeProjectAnalyzerFacade() {
}
@@ -38,4 +41,17 @@ public final class WholeProjectAnalyzerFacade {
public static AnalyzeExhaust analyzeProjectWithCacheOnAFile(@NotNull JetFile file) {
return analyzeFileWithCache(file, JetFilesProvider.getInstance(file.getProject()).sampleToAllFilesInModule());
}
@NotNull
public static ResolveSession getLazyResolveSessionForFile(@NotNull JetFile file) {
return getLazyResolveSession(file);
}
@NotNull
public static BindingContext getLazyResolveContext(@NotNull JetFile file, @Nullable JetExpression expression) {
ResolveSession resolveSession = getLazyResolveSessionForFile(file);
return expression != null ?
LazyBindingContextUtils.getExpressionBindingContext(resolveSession, expression) :
resolveSession.getBindingContext();
}
}