2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.codeInsight
.completion
;
18 import com
.intellij
.codeInsight
.ExpectedTypeInfo
;
19 import com
.intellij
.codeInsight
.ExpectedTypesProvider
;
20 import com
.intellij
.openapi
.application
.ApplicationManager
;
21 import com
.intellij
.openapi
.project
.Project
;
22 import com
.intellij
.openapi
.util
.Computable
;
23 import com
.intellij
.openapi
.util
.text
.StringUtil
;
24 import com
.intellij
.openapi
.editor
.Editor
;
25 import com
.intellij
.openapi
.actionSystem
.IdeActions
;
26 import com
.intellij
.patterns
.PsiJavaElementPattern
;
27 import static com
.intellij
.patterns
.PsiJavaPatterns
.psiElement
;
28 import com
.intellij
.psi
.*;
29 import com
.intellij
.psi
.filters
.ClassFilter
;
30 import com
.intellij
.psi
.filters
.TrueFilter
;
31 import com
.intellij
.psi
.filters
.classes
.ThisOrAnyInnerFilter
;
32 import com
.intellij
.psi
.filters
.element
.ExcludeDeclaredFilter
;
33 import com
.intellij
.psi
.filters
.types
.AssignableFromFilter
;
34 import com
.intellij
.psi
.statistics
.StatisticsInfo
;
35 import com
.intellij
.psi
.statistics
.StatisticsManager
;
36 import com
.intellij
.psi
.util
.PsiTreeUtil
;
37 import com
.intellij
.psi
.util
.PsiUtil
;
38 import com
.intellij
.util
.ProcessingContext
;
39 import com
.intellij
.lang
.StdLanguages
;
40 import com
.intellij
.lang
.LangBundle
;
41 import org
.jetbrains
.annotations
.NotNull
;
46 public class JavaClassNameCompletionContributor
extends CompletionContributor
{
47 private static final PsiJavaElementPattern
.Capture
<PsiElement
> AFTER_THROW_NEW
= psiElement().afterLeaf(
48 psiElement().withText(PsiKeyword
.NEW
).afterLeaf(PsiKeyword
.THROW
));
49 private static final PsiJavaElementPattern
.Capture
<PsiElement
> AFTER_NEW
= psiElement().afterLeaf(PsiKeyword
.NEW
);
50 private static final PsiJavaElementPattern
.Capture
<PsiElement
> IN_TYPE_PARAMETER
=
51 psiElement().afterLeaf(PsiKeyword
.EXTENDS
, PsiKeyword
.SUPER
, "&").withParent(
52 psiElement(PsiReferenceList
.class).withParent(PsiTypeParameter
.class));
53 private static final PsiJavaElementPattern
.Capture
<PsiElement
> INSIDE_METHOD_THROWS_CLAUSE
= psiElement().afterLeaf(PsiKeyword
.THROWS
, ",").inside(
54 PsiMethod
.class).andNot(psiElement().inside(PsiCodeBlock
.class)).andNot(psiElement().inside(PsiParameterList
.class));
56 public JavaClassNameCompletionContributor() {
57 extend(CompletionType
.CLASS_NAME
, psiElement(), new CompletionProvider
<CompletionParameters
>(false) {
58 public void addCompletions(@NotNull final CompletionParameters parameters
, final ProcessingContext matchingContext
, @NotNull final CompletionResultSet result
) {
59 PsiElement insertedElement
= parameters
.getPosition();
60 String prefix
= result
.getPrefixMatcher().getPrefix();
62 final PsiFile file
= parameters
.getOriginalFile();
63 final Project project
= file
.getProject();
65 AllClassesGetter getter
= new AllClassesGetter(TrueFilter
.INSTANCE
);
66 boolean afterNew
= AFTER_NEW
.accepts(insertedElement
);
67 if (AFTER_THROW_NEW
.accepts(insertedElement
)) {
68 getter
= new AllClassesGetter(new AssignableFromFilter("java.lang.Throwable"));
70 else if (IN_TYPE_PARAMETER
.accepts(insertedElement
)) {
71 getter
= new AllClassesGetter(new ExcludeDeclaredFilter(new ClassFilter(PsiTypeParameter
.class)));
73 else if (INSIDE_METHOD_THROWS_CLAUSE
.accepts(insertedElement
)) {
74 getter
= new AllClassesGetter(new ThisOrAnyInnerFilter(new AssignableFromFilter("java.lang.Throwable")));
77 final StatisticsInfo
[] infos
=
78 StatisticsManager
.getInstance().getAllValues(JavaCompletionStatistician
.CLASS_NAME_COMPLETION_PREFIX
+ StringUtil
.capitalsOnly(prefix
));
79 for (final StatisticsInfo info
: infos
) {
80 final PsiClass
[] classes
= ApplicationManager
.getApplication().runReadAction(new Computable
<PsiClass
[]>() {
81 public PsiClass
[] compute() {
82 return JavaPsiFacade
.getInstance(project
).findClasses(info
.getValue(), file
.getResolveScope());
85 for (final PsiClass psiClass
: classes
) {
86 final boolean isExcluded
= ApplicationManager
.getApplication().runReadAction(new Computable
<Boolean
>() {
87 public Boolean
compute() {
88 return JavaCompletionUtil
.isInExcludedPackage(psiClass
);
92 result
.addElement(AllClassesGetter
.createLookupItem(psiClass
));
98 final PsiExpression expr
= PsiTreeUtil
.getContextOfType(insertedElement
, PsiExpression
.class, true);
100 ApplicationManager
.getApplication().runReadAction(new Runnable() {
102 for (final ExpectedTypeInfo info
: ExpectedTypesProvider
.getInstance(project
).getExpectedTypes(expr
, true)) {
103 final PsiType type
= info
.getType();
104 final PsiClass psiClass
= PsiUtil
.resolveClassInType(type
);
105 if (psiClass
!= null) {
106 result
.addElement(AllClassesGetter
.createLookupItem(psiClass
));
108 final PsiType defaultType
= info
.getDefaultType();
109 if (!defaultType
.equals(type
)) {
110 final PsiClass defClass
= PsiUtil
.resolveClassInType(defaultType
);
111 if (defClass
!= null) {
112 result
.addElement(AllClassesGetter
.createLookupItem(defClass
));
121 getter
.getClasses(insertedElement
, result
, parameters
.getOffset(), parameters
.getInvocationCount() == 1);
127 public String
advertise(@NotNull final CompletionParameters parameters
) {
128 if (shouldShowSecondSmartCompletionHint(parameters
) &&
129 CompletionUtil
.shouldShowFeature(parameters
, CodeCompletionFeatures
.SECOND_CLASS_NAME_COMPLETION
)) {
130 return CompletionBundle
.message("completion.class.name.hint.2", getActionShortcut(IdeActions
.ACTION_CLASS_NAME_COMPLETION
));
137 public String
handleEmptyLookup(@NotNull final CompletionParameters parameters
, final Editor editor
) {
138 if (!(parameters
.getOriginalFile() instanceof PsiJavaFile
)) return null;
140 if (shouldShowSecondSmartCompletionHint(parameters
)) {
141 return LangBundle
.message("completion.no.suggestions") +
143 StringUtil
.decapitalize(
144 CompletionBundle
.message("completion.class.name.hint.2", getActionShortcut(IdeActions
.ACTION_CLASS_NAME_COMPLETION
)));
150 private static boolean shouldShowSecondSmartCompletionHint(final CompletionParameters parameters
) {
151 return parameters
.getCompletionType() == CompletionType
.CLASS_NAME
&&
152 parameters
.getInvocationCount() == 1 &&
153 parameters
.getOriginalFile().getLanguage() == StdLanguages
.JAVA
;