move smart completion assignability checking closer to reference processor to fix
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInsight / completion / BasicExpressionCompletionContributor.java
blobdbe8eb18d240ae63f7defdcddc8460f51e7c0500
1 /*
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.guess.GuessManager;
19 import com.intellij.codeInsight.lookup.*;
20 import com.intellij.codeInsight.lookup.KeywordLookupItem;
21 import com.intellij.codeInsight.lookup.VariableLookupItem;
22 import com.intellij.codeInsight.template.SmartCompletionContextType;
23 import com.intellij.codeInsight.template.impl.TemplateImpl;
24 import com.intellij.codeInsight.template.impl.TemplateSettings;
25 import com.intellij.openapi.application.ApplicationManager;
26 import com.intellij.openapi.util.Computable;
27 import com.intellij.patterns.PsiJavaPatterns;
28 import static com.intellij.patterns.PsiJavaPatterns.psiClass;
29 import static com.intellij.patterns.PsiJavaPatterns.psiElement;
30 import static com.intellij.patterns.StandardPatterns.not;
31 import com.intellij.psi.*;
32 import com.intellij.psi.filters.ContextGetter;
33 import com.intellij.psi.filters.element.ExcludeDeclaredFilter;
34 import com.intellij.psi.filters.getters.ClassLiteralGetter;
35 import com.intellij.psi.filters.getters.FilterGetter;
36 import com.intellij.psi.filters.getters.MembersGetter;
37 import com.intellij.psi.filters.getters.ThisGetter;
38 import com.intellij.psi.scope.BaseScopeProcessor;
39 import com.intellij.psi.scope.ElementClassFilter;
40 import com.intellij.psi.scope.util.PsiScopesUtil;
41 import com.intellij.psi.util.PsiTreeUtil;
42 import com.intellij.util.Consumer;
43 import com.intellij.util.IncorrectOperationException;
44 import com.intellij.util.ProcessingContext;
45 import org.jetbrains.annotations.NotNull;
46 import org.jetbrains.annotations.Nullable;
48 import java.util.Map;
50 /**
51 * @author peter
53 public class BasicExpressionCompletionContributor extends ExpressionSmartCompletionContributor{
55 private static void addKeyword(final CompletionResultSet result, final PsiElement element, final String s) {
56 result.addElement(createKeywordLookupItem(element, s));
59 public static LookupElement createKeywordLookupItem(final PsiElement element, final String s) {
60 return ApplicationManager.getApplication().runReadAction(new Computable<LookupItem>() {
61 public LookupItem compute() {
62 try {
63 final PsiKeyword keyword = JavaPsiFacade.getInstance(element.getProject()).getElementFactory().createKeyword(s);
64 return new KeywordLookupItem(keyword, element).setAutoCompletionPolicy(AutoCompletionPolicy.GIVE_CHANCE_TO_OVERWRITE);
66 catch (IncorrectOperationException e) {
67 throw new RuntimeException(e);
70 });
74 public BasicExpressionCompletionContributor() {
75 extend(PsiJavaPatterns.psiElement().afterLeaf(
76 PsiJavaPatterns.psiElement().withText(".").afterLeaf(
77 PsiJavaPatterns.psiElement().withParent(
78 PsiJavaPatterns.psiElement().referencing(psiClass())))), new CompletionProvider<JavaSmartCompletionParameters>() {
79 public void addCompletions(@NotNull final JavaSmartCompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
80 final PsiElement element = parameters.getPosition();
81 addKeyword(result, element, PsiKeyword.CLASS);
82 addKeyword(result, element, PsiKeyword.THIS);
85 });
87 extend(not(psiElement().afterLeaf(".")), new CollectionsUtilityMethodsProvider());
89 extend(not(psiElement().afterLeaf(".")), new CompletionProvider<JavaSmartCompletionParameters>() {
90 protected void addCompletions(@NotNull final JavaSmartCompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
91 final PsiElement position = parameters.getPosition();
92 final PsiType expectedType = parameters.getExpectedType();
93 final FilterGetter baseGetter = new FilterGetter(new ContextGetter() {
94 public Object[] get(final PsiElement context, final CompletionContext completionContext) {
95 return new Object[]{expectedType};
97 }, new ExcludeDeclaredFilter(ElementClassFilter.CLASS));
98 for (final LookupElement element : ClassLiteralGetter.getClassLiterals(position, null, result.getPrefixMatcher(), baseGetter)) {
99 result.addElement(element);
102 for (final TemplateImpl template : TemplateSettings.getInstance().getTemplates()) {
103 if (!template.isDeactivated() && template.getTemplateContext().isEnabled(new SmartCompletionContextType())) {
104 result.addElement(new SmartCompletionTemplateItem(template, position));
108 addKeyword(result, position, PsiKeyword.TRUE);
109 addKeyword(result, position, PsiKeyword.FALSE);
111 final PsiElement parent = position.getParent();
112 if (parent != null && !(parent.getParent() instanceof PsiSwitchLabelStatement)) {
113 MembersGetter.addMembers(parameters.getPosition(), expectedType, result);
114 if (!parameters.getDefaultType().equals(expectedType)) {
115 MembersGetter.addMembers(parameters.getPosition(), parameters.getDefaultType(), result);
118 for (final PsiExpression expression : ThisGetter.getThisExpressionVariants(position)) {
119 result.addElement(new ExpressionLookupItem(expression));
123 processDataflowExpressionTypes(position, expectedType, result.getPrefixMatcher(), new Consumer<LookupElement>() {
124 public void consume(LookupElement decorator) {
125 result.addElement(decorator);
133 public static void processDataflowExpressionTypes(PsiElement position, @Nullable PsiType expectedType, final PrefixMatcher matcher, Consumer<LookupElement> consumer) {
134 final PsiExpression context = PsiTreeUtil.getParentOfType(position, PsiExpression.class);
135 if (context == null) return;
137 final Map<PsiExpression,PsiType> map = GuessManager.getInstance(position.getProject()).getControlFlowExpressionTypes(context);
138 if (map.isEmpty()) {
139 return;
142 PsiScopesUtil.treeWalkUp(new BaseScopeProcessor() {
143 public boolean execute(PsiElement element, ResolveState state) {
144 if (element instanceof PsiLocalVariable) {
145 if (!matcher.prefixMatches(((PsiLocalVariable)element).getName())) {
146 return true;
149 final PsiExpression expression = ((PsiLocalVariable)element).getInitializer();
150 if (expression instanceof PsiTypeCastExpression) {
151 PsiTypeCastExpression typeCastExpression = (PsiTypeCastExpression)expression;
152 final PsiExpression operand = typeCastExpression.getOperand();
153 if (operand != null) {
154 final PsiType dfaCasted = map.get(operand);
155 if (dfaCasted != null && dfaCasted.equals(typeCastExpression.getType())) {
156 map.remove(operand);
161 return true;
163 }, context, context.getContainingFile());
165 for (final PsiExpression expression : map.keySet()) {
166 final PsiType castType = map.get(expression);
167 final PsiType baseType = expression.getType();
168 if (expectedType == null || (expectedType.isAssignableFrom(castType) && (baseType == null || !expectedType.isAssignableFrom(baseType)))) {
169 consumer.consume(CastingLookupElementDecorator.createCastingElement(expressionToLookupElement(expression), castType));
174 @NotNull
175 private static LookupElement expressionToLookupElement(@NotNull PsiExpression expression) {
176 if (expression instanceof PsiReferenceExpression) {
177 final PsiReferenceExpression refExpr = (PsiReferenceExpression)expression;
178 if (!refExpr.isQualified()) {
179 final PsiElement target = refExpr.resolve();
180 if (target instanceof PsiVariable) {
181 final VariableLookupItem item = new VariableLookupItem((PsiVariable)target);
182 item.setSubstitutor(PsiSubstitutor.EMPTY);
183 return item;
187 if (expression instanceof PsiMethodCallExpression) {
188 final PsiMethodCallExpression call = (PsiMethodCallExpression)expression;
189 if (!call.getMethodExpression().isQualified()) {
190 final PsiMethod method = call.resolveMethod();
191 if (method != null) {
192 return new JavaMethodCallElement(method);
197 return new ExpressionLookupItem(expression);