32808d2f7520738c0628064ef31b2758bd2f995f
[idea/community.git] / java / java-impl / src / com / intellij / codeInsight / completion / JavaSmartCompletionContributor.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.intellij.codeInsight.completion;
17
18 import com.intellij.codeInsight.*;
19 import com.intellij.codeInsight.ExceptionUtil;
20 import com.intellij.codeInsight.lookup.*;
21 import com.intellij.openapi.application.ApplicationManager;
22 import com.intellij.openapi.util.Computable;
23 import com.intellij.openapi.util.Condition;
24 import com.intellij.openapi.util.Key;
25 import com.intellij.openapi.util.Pair;
26 import com.intellij.patterns.ElementPattern;
27 import com.intellij.patterns.PsiJavaPatterns;
28 import com.intellij.psi.*;
29 import com.intellij.psi.filters.ElementExtractorFilter;
30 import com.intellij.psi.filters.ElementFilter;
31 import com.intellij.psi.filters.GeneratorFilter;
32 import com.intellij.psi.filters.OrFilter;
33 import com.intellij.psi.filters.getters.CastTypeGetter;
34 import com.intellij.psi.filters.getters.ExpectedTypesGetter;
35 import com.intellij.psi.filters.getters.InstanceOfLeftPartTypeGetter;
36 import com.intellij.psi.filters.getters.ThrowsListGetter;
37 import com.intellij.psi.filters.types.AssignableFromFilter;
38 import com.intellij.psi.filters.types.AssignableGroupFilter;
39 import com.intellij.psi.filters.types.AssignableToFilter;
40 import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference;
41 import com.intellij.psi.infos.CandidateInfo;
42 import com.intellij.psi.javadoc.PsiDocTag;
43 import com.intellij.psi.statistics.JavaStatisticsManager;
44 import com.intellij.psi.statistics.StatisticsInfo;
45 import com.intellij.psi.statistics.StatisticsManager;
46 import com.intellij.psi.util.InheritanceUtil;
47 import com.intellij.psi.util.PsiTreeUtil;
48 import com.intellij.psi.util.PsiUtil;
49 import com.intellij.psi.util.TypeConversionUtil;
50 import com.intellij.util.*;
51 import com.intellij.util.containers.ContainerUtil;
52 import gnu.trove.THashSet;
53 import gnu.trove.TObjectHashingStrategy;
54 import org.jetbrains.annotations.NonNls;
55 import org.jetbrains.annotations.NotNull;
56 import org.jetbrains.annotations.Nullable;
57
58 import java.util.*;
59
60 import static com.intellij.patterns.PlatformPatterns.psiElement;
61 import static com.intellij.patterns.PsiJavaPatterns.psiMethod;
62 import static com.intellij.patterns.StandardPatterns.*;
63
64 /**
65  * @author peter
66  */
67 public class JavaSmartCompletionContributor extends CompletionContributor {
68   private static final TObjectHashingStrategy<ExpectedTypeInfo> EXPECTED_TYPE_INFO_STRATEGY = new TObjectHashingStrategy<ExpectedTypeInfo>() {
69     public int computeHashCode(final ExpectedTypeInfo object) {
70       return object.getType().hashCode();
71     }
72
73     public boolean equals(final ExpectedTypeInfo o1, final ExpectedTypeInfo o2) {
74       return o1.getType().equals(o2.getType());
75     }
76   };
77
78   private static final ElementExtractorFilter THROWABLES_FILTER = new ElementExtractorFilter(new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE));
79   @NonNls private static final String EXCEPTION_TAG = "exception";
80   static final ElementPattern<PsiElement> AFTER_NEW =
81       psiElement().afterLeaf(
82           psiElement().withText(PsiKeyword.NEW).andNot(
83               psiElement().afterLeaf(
84                   psiElement().withText(PsiKeyword.THROW))));
85   static final ElementPattern<PsiElement> AFTER_THROW_NEW =
86       psiElement().afterLeaf(
87           psiElement().withText(PsiKeyword.NEW).afterLeaf(
88               psiElement().withText(PsiKeyword.THROW)));
89   private static final OrFilter THROWABLE_TYPE_FILTER = new OrFilter(
90       new GeneratorFilter(AssignableGroupFilter.class, new ThrowsListGetter()),
91       new AssignableFromFilter("java.lang.RuntimeException"));
92   public static final ElementPattern<PsiElement> INSIDE_EXPRESSION = or(
93         psiElement().withParent(PsiExpression.class).andNot(psiElement().withParent(PsiLiteralExpression.class)),
94         psiElement().inside(PsiClassObjectAccessExpression.class),
95         psiElement().inside(PsiThisExpression.class),
96         psiElement().inside(PsiSuperExpression.class)
97         );
98   static final ElementPattern<PsiElement> INSIDE_TYPECAST_EXPRESSION = psiElement().withParent(
99     psiElement(PsiReferenceExpression.class).afterLeaf(
100       psiElement().withText(")").withParent(PsiTypeCastExpression.class)));
101
102   @Nullable
103   private static ElementFilter getReferenceFilter(PsiElement element) {
104     //throw new foo
105     if (AFTER_THROW_NEW.accepts(element)) {
106       return new ElementExtractorFilter(THROWABLE_TYPE_FILTER);
107     }
108
109     //new xxx.yyy
110     if (psiElement().afterLeaf(psiElement().withText(".")).withSuperParent(2, psiElement(PsiNewExpression.class)).accepts(element)) {
111       if (((PsiNewExpression)element.getParent().getParent()).getClassReference() == element.getParent()) {
112         return new GeneratorFilter(AssignableGroupFilter.class, new ExpectedTypesGetter());
113       }
114     }
115
116     return null;
117   }
118
119
120
121   public JavaSmartCompletionContributor() {
122     extend(CompletionType.SMART, SmartCastProvider.INSIDE_TYPECAST_TYPE, new SmartCastProvider());
123
124     extend(CompletionType.SMART,
125            psiElement().beforeLeaf(psiElement(JavaTokenType.RPARENTH)).afterLeaf("(").withParent(
126              psiElement(PsiReferenceExpression.class).withParent(
127                psiElement(PsiExpressionList.class).withParent(PsiMethodCallExpression.class))), new SameSignatureCallParametersProvider());
128
129     extend(CompletionType.SMART, psiElement().afterLeaf(PsiKeyword.INSTANCEOF), new CompletionProvider<CompletionParameters>(false) {
130       protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
131         final PsiElement position = parameters.getPosition();
132         final PsiType[] leftTypes = ApplicationManager.getApplication().runReadAction(new Computable<PsiType[]>() {
133           public PsiType[] compute() {
134             return InstanceOfLeftPartTypeGetter.getLeftTypes(position);
135           }
136         });
137         final Set<PsiClassType> expectedClassTypes = new LinkedHashSet<PsiClassType>();
138         final Set<PsiClass> parameterizedTypes = new THashSet<PsiClass>();
139         for (final PsiType type : leftTypes) {
140           if (type instanceof PsiClassType) {
141             final PsiClassType classType = (PsiClassType)type;
142             if (!classType.isRaw()) {
143               ContainerUtil.addIfNotNull(classType.resolve(), parameterizedTypes);
144             }
145
146             expectedClassTypes.add(classType.rawType());
147           }
148         }
149
150         processInheritors(parameters, position, position.getContainingFile(), expectedClassTypes, new Consumer<PsiType>() {
151           public void consume(PsiType type) {
152             final PsiClass psiClass = PsiUtil.resolveClassInType(type);
153             if (psiClass == null) return;
154
155             if (expectedClassTypes.contains(type)) return;
156
157             result.addElement(createInstanceofLookupElement(psiClass, parameterizedTypes));
158           }
159         }, result.getPrefixMatcher());
160       }
161     });
162
163     extend(CompletionType.SMART, psiElement(), new CompletionProvider<CompletionParameters>() {
164       protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
165         final PsiElement element = parameters.getPosition();
166         final PsiReference reference = element.getContainingFile().findReferenceAt(parameters.getOffset());
167         if (reference != null) {
168           final ElementFilter filter = getReferenceFilter(element);
169           if (filter != null) {
170             final List<ExpectedTypeInfo> infos = Arrays.asList(getExpectedTypes(parameters));
171             for (final LookupElement item : completeReference(element, reference, filter, true, parameters)) {
172               if (item.getObject() instanceof PsiClass) {
173                 if (AFTER_THROW_NEW.accepts(element)) {
174                   //((LookupItem)item).setAttribute(LookupItem.DONT_CHECK_FOR_INNERS, "");
175                   JavaCompletionUtil.setShowFQN((LookupItem)item);
176                 } else {
177                 }
178                 result.addElement(decorate(LookupElementDecorator.withInsertHandler((LookupItem)item, ConstructorInsertHandler.INSTANCE), infos));
179               }
180             }
181           }
182           else if (INSIDE_TYPECAST_EXPRESSION.accepts(element)) {
183             for (final LookupElement item : completeReference(element, reference, new GeneratorFilter(AssignableToFilter.class, new CastTypeGetter()), false, parameters)) {
184               result.addElement(item);
185             }
186           }
187
188         }
189       }
190     });
191
192     //method throws clause
193     extend(CompletionType.SMART, psiElement().inside(
194       psiElement(PsiReferenceList.class).save("refList").withParent(
195         psiMethod().withThrowsList(get("refList")))), new CompletionProvider<CompletionParameters>() {
196       @Override
197       protected void addCompletions(@NotNull CompletionParameters parameters,
198                                     ProcessingContext context,
199                                     @NotNull CompletionResultSet result) {
200         final PsiElement element = parameters.getPosition();
201         final PsiReference reference = element.getContainingFile().findReferenceAt(parameters.getOffset());
202         assert reference != null;
203         for (final LookupElement item : completeReference(element, reference, THROWABLES_FILTER, true, parameters)) {
204           result.addElement(item);
205         }
206       }
207     });
208
209     extend(CompletionType.SMART, INSIDE_EXPRESSION, new ExpectedTypeBasedCompletionProvider() {
210       protected void addCompletions(final CompletionParameters params, final CompletionResultSet result, final Collection<ExpectedTypeInfo> _infos) {
211         final Set<ExpectedTypeInfo> infos = ApplicationManager.getApplication().runReadAction(new Computable<Set<ExpectedTypeInfo>>() {
212           public Set<ExpectedTypeInfo> compute() {
213             return new THashSet<ExpectedTypeInfo>(_infos, EXPECTED_TYPE_INFO_STRATEGY);
214           }
215         });
216         for (final ExpectedTypeInfo info : infos) {
217           final JavaSmartCompletionParameters parameters = new JavaSmartCompletionParameters(params, info);
218           final PsiType type = info.getType();
219
220           final CompletionService service = CompletionService.getCompletionService();
221           new BasicExpressionCompletionContributor().fillCompletionVariants(parameters, service.createResultSet(parameters, new Consumer<LookupElement>() {
222             public void consume(final LookupElement lookupElement) {
223               final TypedLookupItem typed = JavaCompletionUtil.typedFrom(lookupElement);
224               if (typed != null) {
225                 final PsiType psiType = typed.getType();
226                 if (psiType != null && type.isAssignableFrom(psiType)) {
227                   result.addElement(decorate(lookupElement, _infos));
228                 }
229               }
230             }
231           }, JavaSmartCompletionContributor.this));
232           ReferenceExpressionCompletionContributor.fillCompletionVariants(parameters, service.createResultSet(parameters, new Consumer<LookupElement>() {
233             public void consume(final LookupElement lookupElement) {
234               result.addElement(decorate(lookupElement, _infos));
235             }
236           }, JavaSmartCompletionContributor.this));
237
238         }
239       }
240     });
241
242     extend(CompletionType.SMART, or(
243         PsiJavaPatterns.psiElement().withParent(PsiNameValuePair.class),
244         PsiJavaPatterns.psiElement().withSuperParent(2, PsiNameValuePair.class)), new CompletionProvider<CompletionParameters>() {
245       public void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
246         final PsiElement element = parameters.getPosition();
247         final ElementPattern<? extends PsiElement> leftNeighbor = PsiJavaPatterns.psiElement().afterLeaf(PsiJavaPatterns.psiElement().withText("."));
248         final boolean needQualify = leftNeighbor.accepts(element);
249
250         for (final PsiType type : ExpectedTypesGetter.getExpectedTypes(element, false)) {
251           final PsiClass psiClass = PsiUtil.resolveClassInType(type);
252           if (psiClass != null && psiClass.isAnnotationType()) {
253             final LookupItem item = new JavaPsiClassReferenceElement(psiClass).setTailType(TailType.NONE);
254             if (needQualify) JavaCompletionUtil.qualify(item);
255             result.addElement(item);
256           }
257         }
258
259       }
260     });
261
262     extend(CompletionType.SMART, psiElement().inside(
263         psiElement(PsiDocTag.class).withName(
264             string().oneOf(PsiKeyword.THROWS, EXCEPTION_TAG))), new CompletionProvider<CompletionParameters>() {
265       public void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
266         final PsiElement element = parameters.getPosition();
267         final Set<PsiClass> throwsSet = new HashSet<PsiClass>();
268         final PsiMethod method = PsiTreeUtil.getContextOfType(element, PsiMethod.class, true);
269         if(method != null){
270           for (PsiClassType ref : method.getThrowsList().getReferencedTypes()) {
271             final PsiClass exception = ref.resolve();
272             if (exception != null && throwsSet.add(exception)) {
273               result.addElement(TailTypeDecorator.withTail(new JavaPsiClassReferenceElement(exception).setInsertHandler(new DefaultInsertHandler()), TailType.SPACE));
274             }
275           }
276         }
277
278       }
279     });
280
281     final Key<PsiTryStatement> tryKey = Key.create("try");
282     extend(CompletionType.SMART, psiElement().afterLeaf(
283         psiElement().withText("("))
284         .withSuperParent(3, psiElement(PsiCatchSection.class).withParent(
285         psiElement(PsiTryStatement.class).save(tryKey))), new CompletionProvider<CompletionParameters>() {
286       protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
287         final PsiCodeBlock tryBlock = context.get(tryKey).getTryBlock();
288         if (tryBlock == null) return;
289
290         for (final PsiClassType type : ExceptionUtil.getThrownExceptions(tryBlock.getStatements())) {
291           result.addElement(TailTypeDecorator.withTail(PsiTypeLookupItem.createLookupItem(type, tryBlock).setInsertHandler(new DefaultInsertHandler()), TailType.SPACE));
292         }
293       }
294     });
295
296     extend(CompletionType.SMART, psiElement().inside(psiElement(PsiReferenceParameterList.class)),
297            new CompletionProvider<CompletionParameters>() {
298
299              protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext processingContext, @NotNull final CompletionResultSet resultSet) {
300                final PsiElement context = parameters.getPosition();
301
302                final Pair<PsiClass, Integer> pair = getTypeParameterInfo(context);
303                if (pair == null) return;
304
305                final PsiClass referencedClass = pair.first;
306                final int parameterIndex = pair.second.intValue();
307                final PsiTypeParameter[] typeParameters = referencedClass.getTypeParameters();
308                final PsiTypeParameter targetParameter = typeParameters[parameterIndex];
309
310                boolean isLast = parameterIndex == typeParameters.length - 1;
311                final TailType tail = isLast ? new CharTailType('>') : TailType.COMMA;
312
313                boolean hasExpected = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
314                  public Boolean compute() {
315                    PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper();
316                    final PsiType[] psiTypes = ExpectedTypesGetter.getExpectedTypes(context, false);
317                    if (psiTypes.length == 0) return false;
318
319                    for (PsiType type : psiTypes) {
320                      if (!(type instanceof PsiClassType)) continue;
321                      final PsiClassType.ClassResolveResult result = ((PsiClassType)type).resolveGenerics();
322                      final PsiClass typeClass = result.getElement();
323                      final PsiSubstitutor substitutor = result.getSubstitutor();
324
325                      if (!InheritanceUtil.isInheritorOrSelf(referencedClass, typeClass, true)) continue;
326
327                      final PsiSubstitutor currentSubstitutor =
328                          TypeConversionUtil.getClassSubstitutor(typeClass, referencedClass, PsiSubstitutor.EMPTY);
329                      for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(typeClass)) {
330                        final PsiType argSubstitution = substitutor.substitute(parameter);
331                        final PsiType paramSubstitution = currentSubstitutor.substitute(parameter);
332                        final PsiType substitution = resolveHelper
333                            .getSubstitutionForTypeParameter(targetParameter, paramSubstitution, argSubstitution, false,
334                                                             PsiUtil.getLanguageLevel(context));
335                        if (substitution != null && substitution != PsiType.NULL) {
336                          final LookupItem item = PsiTypeLookupItem.createLookupItem(substitution, context);
337                          resultSet.addElement(TailTypeDecorator.withTail(item.setInsertHandler(new DefaultInsertHandler()), tail));
338                        }
339                      }
340                    }
341                    return true;
342                  }
343                }).booleanValue();
344
345
346                if (!hasExpected) {
347                  final List<PsiClassType> typeList = Collections.singletonList((PsiClassType)TypeConversionUtil.typeParameterErasure(targetParameter));
348                  processInheritors(parameters, context, parameters.getOriginalFile(), typeList, new Consumer<PsiType>() {
349                    public void consume(final PsiType type) {
350                      final PsiClass psiClass = PsiUtil.resolveClassInType(type);
351                      if (psiClass == null) return;
352
353                      resultSet.addElement(TailTypeDecorator.withTail(new JavaPsiClassReferenceElement(psiClass).setInsertHandler(new DefaultInsertHandler()), tail));
354                    }
355                  }, resultSet.getPrefixMatcher());
356
357                }
358              }
359            });
360
361
362     extend(CompletionType.SMART, AFTER_NEW, new CompletionProvider<CompletionParameters>(false) {
363       public void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext matchingContext, @NotNull final CompletionResultSet result) {
364         final PsiElement identifierCopy = parameters.getPosition();
365         final PsiFile file = parameters.getOriginalFile();
366
367         final List<PsiClassType> expectedClassTypes = new SmartList<PsiClassType>();
368         final List<PsiArrayType> expectedArrayTypes = new SmartList<PsiArrayType>();
369         final List<ExpectedTypeInfo> infos = new SmartList<ExpectedTypeInfo>();
370
371         ApplicationManager.getApplication().runReadAction(new Runnable() {
372           public void run() {
373             ContainerUtil.addAll(infos, getExpectedTypes(parameters));
374             for (PsiType type : ExpectedTypesGetter.getExpectedTypes(identifierCopy, true)) {
375               if (type instanceof PsiClassType) {
376                 final PsiClassType classType = (PsiClassType)type;
377                 if (classType.resolve() != null) {
378                   expectedClassTypes.add(classType);
379                 }
380               }
381               else if (type instanceof PsiArrayType) {
382                 expectedArrayTypes.add((PsiArrayType)type);
383               }
384             }
385           }
386         });
387
388
389         for (final PsiArrayType type : expectedArrayTypes) {
390           ApplicationManager.getApplication().runReadAction(new Runnable() {
391             public void run() {
392               final LookupItem item = PsiTypeLookupItem.createLookupItem(JavaCompletionUtil.eliminateWildcards(type), identifierCopy);
393               if (item.getObject() instanceof PsiClass) {
394                 JavaCompletionUtil.setShowFQN(item);
395               }
396               item.setInsertHandler(new DefaultInsertHandler()); //braces & shortening
397               result.addElement(decorate(item, infos));
398             }
399           });
400         }
401         
402         processInheritors(parameters, identifierCopy, file, expectedClassTypes, new Consumer<PsiType>() {
403           public void consume(final PsiType type) {
404             addExpectedType(result, type, parameters, infos);
405           }
406         }, result.getPrefixMatcher());
407       }
408     });
409   }
410
411   public static SmartCompletionDecorator decorate(LookupElement lookupElement, Collection<ExpectedTypeInfo> infos) {
412     if (lookupElement instanceof LookupItem) {
413       final LookupItem lookupItem = (LookupItem)lookupElement;
414       if (lookupItem.getInsertHandler() == null) {
415         lookupItem.setInsertHandler(DefaultInsertHandler.NO_TAIL_HANDLER);
416       }
417     }
418
419     return new SmartCompletionDecorator(lookupElement, infos);
420   }
421
422   private static LookupElement createInstanceofLookupElement(PsiClass psiClass, Set<PsiClass> toWildcardInheritors) {
423     final PsiTypeParameter[] typeParameters = psiClass.getTypeParameters();
424     if (typeParameters.length > 0) {
425       for (final PsiClass parameterizedType : toWildcardInheritors) {
426         if (psiClass.isInheritor(parameterizedType, true)) {
427           PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
428           final PsiWildcardType wildcard = PsiWildcardType.createUnbounded(psiClass.getManager());
429           for (final PsiTypeParameter typeParameter : typeParameters) {
430             substitutor = substitutor.put(typeParameter, wildcard);
431           }
432           final PsiElementFactory factory = JavaPsiFacade.getElementFactory(psiClass.getProject());
433           return PsiTypeLookupItem.createLookupItem(factory.createType(psiClass, substitutor), psiClass);
434         }
435       }
436     }
437
438
439     return new JavaPsiClassReferenceElement(psiClass);
440   }
441
442   @Nullable
443   public static Pair<PsiClass, Integer> getTypeParameterInfo(PsiElement context) {
444     final PsiReferenceParameterList parameterList = PsiTreeUtil.getContextOfType(context, PsiReferenceParameterList.class, true);
445     if (parameterList == null) return null;
446
447     final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)parameterList.getParent();
448     final int parameterIndex;
449
450     int index = 0;
451     final PsiTypeElement typeElement = PsiTreeUtil.getContextOfType(context, PsiTypeElement.class, true);
452     if(typeElement != null){
453       final PsiTypeElement[] elements = referenceElement.getParameterList().getTypeParameterElements();
454       while (index < elements.length) {
455         final PsiTypeElement element = elements[index++];
456         if(element == typeElement) break;
457       }
458     }
459     parameterIndex = index - 1;
460
461     if(parameterIndex < 0) return null;
462     final PsiElement target = referenceElement.resolve();
463     if(!(target instanceof PsiClass)) return null;
464
465     final PsiClass referencedClass = (PsiClass)target;
466     final PsiTypeParameter[] typeParameters = referencedClass.getTypeParameters();
467     if(typeParameters.length <= parameterIndex) return null;
468
469     return Pair.create(referencedClass, parameterIndex);
470   }
471
472
473   public static void processInheritors(final CompletionParameters parameters, final PsiElement identifierCopy, final PsiFile file, final Collection<PsiClassType> expectedClassTypes,
474                                         final Consumer<PsiType> consumer, final PrefixMatcher matcher) {
475     //quick
476     for (final PsiClassType type : expectedClassTypes) {
477       ApplicationManager.getApplication().runReadAction(new Runnable() {
478         public void run() {
479           consumer.consume(type);
480
481           final PsiClassType.ClassResolveResult baseResult = JavaCompletionUtil.originalize(type).resolveGenerics();
482           final PsiClass baseClass = baseResult.getElement();
483           if (baseClass == null) return;
484
485           final PsiSubstitutor baseSubstitutor = baseResult.getSubstitutor();
486
487           final THashSet<PsiType> statVariants = new THashSet<PsiType>();
488           final Processor<PsiClass> processor = CodeInsightUtil
489               .createInheritorsProcessor(parameters.getPosition(), type, 0, false, statVariants, baseClass, baseSubstitutor);
490           final StatisticsInfo[] statisticsInfos =
491               StatisticsManager.getInstance().getAllValues(JavaStatisticsManager.getAfterNewKey(type));
492           for (final StatisticsInfo statisticsInfo : statisticsInfos) {
493             final String value = statisticsInfo.getValue();
494             if (value.startsWith(JavaStatisticsManager.CLASS_PREFIX)) {
495               final String qname = value.substring(JavaStatisticsManager.CLASS_PREFIX.length());
496               final PsiClass psiClass = JavaPsiFacade.getInstance(file.getProject()).findClass(qname, file.getResolveScope());
497               if (psiClass != null && !PsiTreeUtil.isAncestor(file, psiClass, true) && !processor.process(psiClass)) break;
498             }
499           }
500
501           for (final PsiType variant : statVariants) {
502             consumer.consume(variant);
503           }
504         }
505       });
506     }
507
508     //long
509     final Condition<String> shortNameCondition = new Condition<String>() {
510       public boolean value(String s) {
511         return matcher.prefixMatches(s);
512       }
513     };
514     for (final PsiClassType type : expectedClassTypes) {
515       final boolean shouldSearchForInheritors = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
516         public Boolean compute() {
517           final PsiClass psiClass = type.resolve();
518           return psiClass != null && psiClass.isValid() && !psiClass.hasModifierProperty(PsiModifier.FINAL);
519         }
520       }).booleanValue();
521       if (shouldSearchForInheritors) {
522         final Set<PsiType> psiTypes = CodeInsightUtil.addSubtypes(type, identifierCopy, false, shortNameCondition);
523         for (final PsiType psiType : psiTypes) {
524           ApplicationManager.getApplication().runReadAction(new Runnable() {
525             public void run() {
526               if (psiType.isValid()) {
527                 consumer.consume(psiType);
528               }
529             }
530           });
531         }
532       }
533     }
534   }
535
536   public static ExpectedTypeInfo[] getExpectedTypes(final CompletionParameters parameters) {
537     final PsiElement position = parameters.getPosition();
538     if (psiElement().withParent(psiElement(PsiReferenceExpression.class).withParent(PsiThrowStatement.class)).accepts(position)) {
539       final PsiElementFactory factory = JavaPsiFacade.getInstance(position.getProject()).getElementFactory();
540       final PsiClassType classType = factory
541           .createTypeByFQClassName(CommonClassNames.JAVA_LANG_RUNTIME_EXCEPTION, position.getResolveScope());
542       final List<ExpectedTypeInfo> result = new SmartList<ExpectedTypeInfo>();
543       result.add(new ExpectedTypeInfoImpl(classType, ExpectedTypeInfo.TYPE_OR_SUBTYPE, 0, classType, TailType.SEMICOLON));
544       final PsiMethod method = PsiTreeUtil.getContextOfType(position, PsiMethod.class, true);
545       if (method != null) {
546         for (final PsiClassType type : method.getThrowsList().getReferencedTypes()) {
547           result.add(new ExpectedTypeInfoImpl(type, ExpectedTypeInfo.TYPE_OR_SUBTYPE, 0, type, TailType.SEMICOLON));
548         }
549       }
550       return result.toArray(new ExpectedTypeInfo[result.size()]);
551     }
552
553     PsiExpression expression = PsiTreeUtil.getContextOfType(position, PsiExpression.class, true);
554     if (expression == null) return ExpectedTypeInfo.EMPTY_ARRAY;
555
556     return ExpectedTypesProvider.getExpectedTypes(expression, true, parameters.getCompletionType() == CompletionType.SMART, false);
557   }
558
559   private static void addExpectedType(final CompletionResultSet result, final PsiType type, final CompletionParameters parameters, Collection<ExpectedTypeInfo> infos) {
560     if (!JavaCompletionUtil.hasAccessibleConstructor(type)) return;
561
562     final PsiClass psiClass = PsiUtil.resolveClassInType(type);
563     if (psiClass == null) return;
564
565     final PsiClass parentClass = psiClass.getContainingClass();
566     if (parentClass != null && !psiClass.hasModifierProperty(PsiModifier.STATIC) &&
567         !PsiTreeUtil.isAncestor(parentClass, parameters.getPosition(), false) &&
568         !(parentClass.getContainingFile().equals(parameters.getOriginalFile()) &&
569           parentClass.getTextRange().contains(parameters.getOffset()))) {
570       return;
571     }
572
573     final LookupItem item = PsiTypeLookupItem.createLookupItem(JavaCompletionUtil.eliminateWildcards(type), parameters.getPosition());
574     JavaCompletionUtil.setShowFQN(item);
575
576     if (psiClass.isInterface() || psiClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
577       item.setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE);
578       item.setAttribute(LookupItem.INDICATE_ANONYMOUS, "");
579     }
580
581     result.addElement(decorate(type instanceof PsiClassType ? LookupElementDecorator.withInsertHandler(item, ConstructorInsertHandler.INSTANCE) : item, infos));
582   }
583
584   static Set<LookupElement> completeReference(final PsiElement element, PsiReference reference, final ElementFilter filter, final boolean acceptClasses, CompletionParameters parameters) {
585     if (reference instanceof PsiMultiReference) {
586       reference = ContainerUtil.findInstance(((PsiMultiReference) reference).getReferences(), PsiJavaReference.class);
587     }
588
589     if (reference instanceof PsiJavaReference) {
590       final PsiJavaReference javaReference = (PsiJavaReference)reference;
591
592       return JavaCompletionUtil.processJavaReference(element, javaReference, new ElementFilter() {
593         public boolean isAcceptable(Object element, PsiElement context) {
594           return filter.isAcceptable(element, context);
595         }
596
597         public boolean isClassAcceptable(Class hintClass) {
598           if (acceptClasses) {
599             return ReflectionCache.isAssignable(PsiClass.class, hintClass);
600           }
601
602           return ReflectionCache.isAssignable(PsiVariable.class, hintClass) ||
603                  ReflectionCache.isAssignable(PsiMethod.class, hintClass) ||
604                  ReflectionCache.isAssignable(CandidateInfo.class, hintClass);
605         }
606       }, true, null, parameters);
607     }
608
609     return Collections.emptySet();
610   }
611
612   @Override
613   public void beforeCompletion(@NotNull CompletionInitializationContext context) {
614     if (context.getCompletionType() != CompletionType.SMART) {
615       return;
616     }
617
618     if (!context.getEditor().getSelectionModel().hasSelection()) {
619       final PsiFile file = context.getFile();
620       PsiElement element = file.findElementAt(context.getStartOffset());
621       if (element instanceof PsiIdentifier) {
622         element = element.getParent();
623         while (element instanceof PsiJavaCodeReferenceElement || element instanceof PsiCall ||
624                element instanceof PsiThisExpression || element instanceof PsiSuperExpression ||
625                element instanceof PsiTypeElement ||
626                element instanceof PsiClassObjectAccessExpression) {
627           int newEnd = element.getTextRange().getEndOffset();
628           if (element instanceof PsiMethodCallExpression) {
629             newEnd = ((PsiMethodCallExpression)element).getMethodExpression().getTextRange().getEndOffset();
630           }
631           else if (element instanceof PsiNewExpression) {
632             final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)element).getClassReference();
633             if (classReference != null) {
634               newEnd = classReference.getTextRange().getEndOffset();
635             }
636           }
637           context.getOffsetMap().addOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET, newEnd);
638           element = element.getParent();
639         }
640       }
641     }
642
643     PsiElement lastElement = context.getFile().findElementAt(context.getStartOffset() - 1);
644     if (lastElement != null && lastElement.getText().equals("(")) {
645       final PsiElement parent = lastElement.getParent();
646       if (parent instanceof PsiTypeCastExpression) {
647         context.setFileCopyPatcher(new DummyIdentifierPatcher(""));
648         return;
649       }
650       if (parent instanceof PsiParenthesizedExpression) {
651         context.setFileCopyPatcher(new DummyIdentifierPatcher("xxx)yyy ")); // to handle type cast
652         return;
653       }
654     }
655     context.setFileCopyPatcher(new DummyIdentifierPatcher("xxx"));
656   }
657
658 }