KT-983 Code completion for not-imported classes - Show kotlin classes (another temp commit)

This commit is contained in:
Nikolay Krasko
2012-01-23 15:20:57 +04:00
parent 0f70f098b3
commit c52e56740d
11 changed files with 475 additions and 130 deletions
@@ -40,6 +40,12 @@ public class AnalyzerFacade {
private final static Key<CachedValue<BindingContext>> BINDING_CONTEXT = Key.create("BINDING_CONTEXT");
private static final Object lock = new Object();
/**
* Analyze project with string cache for given file. Given file will be fully analyzed.
* @param file
* @param declarationProvider
* @return
*/
public static BindingContext analyzeFileWithCache(@NotNull final JetFile file, @NotNull final Function<JetFile, Collection<JetFile>> declarationProvider) {
// Need lock for getValue(), because parallel threads can start evaluation of compute() simultaneously
synchronized (lock) {
@@ -49,7 +55,11 @@ public class AnalyzerFacade {
@Override
public Result<BindingContext> compute() {
try {
BindingContext bindingContext = analyzeFilesWithJavaIntegration(file.getProject(), declarationProvider.fun(file), Predicates.<PsiFile>equalTo(file), JetControlFlowDataTraceFactory.EMPTY);
BindingContext bindingContext = analyzeFilesWithJavaIntegration(
file.getProject(),
declarationProvider.fun(file),
Predicates.<PsiFile>equalTo(file),
JetControlFlowDataTraceFactory.EMPTY);
return new Result<BindingContext>(bindingContext, PsiModificationTracker.MODIFICATION_COUNT);
}
catch (ProcessCanceledException e) {
@@ -71,11 +81,49 @@ public class AnalyzerFacade {
}
}
/**
* Analyze project with string cache for the whole project. All given files will be analyzed only for descriptors.
*/
public static BindingContext analyzeProjectWithCache(@NotNull final Project project,
@NotNull final Collection<JetFile> files) {
// Need lock for getValue(), because parallel threads can start evaluation of compute() simultaneously
synchronized (lock) {
CachedValue<BindingContext> bindingContextCachedValue = project.getUserData(BINDING_CONTEXT);
if (bindingContextCachedValue == null) {
bindingContextCachedValue = CachedValuesManager.getManager(project).createCachedValue(new CachedValueProvider<BindingContext>() {
@Override
public Result<BindingContext> compute() {
try {
BindingContext bindingContext = analyzeFilesWithJavaIntegration(
project,
files,
Predicates.<PsiFile>alwaysFalse(),
JetControlFlowDataTraceFactory.EMPTY);
return new Result<BindingContext>(bindingContext, PsiModificationTracker.MODIFICATION_COUNT);
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Throwable e) {
DiagnosticUtils.throwIfRunningOnServer(e);
e.printStackTrace();
BindingTraceContext bindingTraceContext = new BindingTraceContext();
return new Result<BindingContext>(bindingTraceContext.getBindingContext(), PsiModificationTracker.MODIFICATION_COUNT);
}
}
}, false);
project.putUserData(BINDING_CONTEXT, bindingContextCachedValue);
}
return bindingContextCachedValue.getValue();
}
}
public static BindingContext analyzeOneFileWithJavaIntegration(JetFile file, JetControlFlowDataTraceFactory flowDataTraceFactory) {
return analyzeFilesWithJavaIntegration(file.getProject(), Collections.singleton(file), Predicates.<PsiFile>alwaysTrue(), flowDataTraceFactory);
}
public static BindingContext analyzeFilesWithJavaIntegration(Project project, Collection<JetFile> files, Predicate<PsiFile> filesToAnalyzeCompletely, JetControlFlowDataTraceFactory flowDataTraceFactory) {
public static BindingContext analyzeFilesWithJavaIntegration(Project project, Collection<JetFile> files, Predicate<PsiFile> filesToAnalyzeCompletely,
JetControlFlowDataTraceFactory flowDataTraceFactory) {
BindingTraceContext bindingTraceContext = new BindingTraceContext();
JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project);
return AnalyzingUtils.analyzeFilesWithGivenTrace(
@@ -3,14 +3,13 @@
*/
package org.jetbrains.jet.asJava;
import com.intellij.openapi.compiler.ex.CompilerPathsEx;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.psi.*;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElementFinder;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.impl.file.PsiPackageImpl;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.SmartList;
@@ -18,9 +17,11 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.codegen.JetTypeMapper;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.plugin.JetFileType;
import java.util.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.WeakHashMap;
public class JavaElementFinder extends PsiElementFinder {
private final Project project;
@@ -181,29 +182,8 @@ public class JavaElementFinder extends PsiElementFinder {
List<JetFile> cachedFiles = jetFiles.get(scope);
if (cachedFiles == null) {
final List<JetFile> answer = new ArrayList<JetFile>();
final FileTypeManager fileTypeManager = FileTypeManager.getInstance();
List<VirtualFile> contentRoots = Arrays.asList(ProjectRootManager.getInstance(project).getContentRoots());
CompilerPathsEx.visitFiles(contentRoots, new CompilerPathsEx.FileVisitor() {
@Override
protected void acceptFile(VirtualFile file, String fileRoot, String filePath) {
final FileType fileType = fileTypeManager.getFileTypeByFile(file);
if (fileType != JetFileType.INSTANCE) return;
if (scope.accept(file)) {
final PsiFile psiFile = psiManager.findFile(file);
if (psiFile instanceof JetFile) {
answer.add((JetFile) psiFile);
}
}
}
});
cachedFiles = answer;
jetFiles.put(scope, answer);
cachedFiles = JetFileUtil.collectJetFiles(project, scope);
jetFiles.put(scope, cachedFiles);
}
return cachedFiles;
@@ -0,0 +1,51 @@
package org.jetbrains.jet.asJava;
import com.intellij.openapi.compiler.ex.CompilerPathsEx;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.plugin.JetFileType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Nikolay Krasko
*/
public final class JetFileUtil {
private JetFileUtil() {}
public static List<JetFile> collectJetFiles(final Project project, @NotNull final GlobalSearchScope scope) {
final List<JetFile> answer = new ArrayList<JetFile>();
final FileTypeManager fileTypeManager = FileTypeManager.getInstance();
List<VirtualFile> contentRoots = Arrays.asList(ProjectRootManager.getInstance(project).getContentRoots());
final PsiManager manager = PsiManager.getInstance(project);
CompilerPathsEx.visitFiles(contentRoots, new CompilerPathsEx.FileVisitor() {
@Override
protected void acceptFile(VirtualFile file, String fileRoot, String filePath) {
final FileType fileType = fileTypeManager.getFileTypeByFile(file);
if (fileType != JetFileType.INSTANCE) return;
if (scope.accept(file)) {
final PsiFile psiFile = manager.findFile(file);
if (psiFile instanceof JetFile) {
answer.add((JetFile) psiFile);
}
}
}
});
return answer;
}
}
+4
View File
@@ -11,6 +11,9 @@
<component>
<implementation-class>org.jetbrains.jet.plugin.compiler.JetCompilerManager</implementation-class>
</component>
<component>
<implementation-class>org.jetbrains.jet.plugin.caches.JetCacheManager</implementation-class>
</component>
</project-components>
<actions>
@@ -74,6 +77,7 @@
<codeInsight.overrideMethod language="jet" implementationClass="org.jetbrains.jet.plugin.codeInsight.OverrideMethodsHandler"/>
<java.elementFinder implementation="org.jetbrains.jet.asJava.JavaElementFinder"/>
<java.shortNamesCache implementation="org.jetbrains.jet.plugin.caches.JetShortNamesCache"/>
<psi.treeChangePreprocessor implementation="org.jetbrains.jet.asJava.JetCodeBlockModificationListener"/>
@@ -0,0 +1,51 @@
package org.jetbrains.jet.plugin.caches;
import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
/**
* @author Nikolay Krasko
*/
public class JetCacheManager implements ProjectComponent {
private Project myProject;
private JetShortNamesCache myCache;
public static JetCacheManager getInstance(Project project) {
return project.getComponent(JetCacheManager.class);
}
public JetCacheManager(Project project) {
myProject = project;
}
@Override
public void projectOpened() {
}
@Override
public void projectClosed() {
}
@Override
@NotNull
public String getComponentName() {
return "Kotlin caches manager";
}
@Override
public void initComponent() {
myCache = new JetShortNamesCache(myProject);
}
@Override
public void disposeComponent() {
}
public JetShortNamesCache getNamesCache() {
return myCache;
}
}
@@ -0,0 +1,148 @@
package org.jetbrains.jet.plugin.caches;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author Nikolay Krasko
*/
public class JetShortNamesCache extends PsiShortNamesCache {
private final Project project;
public JetShortNamesCache(Project project) {
this.project = project;
}
@NotNull
@Override
public PsiClass[] getClassesByName(@NotNull @NonNls String name, @NotNull GlobalSearchScope scope) {
return new PsiClass[0];
}
@NotNull
@Override
public String[] getAllClassNames() {
return new String[0];
}
@Override
public void getAllClassNames(@NotNull HashSet<String> dest) {
}
public List<String> getAllJetClassNames() {
final BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCache(project, GlobalSearchScope.allScope(project));
final Collection<String> fqNames = context.getKeys(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR);
final ArrayList<String> classNames = new ArrayList<String>();
for (String fqName : fqNames) {
int lastDotIndex = fqName.lastIndexOf('.');
if (lastDotIndex != -1) {
classNames.add(fqName.substring(lastDotIndex + 1, fqName.length()));
}
else {
classNames.add(fqName);
}
}
return classNames;
}
public Collection<ClassDescriptor> getClassDescriptors() {
final BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCache(project, GlobalSearchScope.allScope(project));
final Collection<String> fqNames = context.getKeys(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR);
return Collections2.transform(fqNames, new Function<String, ClassDescriptor>() {
@Override
public ClassDescriptor apply(String fqName) {
return context.get(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, fqName);
}
});
}
public List<JetClass> getJetClassesByName(@NotNull String name, @NotNull GlobalSearchScope scope) {
final BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCache(project, scope);
final ArrayList<JetClass> classesResult = new ArrayList<JetClass>();
for (String fqn : getFQNamesByName(name, scope)) {
final ClassDescriptor descriptor = context.get(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, fqn);
final PsiElement declaration = context.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor);
if (declaration instanceof JetClass) {
classesResult.add((JetClass) declaration);
}
}
return classesResult;
}
@NotNull
public Collection<String> getFQNamesByName(@NotNull final String name, @NotNull GlobalSearchScope scope) {
final BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCache(project, scope);
return Collections2.filter(context.getKeys(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR), new Predicate<String>() {
@Override
public boolean apply(@Nullable String fqName) {
return fqName != null && (fqName.endsWith('.' + name) || fqName.equals(name));
}
});
}
@NotNull
@Override
public PsiMethod[] getMethodsByName(@NonNls @NotNull String name, @NotNull GlobalSearchScope scope) {
return new PsiMethod[0];
}
@NotNull
@Override
public PsiMethod[] getMethodsByNameIfNotMoreThan(@NonNls @NotNull String name, @NotNull GlobalSearchScope scope, int maxCount) {
return new PsiMethod[0];
}
@NotNull
@Override
public String[] getAllMethodNames() {
return new String[0];
}
@Override
public void getAllMethodNames(@NotNull HashSet<String> set) {
}
@NotNull
@Override
public PsiField[] getFieldsByName(@NotNull @NonNls String name, @NotNull GlobalSearchScope scope) {
return new PsiField[0];
}
@NotNull
@Override
public String[] getAllFieldNames() {
return new String[0];
}
@Override
public void getAllFieldNames(@NotNull HashSet<String> set) {
}
}
@@ -9,8 +9,10 @@ import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.asJava.JetFileUtil;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
@@ -63,9 +65,13 @@ public final class WholeProjectAnalyzerFacade {
}
};
@NotNull
public static BindingContext analyzeProjectWithCacheOnAFile(@NotNull JetFile file) {
return AnalyzerFacade.analyzeFileWithCache(file, WHOLE_PROJECT_DECLARATION_PROVIDER);
}
@NotNull
public static BindingContext analyzeProjectWithCache(@NotNull Project project, @NotNull GlobalSearchScope scope) {
return AnalyzerFacade.analyzeProjectWithCache(project, JetFileUtil.collectJetFiles(project, scope));
}
}
@@ -0,0 +1,85 @@
package org.jetbrains.jet.plugin.completion;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler;
import org.jetbrains.jet.resolve.DescriptorRenderer;
/**
* @author Nikolay Krasko
*/
public final class DescriptorLookupConverter {
private final static JetFunctionInsertHandler EMPTY_FUNCTION_HANDLER = new JetFunctionInsertHandler(
JetFunctionInsertHandler.CaretPosition.AFTER_BRACKETS);
private final static JetFunctionInsertHandler PARAMS_FUNCTION_HANDLER = new JetFunctionInsertHandler(
JetFunctionInsertHandler.CaretPosition.IN_BRACKETS);
@NotNull
public static LookupElement createLookupElement(@NotNull DeclarationDescriptor descriptor, @Nullable PsiElement declaration) {
LookupElementBuilder element = LookupElementBuilder.create(descriptor, descriptor.getName());
String typeText = "";
String tailText = "";
boolean tailTextGrayed = false;
if (descriptor instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
JetType returnType = functionDescriptor.getReturnType();
typeText = DescriptorRenderer.TEXT.renderType(returnType);
tailText = "(" + StringUtil.join(functionDescriptor.getValueParameters(), new Function<ValueParameterDescriptor, String>() {
@Override
public String fun(ValueParameterDescriptor valueParameterDescriptor) {
return valueParameterDescriptor.getName() + ":" +
DescriptorRenderer.TEXT.renderType(valueParameterDescriptor.getOutType());
}
}, ",") + ")";
// TODO: A special case when it's impossible to resolve type parameters from arguments. Need '<' caret '>'
// TODO: Support omitting brackets for one argument functions
if (functionDescriptor.getValueParameters().isEmpty()) {
element = element.setInsertHandler(EMPTY_FUNCTION_HANDLER);
} else {
element = element.setInsertHandler(PARAMS_FUNCTION_HANDLER);
}
}
else if (descriptor instanceof VariableDescriptor) {
JetType outType = ((VariableDescriptor) descriptor).getOutType();
typeText = DescriptorRenderer.TEXT.renderType(outType);
}
else if (descriptor instanceof ClassDescriptor) {
tailText = " (" + DescriptorUtils.getFQName(descriptor.getContainingDeclaration()) + ")";
tailTextGrayed = true;
}
else {
typeText = DescriptorRenderer.TEXT.render(descriptor);
}
element = element.setTailText(tailText, tailTextGrayed).setTypeText(typeText);
if (declaration != null) {
element = element.setIcon(declaration.getIcon(Iconable.ICON_FLAG_OPEN | Iconable.ICON_FLAG_VISIBILITY));
}
return element;
}
@NotNull
public static LookupElement createLookupElement(@NotNull BindingContext bindingContext, @NotNull DeclarationDescriptor descriptor) {
return createLookupElement(descriptor, bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor.getOriginal()));
}
}
@@ -2,17 +2,22 @@ package org.jetbrains.jet.plugin.completion;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.project.Project;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.Consumer;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetQualifiedExpression;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.psi.JetUserType;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.caches.JetCacheManager;
import java.util.Collection;
/**
* @author Nikolay Krasko
@@ -23,9 +28,9 @@ public class JetCompletionContributor extends CompletionContributor {
new CompletionProvider<CompletionParameters>() {
@Override
protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context,
final @NotNull CompletionResultSet _result) {
final @NotNull CompletionResultSet result) {
if (_result.getPrefixMatcher().getPrefix().isEmpty()) {
if (result.getPrefixMatcher().getPrefix().isEmpty()) {
return;
}
@@ -34,23 +39,55 @@ public class JetCompletionContributor extends CompletionContributor {
return;
}
CompletionResultSet result = _result.withPrefixMatcher(CompletionUtil.findReferenceOrAlphanumericPrefix(parameters));
if (shouldRunClassNameCompletion(parameters, context)) {
JavaClassNameCompletionContributor.addAllClasses(parameters, JavaCompletionSorting.addJavaSorting(
parameters, result), parameters.getInvocationCount() <= 1, new Consumer<LookupElement>() {
@Override
public void consume(LookupElement element) {
_result.addElement(element);
}
});
addJavaClasses(parameters, result);
addJetClasses(result, position);
}
}
});
}
private static void addJetClasses(CompletionResultSet result, PsiElement position) {
if (position.getParent() instanceof JetSimpleNameExpression) {
final JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) position.getParent();
if (PsiTreeUtil.getParentOfType(nameExpression, JetQualifiedExpression.class) == null) {
Project project = position.getProject();
final String referencedName = nameExpression.getReferencedName();
if (referencedName != null && referencedName.endsWith(CompletionInitializationContext.DUMMY_IDENTIFIER_TRIMMED)) {
int lastPrefixIndex = referencedName.length() -
CompletionInitializationContext.DUMMY_IDENTIFIER_TRIMMED.length();
String actualPrefix = referencedName.substring(0, lastPrefixIndex);
final Collection<ClassDescriptor> classDescriptors =
JetCacheManager.getInstance(project).getNamesCache().getClassDescriptors();
for (ClassDescriptor descriptor : classDescriptors) {
if (descriptor.getName().startsWith(actualPrefix)) {
result.addElement(DescriptorLookupConverter.createLookupElement(descriptor, null));
}
}
}
}
}
}
private static void addJavaClasses(CompletionParameters parameters, final CompletionResultSet result) {
CompletionResultSet tempResult = result.withPrefixMatcher(CompletionUtil.findReferenceOrAlphanumericPrefix(parameters));
JavaClassNameCompletionContributor.addAllClasses(parameters, JavaCompletionSorting.addJavaSorting(
parameters, tempResult), parameters.getInvocationCount() <= 1, new Consumer<LookupElement>() {
@Override
public void consume(LookupElement element) {
result.addElement(element);
}
});
}
private static boolean shouldRunClassNameCompletion(@NotNull CompletionParameters parameters, ProcessingContext context) {
final PsiElement element = parameters.getPosition();
@@ -75,4 +112,9 @@ public class JetCompletionContributor extends CompletionContributor {
return false;
}
@Override
public void beforeCompletion(@NotNull CompletionInitializationContext context) {
super.beforeCompletion(context); //To change body of overridden methods use File | Settings | File Templates.
}
}
@@ -1,7 +1,6 @@
package org.jetbrains.jet.plugin.quickfix;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@@ -25,10 +24,9 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.plugin.JetFileType;
import org.jetbrains.jet.plugin.actions.JetAddImportAction;
import org.jetbrains.jet.plugin.caches.JetCacheManager;
import java.util.Collection;
import java.util.Collections;
@@ -56,31 +54,29 @@ public class ImportClassFix extends JetHintAction<JetSimpleNameExpression> imple
return Collections.emptyList();
}
final BindingContext context = AnalyzerFacade.analyzeFileWithCache(
(JetFile) file, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER);
return getClassNames(element, context, file.getProject());
return getClassNames(element, file.getProject());
}
/*
* Searches for possible class names in kotlin context and java facade.
*/
public static List<String> getClassNames(@NotNull JetSimpleNameExpression expression, @NotNull BindingContext context, @NotNull Project project) {
public static List<String> getClassNames(@NotNull JetSimpleNameExpression expression, @NotNull Project project) {
final String referenceName = expression.getReferencedName();
if (referenceName == null) {
return Collections.emptyList();
}
final GlobalSearchScope scope = GlobalSearchScope.allScope(project);
Set<String> possibleResolveNames = Sets.newHashSet();
possibleResolveNames.addAll(filterPossibleTypes(referenceName, context.getKeys(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR)));
possibleResolveNames.addAll(getJavaClasses(referenceName, project));
possibleResolveNames.addAll(JetCacheManager.getInstance(project).getNamesCache().getFQNamesByName(referenceName, scope));
possibleResolveNames.addAll(getJavaClasses(referenceName, project, scope));
// TODO: Do appropriate sorting
return Lists.newArrayList(possibleResolveNames);
}
private static Collection<String> getJavaClasses(@NotNull final String typeName, @NotNull Project project) {
private static Collection<String> getJavaClasses(@NotNull final String typeName, @NotNull Project project, final GlobalSearchScope scope) {
PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project);
PsiClass[] classes = cache.getClassesByName(typeName, new DelegatingGlobalSearchScope(GlobalSearchScope.allScope(project)) {
@@ -100,16 +96,6 @@ public class ImportClassFix extends JetHintAction<JetSimpleNameExpression> imple
});
}
@NotNull
private static Collection<String> filterPossibleTypes(@NotNull final String typeName, @NotNull Collection<String> variants) {
return Collections2.filter(variants, new Predicate<String>() {
@Override
public boolean apply(@Nullable String fqName) {
return fqName != null && (fqName.endsWith('.' + typeName) || fqName.equals(typeName));
}
});
}
@Override
public boolean showHint(@NotNull Editor editor) {
if (suggestions.isEmpty()) {
@@ -2,23 +2,18 @@ package org.jetbrains.jet.plugin.references;
import com.google.common.collect.Lists;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
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.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetPsiFactory;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler;
import org.jetbrains.jet.resolve.DescriptorRenderer;
import org.jetbrains.jet.plugin.completion.DescriptorLookupConverter;
import java.util.List;
@@ -27,12 +22,6 @@ import java.util.List;
*/
class JetSimpleNameReference extends JetPsiReference {
private final static JetFunctionInsertHandler EMPTY_FUNCTION_HANDLER = new JetFunctionInsertHandler(
JetFunctionInsertHandler.CaretPosition.AFTER_BRACKETS);
private final static JetFunctionInsertHandler PARAMS_FUNCTION_HANDLER = new JetFunctionInsertHandler(
JetFunctionInsertHandler.CaretPosition.IN_BRACKETS);
private final JetSimpleNameExpression myExpression;
public JetSimpleNameReference(JetSimpleNameExpression jetSimpleNameExpression) {
@@ -71,54 +60,9 @@ class JetSimpleNameReference extends JetPsiReference {
List<LookupElement> result = Lists.newArrayList();
for (final DeclarationDescriptor descriptor : descriptors) {
LookupElementBuilder element = LookupElementBuilder.create(descriptor, descriptor.getName());
String typeText = "";
String tailText = "";
boolean tailTextGrayed = false;
if (descriptor instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
JetType returnType = functionDescriptor.getReturnType();
typeText = DescriptorRenderer.TEXT.renderType(returnType);
tailText = "(" + StringUtil.join(functionDescriptor.getValueParameters(), new Function<ValueParameterDescriptor, String>() {
@Override
public String fun(ValueParameterDescriptor valueParameterDescriptor) {
return valueParameterDescriptor.getName() + ":" +
DescriptorRenderer.TEXT.renderType(valueParameterDescriptor.getOutType());
}
}, ",") + ")";
// TODO: A special case when it's impossible to resolve type parameters from arguments. Need '<' caret '>'
// TODO: Support omitting brackets for one argument functions
if (functionDescriptor.getValueParameters().isEmpty()) {
element = element.setInsertHandler(EMPTY_FUNCTION_HANDLER);
} else {
element = element.setInsertHandler(PARAMS_FUNCTION_HANDLER);
}
}
else if (descriptor instanceof VariableDescriptor) {
JetType outType = ((VariableDescriptor) descriptor).getOutType();
typeText = DescriptorRenderer.TEXT.renderType(outType);
}
else if (descriptor instanceof ClassDescriptor) {
tailText = " (" + DescriptorUtils.getFQName(descriptor.getContainingDeclaration()) + ")";
tailTextGrayed = true;
}
else {
typeText = DescriptorRenderer.TEXT.render(descriptor);
}
element = element.setTailText(tailText, tailTextGrayed).setTypeText(typeText);
PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor.getOriginal());
if (declaration != null) {
element = element.setIcon(declaration.getIcon(Iconable.ICON_FLAG_OPEN | Iconable.ICON_FLAG_VISIBILITY));
}
result.add(element);
result.add(DescriptorLookupConverter.createLookupElement(bindingContext, descriptor));
}
return result.toArray();
}
}