diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java index d99e9a0b500..18372585335 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java @@ -40,6 +40,12 @@ public class AnalyzerFacade { private final static Key> 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> 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 compute() { try { - BindingContext bindingContext = analyzeFilesWithJavaIntegration(file.getProject(), declarationProvider.fun(file), Predicates.equalTo(file), JetControlFlowDataTraceFactory.EMPTY); + BindingContext bindingContext = analyzeFilesWithJavaIntegration( + file.getProject(), + declarationProvider.fun(file), + Predicates.equalTo(file), + JetControlFlowDataTraceFactory.EMPTY); return new Result(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 files) { + // Need lock for getValue(), because parallel threads can start evaluation of compute() simultaneously + synchronized (lock) { + CachedValue bindingContextCachedValue = project.getUserData(BINDING_CONTEXT); + if (bindingContextCachedValue == null) { + bindingContextCachedValue = CachedValuesManager.getManager(project).createCachedValue(new CachedValueProvider() { + @Override + public Result compute() { + try { + BindingContext bindingContext = analyzeFilesWithJavaIntegration( + project, + files, + Predicates.alwaysFalse(), + JetControlFlowDataTraceFactory.EMPTY); + return new Result(bindingContext, PsiModificationTracker.MODIFICATION_COUNT); + } + catch (ProcessCanceledException e) { + throw e; + } + catch (Throwable e) { + DiagnosticUtils.throwIfRunningOnServer(e); + e.printStackTrace(); + BindingTraceContext bindingTraceContext = new BindingTraceContext(); + return new Result(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.alwaysTrue(), flowDataTraceFactory); } - public static BindingContext analyzeFilesWithJavaIntegration(Project project, Collection files, Predicate filesToAnalyzeCompletely, JetControlFlowDataTraceFactory flowDataTraceFactory) { + public static BindingContext analyzeFilesWithJavaIntegration(Project project, Collection files, Predicate filesToAnalyzeCompletely, + JetControlFlowDataTraceFactory flowDataTraceFactory) { BindingTraceContext bindingTraceContext = new BindingTraceContext(); JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project); return AnalyzingUtils.analyzeFilesWithGivenTrace( diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JavaElementFinder.java b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JavaElementFinder.java index 2c35264eb99..4c085ebebfe 100644 --- a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JavaElementFinder.java +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JavaElementFinder.java @@ -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 cachedFiles = jetFiles.get(scope); if (cachedFiles == null) { - final List answer = new ArrayList(); - - final FileTypeManager fileTypeManager = FileTypeManager.getInstance(); - - List 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; diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JetFileUtil.java b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JetFileUtil.java new file mode 100644 index 00000000000..873e96dc4fd --- /dev/null +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JetFileUtil.java @@ -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 collectJetFiles(final Project project, @NotNull final GlobalSearchScope scope) { + final List answer = new ArrayList(); + + final FileTypeManager fileTypeManager = FileTypeManager.getInstance(); + List 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; + } +} diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 7fc1597c86e..d4db336e0f4 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -11,6 +11,9 @@ org.jetbrains.jet.plugin.compiler.JetCompilerManager + + org.jetbrains.jet.plugin.caches.JetCacheManager + @@ -74,6 +77,7 @@ + diff --git a/idea/src/org/jetbrains/jet/plugin/caches/JetCacheManager.java b/idea/src/org/jetbrains/jet/plugin/caches/JetCacheManager.java new file mode 100644 index 00000000000..ef7484cfd43 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/caches/JetCacheManager.java @@ -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; + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java b/idea/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java new file mode 100644 index 00000000000..86baba1ba8e --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java @@ -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 dest) { + } + + public List getAllJetClassNames() { + final BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCache(project, GlobalSearchScope.allScope(project)); + final Collection fqNames = context.getKeys(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR); + + final ArrayList classNames = new ArrayList(); + + 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 getClassDescriptors() { + final BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCache(project, GlobalSearchScope.allScope(project)); + + final Collection fqNames = context.getKeys(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR); + return Collections2.transform(fqNames, new Function() { + @Override + public ClassDescriptor apply(String fqName) { + return context.get(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, fqName); + } + }); + } + + public List getJetClassesByName(@NotNull String name, @NotNull GlobalSearchScope scope) { + final BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCache(project, scope); + final ArrayList classesResult = new ArrayList(); + + 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 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() { + @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 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 set) { + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java b/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java index e9ad46da98a..5097a0a2d75 100644 --- a/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java +++ b/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java @@ -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)); + } } diff --git a/idea/src/org/jetbrains/jet/plugin/completion/DescriptorLookupConverter.java b/idea/src/org/jetbrains/jet/plugin/completion/DescriptorLookupConverter.java new file mode 100644 index 00000000000..f587a398ae8 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/completion/DescriptorLookupConverter.java @@ -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() { + @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())); + } + + +} diff --git a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java index 5f2d750ed5d..6c6535e4b4e 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java +++ b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java @@ -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() { @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() { - - @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 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() { + + @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. + } } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassFix.java index 1d702684e31..674bbfae967 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassFix.java @@ -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 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 getClassNames(@NotNull JetSimpleNameExpression expression, @NotNull BindingContext context, @NotNull Project project) { + public static List 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 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 getJavaClasses(@NotNull final String typeName, @NotNull Project project) { + private static Collection 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 imple }); } - @NotNull - private static Collection filterPossibleTypes(@NotNull final String typeName, @NotNull Collection variants) { - return Collections2.filter(variants, new Predicate() { - @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()) { diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java index a0a42cfeee2..d5b61a48dd6 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java @@ -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 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() { - @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(); } }