IDEA-248001 Annotation parameter completion in generics doesn't work correctly
[idea/community.git] / java / java-impl / src / com / intellij / codeInsight / completion / JavaCompletionContributor.java
1 // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.codeInsight.completion;
3
4 import com.intellij.application.options.CodeStyle;
5 import com.intellij.codeInsight.ExpectedTypeInfo;
6 import com.intellij.codeInsight.ExpectedTypesProvider;
7 import com.intellij.codeInsight.TailType;
8 import com.intellij.codeInsight.TailTypes;
9 import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor;
10 import com.intellij.codeInsight.daemon.impl.analysis.LambdaHighlightingUtil;
11 import com.intellij.codeInsight.lookup.*;
12 import com.intellij.featureStatistics.FeatureUsageTracker;
13 import com.intellij.icons.AllIcons;
14 import com.intellij.java.JavaBundle;
15 import com.intellij.lang.LangBundle;
16 import com.intellij.lang.java.JavaLanguage;
17 import com.intellij.openapi.actionSystem.IdeActions;
18 import com.intellij.openapi.editor.Document;
19 import com.intellij.openapi.editor.Editor;
20 import com.intellij.openapi.keymap.KeymapUtil;
21 import com.intellij.openapi.module.Module;
22 import com.intellij.openapi.module.ModuleUtilCore;
23 import com.intellij.openapi.project.DumbAware;
24 import com.intellij.openapi.project.Project;
25 import com.intellij.openapi.roots.ModuleRootManager;
26 import com.intellij.openapi.util.Condition;
27 import com.intellij.openapi.util.TextRange;
28 import com.intellij.openapi.util.text.StringUtil;
29 import com.intellij.openapi.vfs.VirtualFile;
30 import com.intellij.patterns.ElementPattern;
31 import com.intellij.patterns.PatternCondition;
32 import com.intellij.patterns.PsiNameValuePairPattern;
33 import com.intellij.psi.*;
34 import com.intellij.psi.codeStyle.CodeStyleManager;
35 import com.intellij.psi.filters.*;
36 import com.intellij.psi.filters.classes.AnnotationTypeFilter;
37 import com.intellij.psi.filters.classes.AssignableFromContextFilter;
38 import com.intellij.psi.filters.element.ModifierFilter;
39 import com.intellij.psi.filters.getters.ExpectedTypesGetter;
40 import com.intellij.psi.filters.getters.JavaMembersGetter;
41 import com.intellij.psi.filters.types.AssignableFromFilter;
42 import com.intellij.psi.impl.PsiImplUtil;
43 import com.intellij.psi.impl.java.stubs.index.JavaAutoModuleNameIndex;
44 import com.intellij.psi.impl.java.stubs.index.JavaModuleNameIndex;
45 import com.intellij.psi.impl.java.stubs.index.JavaSourceModuleNameIndex;
46 import com.intellij.psi.impl.source.PsiJavaCodeReferenceElementImpl;
47 import com.intellij.psi.impl.source.PsiLabelReference;
48 import com.intellij.psi.scope.ElementClassFilter;
49 import com.intellij.psi.search.GlobalSearchScope;
50 import com.intellij.psi.search.ProjectScope;
51 import com.intellij.psi.util.PsiTreeUtil;
52 import com.intellij.psi.util.PsiUtil;
53 import com.intellij.psi.util.PsiUtilCore;
54 import com.intellij.psi.util.TypeConversionUtil;
55 import com.intellij.util.Consumer;
56 import com.intellij.util.DocumentUtil;
57 import com.intellij.util.ProcessingContext;
58 import com.intellij.util.containers.ContainerUtil;
59 import gnu.trove.THashSet;
60 import org.jetbrains.annotations.NotNull;
61 import org.jetbrains.annotations.Nullable;
62
63 import java.util.*;
64
65 import static com.intellij.codeInsight.completion.ReferenceExpressionCompletionContributor.getSpace;
66 import static com.intellij.patterns.PsiJavaPatterns.*;
67
68 /**
69  * @author peter
70  */
71 public class JavaCompletionContributor extends CompletionContributor implements DumbAware {
72   private static final ElementPattern<PsiElement> UNEXPECTED_REFERENCE_AFTER_DOT =
73     psiElement().afterLeaf(".").insideStarting(psiExpressionStatement());
74   private static final PsiNameValuePairPattern NAME_VALUE_PAIR =
75     psiNameValuePair().withSuperParent(2, psiElement(PsiAnnotation.class));
76   private static final ElementPattern<PsiElement> ANNOTATION_ATTRIBUTE_NAME =
77     or(psiElement(PsiIdentifier.class).withParent(NAME_VALUE_PAIR),
78        psiElement().afterLeaf("(").withParent(psiReferenceExpression().withParent(NAME_VALUE_PAIR)));
79
80   public static final ElementPattern<PsiElement> IN_SWITCH_LABEL =
81     psiElement().withSuperParent(2, psiElement(PsiExpressionList.class).withParent(psiElement(PsiSwitchLabelStatementBase.class).withSuperParent(2, PsiSwitchBlock.class)));
82   private static final ElementPattern<PsiElement> IN_ENUM_SWITCH_LABEL =
83     psiElement().withSuperParent(2, psiElement(PsiExpressionList.class).withParent(psiElement(PsiSwitchLabelStatementBase.class).withSuperParent(2,
84       psiElement(PsiSwitchBlock.class).with(new PatternCondition<PsiSwitchBlock>("enumExpressionType") {
85         @Override
86         public boolean accepts(@NotNull PsiSwitchBlock psiSwitchBlock, ProcessingContext context) {
87           PsiExpression expression = psiSwitchBlock.getExpression();
88           if (expression == null) return false;
89           PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(expression.getType());
90           return aClass != null && aClass.isEnum();
91         }
92       }))));
93
94   private static final ElementPattern<PsiElement> AFTER_NUMBER_LITERAL =
95     psiElement().afterLeaf(psiElement().withElementType(
96       elementType().oneOf(JavaTokenType.DOUBLE_LITERAL, JavaTokenType.LONG_LITERAL, JavaTokenType.FLOAT_LITERAL, JavaTokenType.INTEGER_LITERAL)));
97   private static final ElementPattern<PsiElement> IMPORT_REFERENCE =
98     psiElement().withParent(psiElement(PsiJavaCodeReferenceElement.class).withParent(PsiImportStatementBase.class));
99   private static final ElementPattern<PsiElement> CATCH_OR_FINALLY = psiElement().afterLeaf(
100     psiElement().withText("}").withParent(
101       psiElement(PsiCodeBlock.class).afterLeaf(PsiKeyword.TRY)));
102   private static final ElementPattern<PsiElement> INSIDE_CONSTRUCTOR = psiElement().inside(psiMethod().constructor(true));
103   private static final ElementPattern<PsiElement> AFTER_ENUM_CONSTANT =
104     psiElement().inside(PsiTypeElement.class).afterLeaf(
105       psiElement().inside(true, psiElement(PsiEnumConstant.class), psiElement(PsiClass.class, PsiExpressionList.class)));
106
107   @Nullable
108   public static ElementFilter getReferenceFilter(PsiElement position) {
109     if (isInExtendsOrImplementsList(position)) {
110       return new AndFilter(ElementClassFilter.CLASS, new NotFilter(new AssignableFromContextFilter()));
111     }
112
113     if (getAnnotationNameIfInside(position) != null) {
114       return new OrFilter(ElementClassFilter.PACKAGE, new AnnotationTypeFilter());
115     }
116
117     if (JavaKeywordCompletion.isDeclarationStart(position) ||
118         JavaKeywordCompletion.isInsideParameterList(position) ||
119         isInsideAnnotationName(position) ||
120         PsiTreeUtil.getParentOfType(position, PsiReferenceParameterList.class, false, PsiAnnotation.class) != null ||
121         isDefinitelyVariableType(position)) {
122       return new OrFilter(ElementClassFilter.CLASS, ElementClassFilter.PACKAGE);
123     }
124
125     if (psiElement().afterLeaf(PsiKeyword.INSTANCEOF).accepts(position)) {
126       return new ElementExtractorFilter(ElementClassFilter.CLASS);
127     }
128
129     if (JavaKeywordCompletion.VARIABLE_AFTER_FINAL.accepts(position)) {
130       return ElementClassFilter.CLASS;
131     }
132
133     if (CATCH_OR_FINALLY.accepts(position) ||
134         JavaKeywordCompletion.START_SWITCH.accepts(position) ||
135         JavaKeywordCompletion.isInstanceofPlace(position) ||
136         JavaKeywordCompletion.isAfterPrimitiveOrArrayType(position)) {
137       return null;
138     }
139
140     if (JavaKeywordCompletion.START_FOR.withParents(PsiJavaCodeReferenceElement.class, PsiExpressionStatement.class, PsiForStatement.class).accepts(position)) {
141       return new OrFilter(ElementClassFilter.CLASS, ElementClassFilter.VARIABLE);
142     }
143
144     if (JavaSmartCompletionContributor.AFTER_NEW.accepts(position)) {
145       return ElementClassFilter.CLASS;
146     }
147
148     if (psiElement().inside(PsiAnnotationParameterList.class).accepts(position)) {
149       return createAnnotationFilter();
150     }
151
152     PsiVariable var = PsiTreeUtil.getParentOfType(position, PsiVariable.class, false, PsiClass.class);
153     if (var != null && PsiTreeUtil.isAncestor(var.getInitializer(), position, false)) {
154       return new ExcludeFilter(var);
155     }
156
157     if (IN_ENUM_SWITCH_LABEL.accepts(position)) {
158       return new ClassFilter(PsiField.class) {
159         @Override
160         public boolean isAcceptable(Object element, PsiElement context) {
161           return element instanceof PsiEnumConstant;
162         }
163       };
164     }
165
166     PsiForeachStatement loop = PsiTreeUtil.getParentOfType(position, PsiForeachStatement.class);
167     if (loop != null && PsiTreeUtil.isAncestor(loop.getIteratedValue(), position, false)) {
168       return new ExcludeFilter(loop.getIterationParameter());
169     }
170
171     if (PsiTreeUtil.getParentOfType(position, PsiPackageAccessibilityStatement.class) != null) {
172       return applyScopeFilter(ElementClassFilter.PACKAGE, position);
173     }
174
175     if (PsiTreeUtil.getParentOfType(position, PsiUsesStatement.class, PsiProvidesStatement.class) != null) {
176       ElementFilter filter = new OrFilter(ElementClassFilter.CLASS, ElementClassFilter.PACKAGE);
177       if (PsiTreeUtil.getParentOfType(position, PsiReferenceList.class) != null) {
178         filter = applyScopeFilter(filter, position);
179       }
180       return filter;
181     }
182
183     return TrueFilter.INSTANCE;
184   }
185
186   private static boolean isDefinitelyVariableType(PsiElement position) {
187     return psiElement().withParents(PsiJavaCodeReferenceElement.class, PsiTypeElement.class, PsiDeclarationStatement.class).afterLeaf(psiElement().inside(psiAnnotation())).accepts(position);
188   }
189
190   private static boolean isInExtendsOrImplementsList(PsiElement position) {
191     PsiClass containingClass = PsiTreeUtil.getParentOfType(
192       position, PsiClass.class, false, PsiCodeBlock.class, PsiMethod.class, PsiExpressionList.class, PsiVariable.class, PsiAnnotation.class);
193     return containingClass != null &&
194            psiElement().afterLeaf(
195              psiElement()
196                .withText(string().oneOf(PsiKeyword.EXTENDS, PsiKeyword.IMPLEMENTS, ",", "&"))
197                .withParent(PsiReferenceList.class)
198            ).accepts(position);
199   }
200
201   private static boolean isInsideAnnotationName(PsiElement position) {
202     PsiAnnotation anno = PsiTreeUtil.getParentOfType(position, PsiAnnotation.class, true, PsiMember.class);
203     return anno != null && PsiTreeUtil.isAncestor(anno.getNameReferenceElement(), position, true);
204   }
205
206   private static ElementFilter createAnnotationFilter() {
207     return new OrFilter(
208       ElementClassFilter.CLASS,
209       ElementClassFilter.PACKAGE,
210       new AndFilter(new ClassFilter(PsiField.class), new ModifierFilter(PsiModifier.STATIC, PsiModifier.FINAL)));
211   }
212
213   public static ElementFilter applyScopeFilter(ElementFilter filter, PsiElement position) {
214     Module module = ModuleUtilCore.findModuleForPsiElement(position);
215     return module != null ? new AndFilter(filter, new SearchScopeFilter(module.getModuleScope())) : filter;
216   }
217
218   @Override
219   public void fillCompletionVariants(@NotNull final CompletionParameters parameters, @NotNull final CompletionResultSet _result) {
220     final PsiElement position = parameters.getPosition();
221     if (!isInJavaContext(position)) {
222       return;
223     }
224
225     if (AFTER_NUMBER_LITERAL.accepts(position) ||
226         UNEXPECTED_REFERENCE_AFTER_DOT.accepts(position) ||
227         AFTER_ENUM_CONSTANT.accepts(position)) {
228       _result.stopHere();
229       return;
230     }
231
232     boolean smart = parameters.getCompletionType() == CompletionType.SMART;
233
234     final CompletionResultSet result = JavaCompletionSorting.addJavaSorting(parameters, _result);
235     JavaCompletionSession session = new JavaCompletionSession(result);
236
237     PrefixMatcher matcher = result.getPrefixMatcher();
238     PsiElement parent = position.getParent();
239
240     if (!smart && new JavaKeywordCompletion(parameters, session).addWildcardExtendsSuper(result, position)) {
241       result.stopHere();
242       return;
243     }
244
245     boolean mayCompleteReference = true;
246
247     if (position instanceof PsiIdentifier) {
248       addIdentifierVariants(parameters, position, result, session, matcher);
249
250       Set<ExpectedTypeInfo> expectedInfos = ContainerUtil.newHashSet(JavaSmartCompletionContributor.getExpectedTypes(parameters));
251       boolean shouldAddExpressionVariants = shouldAddExpressionVariants(parameters);
252
253       boolean hasTypeMatchingSuggestions =
254         shouldAddExpressionVariants && addExpectedTypeMembers(parameters, false, expectedInfos,
255                                                               item -> session.registerBatchItems(Collections.singleton(item)));
256
257       if (!smart) {
258         PsiAnnotation anno = findAnnotationWhoseAttributeIsCompleted(position);
259         if (anno != null) {
260           PsiClass annoClass = anno.resolveAnnotationType();
261           mayCompleteReference = psiElement().afterLeaf("(").accepts(position) &&
262                               annoClass != null && annoClass.findMethodsByName("value", false).length > 0;
263           if (annoClass != null) {
264             completeAnnotationAttributeName(result, position, anno, annoClass);
265             JavaKeywordCompletion.addPrimitiveTypes(result, position, session);
266           }
267         }
268       }
269
270       PsiReference ref = position.getContainingFile().findReferenceAt(parameters.getOffset());
271       if (ref instanceof PsiLabelReference) {
272         session.registerBatchItems(processLabelReference((PsiLabelReference)ref));
273         result.stopHere();
274       }
275
276       List<LookupElement> refSuggestions = Collections.emptyList();
277       if (parent instanceof PsiJavaCodeReferenceElement && mayCompleteReference) {
278         refSuggestions = completeReference(parameters, (PsiJavaCodeReferenceElement)parent, session, expectedInfos, matcher::prefixMatches);
279         List<LookupElement> filtered = filterReferenceSuggestions(parameters, expectedInfos, refSuggestions);
280         hasTypeMatchingSuggestions |= ContainerUtil.exists(filtered, item ->
281           ReferenceExpressionCompletionContributor.matchesExpectedType(item, expectedInfos));
282         session.registerBatchItems(filtered);
283         result.stopHere();
284       }
285
286       session.flushBatchItems();
287
288       if (smart) {
289         hasTypeMatchingSuggestions |= smartCompleteExpression(parameters, result, expectedInfos);
290         smartCompleteNonExpression(parameters, result);
291       }
292
293       if ((!hasTypeMatchingSuggestions || parameters.getInvocationCount() >= 2) &&
294           parent instanceof PsiJavaCodeReferenceElement &&
295           !expectedInfos.isEmpty() &&
296           JavaSmartCompletionContributor.INSIDE_EXPRESSION.accepts(position)) {
297         List<LookupElement> base = ContainerUtil.concat(
298           refSuggestions,
299           completeReference(parameters, (PsiJavaCodeReferenceElement)parent, session, expectedInfos, s -> !matcher.prefixMatches(s)));
300         SlowerTypeConversions.addChainedSuggestions(parameters, result, expectedInfos, base);
301       }
302
303       if (smart && parameters.getInvocationCount() > 1 && shouldAddExpressionVariants) {
304         addExpectedTypeMembers(parameters, true, expectedInfos, result);
305       }
306     }
307
308     if (!smart && psiElement().inside(PsiLiteralExpression.class).accepts(position)) {
309       Set<String> usedWords = new HashSet<>();
310       result.runRemainingContributors(parameters, cr -> {
311         usedWords.add(cr.getLookupElement().getLookupString());
312         result.passResult(cr);
313       });
314
315       PsiReference reference = position.getContainingFile().findReferenceAt(parameters.getOffset());
316       if (reference == null || reference.isSoft()) {
317         WordCompletionContributor.addWordCompletionVariants(result, parameters, usedWords);
318       }
319     }
320
321     if (!smart && position instanceof PsiIdentifier) {
322       JavaGenerateMemberCompletionContributor.fillCompletionVariants(parameters, result);
323     }
324
325     if (!smart && mayCompleteReference) {
326       addAllClasses(parameters, result, session);
327     }
328
329     if (position instanceof PsiIdentifier) {
330       FunctionalExpressionCompletionProvider.addFunctionalVariants(parameters, true, result.getPrefixMatcher(), result);
331     }
332
333     if (position instanceof PsiIdentifier &&
334         !smart &&
335         parent instanceof PsiReferenceExpression &&
336         !((PsiReferenceExpression)parent).isQualified() &&
337         parameters.isExtendedCompletion() &&
338         StringUtil.isNotEmpty(matcher.getPrefix())) {
339       new JavaStaticMemberProcessor(parameters).processStaticMethodsGlobally(matcher, result);
340     }
341
342     if (!smart && parent instanceof PsiJavaModuleReferenceElement) {
343       addModuleReferences(parent, parameters.getOriginalFile(), result);
344     }
345   }
346
347   private static List<LookupElement> filterReferenceSuggestions(CompletionParameters parameters,
348                                                                 Set<ExpectedTypeInfo> expectedInfos,
349                                                                 List<LookupElement> refSuggestions) {
350     if (parameters.getCompletionType() == CompletionType.SMART) {
351       return ReferenceExpressionCompletionContributor.smartCompleteReference(refSuggestions, expectedInfos);
352     }
353     return refSuggestions;
354   }
355
356   private static void smartCompleteNonExpression(CompletionParameters parameters, CompletionResultSet result) {
357     PsiElement position = parameters.getPosition();
358     PsiElement parent = position.getParent();
359     if (!SmartCastProvider.shouldSuggestCast(parameters) && parent instanceof PsiJavaCodeReferenceElement) {
360       JavaSmartCompletionContributor.addClassReferenceSuggestions(parameters, result, position, (PsiJavaCodeReferenceElement)parent);
361     }
362     if (InstanceofTypeProvider.AFTER_INSTANCEOF.accepts(position)) {
363       InstanceofTypeProvider.addCompletions(parameters, result);
364     }
365     if (ExpectedAnnotationsProvider.ANNOTATION_ATTRIBUTE_VALUE.accepts(position)) {
366       ExpectedAnnotationsProvider.addCompletions(position, result);
367     }
368     if (CatchTypeProvider.CATCH_CLAUSE_TYPE.accepts(position)) {
369       CatchTypeProvider.addCompletions(parameters, result);
370     }
371   }
372
373   private static boolean smartCompleteExpression(CompletionParameters parameters,
374                                                  CompletionResultSet result,
375                                                  Set<ExpectedTypeInfo> infos) {
376     PsiElement position = parameters.getPosition();
377     if (SmartCastProvider.shouldSuggestCast(parameters) ||
378         !JavaSmartCompletionContributor.INSIDE_EXPRESSION.accepts(position) ||
379         !(position.getParent() instanceof PsiJavaCodeReferenceElement)) {
380       return false;
381     }
382
383     boolean[] hadItems = new boolean[1];
384     for (ExpectedTypeInfo info : new THashSet<>(infos, JavaSmartCompletionContributor.EXPECTED_TYPE_INFO_STRATEGY)) {
385       BasicExpressionCompletionContributor.fillCompletionVariants(new JavaSmartCompletionParameters(parameters, info), lookupElement -> {
386         final PsiType psiType = JavaCompletionUtil.getLookupElementType(lookupElement);
387         if (psiType != null && info.getType().isAssignableFrom(psiType)) {
388           hadItems[0] = true;
389           result.addElement(JavaSmartCompletionContributor.decorate(lookupElement, infos));
390         }
391       }, result.getPrefixMatcher());
392     }
393     return hadItems[0];
394   }
395
396   @Nullable
397   private static PsiAnnotation findAnnotationWhoseAttributeIsCompleted(@NotNull PsiElement position) {
398     return ANNOTATION_ATTRIBUTE_NAME.accepts(position) && !JavaKeywordCompletion.isAfterPrimitiveOrArrayType(position)
399            ? Objects.requireNonNull(PsiTreeUtil.getParentOfType(position, PsiAnnotation.class))
400            : null;
401   }
402
403   private static void addIdentifierVariants(@NotNull CompletionParameters parameters,
404                                             PsiElement position,
405                                             CompletionResultSet result,
406                                             JavaCompletionSession session, PrefixMatcher matcher) {
407     session.registerBatchItems(getFastIdentifierVariants(parameters, position, matcher, position.getParent(), session));
408
409     if (JavaSmartCompletionContributor.AFTER_NEW.accepts(position)) {
410       session.flushBatchItems();
411
412       boolean smart = parameters.getCompletionType() == CompletionType.SMART;
413       ConstructorInsertHandler handler = smart
414                                          ? ConstructorInsertHandler.SMART_INSTANCE
415                                          : ConstructorInsertHandler.BASIC_INSTANCE;
416       ExpectedTypeInfo[] types = JavaSmartCompletionContributor.getExpectedTypes(parameters);
417       new JavaInheritorsGetter(handler).generateVariants(parameters, matcher, types, lookupElement -> {
418         if ((smart || !isSuggestedByKeywordCompletion(lookupElement)) && result.getPrefixMatcher().prefixMatches(lookupElement)) {
419           session.registerClassFrom(lookupElement);
420           result.addElement(smart
421                             ? JavaSmartCompletionContributor.decorate(lookupElement, Arrays.asList(types))
422                             : AutoCompletionPolicy.NEVER_AUTOCOMPLETE.applyPolicy(lookupElement));
423         }
424       });
425     }
426
427     suggestSmartCast(parameters, session, false, result);
428   }
429
430   private static boolean isSuggestedByKeywordCompletion(LookupElement lookupElement) {
431     if (lookupElement instanceof PsiTypeLookupItem) {
432       PsiType type = ((PsiTypeLookupItem)lookupElement).getType();
433       return type instanceof PsiArrayType && ((PsiArrayType)type).getComponentType() instanceof PsiPrimitiveType;
434     }
435     return false;
436   }
437
438   private static void suggestSmartCast(CompletionParameters parameters, JavaCompletionSession session, boolean quick, Consumer<? super LookupElement> result) {
439     if (SmartCastProvider.shouldSuggestCast(parameters)) {
440       session.flushBatchItems();
441       SmartCastProvider.addCastVariants(parameters, session.getMatcher(), element -> {
442         registerClassFromTypeElement(element, session);
443         result.consume(PrioritizedLookupElement.withPriority(element, 1));
444       }, quick);
445     }
446   }
447
448   private static List<LookupElement> getFastIdentifierVariants(@NotNull CompletionParameters parameters,
449                                                                PsiElement position,
450                                                                PrefixMatcher matcher,
451                                                                PsiElement parent,
452                                                                @NotNull JavaCompletionSession session) {
453     boolean smart = parameters.getCompletionType() == CompletionType.SMART;
454
455     List<LookupElement> items = new ArrayList<>();
456     if (TypeArgumentCompletionProvider.IN_TYPE_ARGS.accepts(position)) {
457       new TypeArgumentCompletionProvider(smart, session).addTypeArgumentVariants(parameters, items::add, matcher);
458     }
459
460     FunctionalExpressionCompletionProvider.addFunctionalVariants(parameters, false, matcher, items::add);
461
462     if (MethodReturnTypeProvider.IN_METHOD_RETURN_TYPE.accepts(position)) {
463       MethodReturnTypeProvider.addProbableReturnTypes(position, element -> {
464         registerClassFromTypeElement(element, session);
465         items.add(element);
466       });
467     }
468
469     suggestSmartCast(parameters, session, true, items::add);
470
471     if (parent instanceof PsiReferenceExpression && !(parent instanceof PsiMethodReferenceExpression)) {
472       final List<ExpectedTypeInfo> expected = Arrays.asList(ExpectedTypesProvider.getExpectedTypes((PsiExpression)parent, true));
473       StreamConversion.addCollectConversion((PsiReferenceExpression)parent, expected,
474                                              lookupElement -> items.add(JavaSmartCompletionContributor.decorate(lookupElement, expected)));
475       if (!smart) {
476         items.addAll(StreamConversion.addToStreamConversion((PsiReferenceExpression)parent, parameters));
477       }
478     }
479
480     if (IMPORT_REFERENCE.accepts(position)) {
481       items.add(LookupElementBuilder.create("*"));
482     }
483
484     if (!smart && findAnnotationWhoseAttributeIsCompleted(position) == null) {
485       items.addAll(new JavaKeywordCompletion(parameters, session).getResults());
486     }
487
488     addExpressionVariants(parameters, position, items::add);
489
490     return items;
491   }
492
493   private static void registerClassFromTypeElement(LookupElement element, JavaCompletionSession session) {
494     PsiType type = Objects.requireNonNull(element.as(PsiTypeLookupItem.CLASS_CONDITION_KEY)).getType();
495     if (type instanceof PsiPrimitiveType) {
496       session.registerKeyword(type.getCanonicalText(false));
497     }
498     else if (type instanceof PsiClassType && ((PsiClassType)type).getParameterCount() == 0) {
499       PsiClass aClass = ((PsiClassType)type).resolve();
500       if (aClass != null) {
501         session.registerClass(aClass);
502       }
503     }
504   }
505
506   private static boolean shouldAddExpressionVariants(CompletionParameters parameters) {
507     return JavaSmartCompletionContributor.INSIDE_EXPRESSION.accepts(parameters.getPosition()) &&
508            !JavaKeywordCompletion.AFTER_DOT.accepts(parameters.getPosition()) &&
509            !SmartCastProvider.shouldSuggestCast(parameters);
510   }
511
512   private static void addExpressionVariants(@NotNull CompletionParameters parameters, PsiElement position, Consumer<? super LookupElement> result) {
513     if (shouldAddExpressionVariants(parameters)) {
514       if (SameSignatureCallParametersProvider.IN_CALL_ARGUMENT.accepts(position)) {
515         new SameSignatureCallParametersProvider().addSignatureItems(position, result);
516       }
517     }
518   }
519
520   public static boolean isInJavaContext(PsiElement position) {
521     return PsiUtilCore.findLanguageFromElement(position).isKindOf(JavaLanguage.INSTANCE);
522   }
523
524   public static void addAllClasses(CompletionParameters parameters, CompletionResultSet result, JavaCompletionSession session) {
525     if (!isClassNamePossible(parameters) || !mayStartClassName(result)) {
526       return;
527     }
528
529     if (parameters.getInvocationCount() >= 2) {
530       JavaNoVariantsDelegator.suggestNonImportedClasses(parameters, result, session);
531     }
532     else {
533       advertiseSecondCompletion(parameters.getPosition().getProject(), result);
534     }
535   }
536
537   public static void advertiseSecondCompletion(Project project, CompletionResultSet result) {
538     if (FeatureUsageTracker.getInstance().isToBeAdvertisedInLookup(CodeCompletionFeatures.SECOND_BASIC_COMPLETION, project)) {
539       result.addLookupAdvertisement(JavaBundle.message("press.0.to.see.non.imported.classes",
540                                                              KeymapUtil.getFirstKeyboardShortcutText(IdeActions.ACTION_CODE_COMPLETION)));
541     }
542   }
543
544   private static List<LookupElement> completeReference(CompletionParameters parameters,
545                                                        PsiJavaCodeReferenceElement ref,
546                                                        JavaCompletionSession session,
547                                                        Set<ExpectedTypeInfo> expectedTypes,
548                                                        Condition<String> nameCondition) {
549     PsiElement position = parameters.getPosition();
550     ElementFilter filter = getReferenceFilter(position);
551     if (filter == null) return Collections.emptyList();
552
553     boolean smart = parameters.getCompletionType() == CompletionType.SMART;
554     if (smart) {
555       if (JavaSmartCompletionContributor.INSIDE_TYPECAST_EXPRESSION.accepts(position) || SmartCastProvider.shouldSuggestCast(parameters)) {
556         return Collections.emptyList();
557       }
558
559       ElementFilter smartRestriction = ReferenceExpressionCompletionContributor.getReferenceFilter(position, false);
560       if (smartRestriction != TrueFilter.INSTANCE) {
561         filter = new AndFilter(filter, smartRestriction);
562       }
563     }
564
565     boolean inSwitchLabel = IN_SWITCH_LABEL.accepts(position);
566     TailType forcedTail = null;
567     if (!smart) {
568       if (inSwitchLabel) {
569         forcedTail = TailTypes.forSwitchLabel(Objects.requireNonNull(PsiTreeUtil.getParentOfType(position, PsiSwitchBlock.class)));
570       }
571       else if (shouldInsertSemicolon(position)) {
572         forcedTail = TailType.SEMICOLON;
573       }
574     }
575
576     List<LookupElement> items = new ArrayList<>();
577     if (INSIDE_CONSTRUCTOR.accepts(position) &&
578         (parameters.getInvocationCount() <= 1 || CheckInitialized.isInsideConstructorCall(position))) {
579       filter = new AndFilter(filter, new CheckInitialized(position));
580     }
581     PsiFile originalFile = parameters.getOriginalFile();
582
583     boolean first = parameters.getInvocationCount() <= 1;
584     JavaCompletionProcessor.Options options =
585       JavaCompletionProcessor.Options.DEFAULT_OPTIONS
586         .withCheckAccess(first)
587         .withFilterStaticAfterInstance(first)
588         .withShowInstanceInStaticContext(!first && !smart);
589
590     for (LookupElement element : JavaCompletionUtil.processJavaReference(position,
591                                                                          ref,
592                                                                          new ElementExtractorFilter(filter),
593                                                                          options,
594                                                                          nameCondition, parameters)) {
595       if (session.alreadyProcessed(element)) {
596         continue;
597       }
598
599       LookupItem<?> item = element.as(LookupItem.CLASS_CONDITION_KEY);
600       if (forcedTail != null) {
601         element = TailTypeDecorator.withTail(element, forcedTail);
602       }
603       if (inSwitchLabel && !smart) {
604         element = new IndentingDecorator(element);
605       }
606       if (originalFile instanceof PsiJavaCodeReferenceCodeFragment &&
607           !((PsiJavaCodeReferenceCodeFragment)originalFile).isClassesAccepted() && item != null) {
608         item.setTailType(TailType.NONE);
609       }
610       if (item instanceof JavaMethodCallElement) {
611         JavaMethodCallElement call = (JavaMethodCallElement)item;
612         final PsiMethod method = call.getObject();
613         if (method.getTypeParameters().length > 0) {
614           PsiType returned = TypeConversionUtil.erasure(method.getReturnType());
615           ExpectedTypeInfo matchingExpectation = returned == null ? null : ContainerUtil.find(expectedTypes, info ->
616             info.getDefaultType().isAssignableFrom(returned) ||
617             AssignableFromFilter.isAcceptable(method, position, info.getDefaultType(), call.getSubstitutor()));
618           if (matchingExpectation != null) {
619             call.setInferenceSubstitutorFromExpectedType(position, matchingExpectation.getDefaultType());
620           }
621         }
622       }
623       items.add(element);
624
625       ContainerUtil.addIfNotNull(items, ArrayMemberAccess.accessFirstElement(position, element));
626
627     }
628     return items;
629   }
630
631   static boolean shouldInsertSemicolon(PsiElement position) {
632     return position.getParent() instanceof PsiMethodReferenceExpression &&
633            LambdaHighlightingUtil.insertSemicolon(position.getParent().getParent());
634   }
635
636   private static List<LookupElement> processLabelReference(PsiLabelReference reference) {
637     return ContainerUtil.map(reference.getVariants(), s -> TailTypeDecorator.withTail(LookupElementBuilder.create(s), TailType.SEMICOLON));
638   }
639
640   static boolean isClassNamePossible(CompletionParameters parameters) {
641     boolean isSecondCompletion = parameters.getInvocationCount() >= 2;
642
643     PsiElement position = parameters.getPosition();
644     if (JavaKeywordCompletion.isInstanceofPlace(position) ||
645         JavaMemberNameCompletionContributor.INSIDE_TYPE_PARAMS_PATTERN.accepts(position) ||
646         AFTER_ENUM_CONSTANT.accepts(position)) {
647       return false;
648     }
649
650     final PsiElement parent = position.getParent();
651     if (!(parent instanceof PsiJavaCodeReferenceElement)) return isSecondCompletion;
652     if (((PsiJavaCodeReferenceElement)parent).getQualifier() != null) return isSecondCompletion;
653
654     if (parent instanceof PsiJavaCodeReferenceElementImpl &&
655         ((PsiJavaCodeReferenceElementImpl)parent).getKindEnum(parent.getContainingFile()) == PsiJavaCodeReferenceElementImpl.Kind.PACKAGE_NAME_KIND) {
656       return false;
657     }
658
659     if (IN_SWITCH_LABEL.accepts(position)) {
660       return false;
661     }
662
663     if (psiElement().inside(PsiImportStatement.class).accepts(parent)) {
664       return isSecondCompletion;
665     }
666
667     PsiElement grand = parent.getParent();
668     if (grand instanceof PsiAnonymousClass) {
669       grand = grand.getParent();
670     }
671     if (grand instanceof PsiNewExpression && ((PsiNewExpression)grand).getQualifier() != null) {
672       return false;
673     }
674
675     if (JavaKeywordCompletion.isAfterPrimitiveOrArrayType(position)) {
676       return false;
677     }
678
679     return true;
680   }
681
682   public static boolean mayStartClassName(CompletionResultSet result) {
683     return InternalCompletionSettings.getInstance().mayStartClassNameCompletion(result);
684   }
685
686   private static void completeAnnotationAttributeName(CompletionResultSet result,
687                                                       PsiElement position,
688                                                       PsiAnnotation anno,
689                                                       PsiClass annoClass) {
690     PsiNameValuePair[] existingPairs = anno.getParameterList().getAttributes();
691
692     methods: for (PsiMethod method : annoClass.getMethods()) {
693       if (!(method instanceof PsiAnnotationMethod)) continue;
694
695       final String attrName = method.getName();
696       for (PsiNameValuePair existingAttr : existingPairs) {
697         if (PsiTreeUtil.isAncestor(existingAttr, position, false)) break;
698         if (Objects.equals(existingAttr.getName(), attrName) ||
699             PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(attrName) && existingAttr.getName() == null) continue methods;
700       }
701
702       PsiAnnotationMemberValue defaultValue = ((PsiAnnotationMethod)method).getDefaultValue();
703       String defText = defaultValue == null ? null : defaultValue.getText();
704       if (PsiKeyword.TRUE.equals(defText) || PsiKeyword.FALSE.equals(defText)) {
705         result.addElement(createAnnotationAttributeElement(method, PsiKeyword.TRUE.equals(defText) ? PsiKeyword.FALSE : PsiKeyword.TRUE));
706         result.addElement(PrioritizedLookupElement.withPriority(createAnnotationAttributeElement(method, defText).withTailText(" (default)", true), -1));
707       } else {
708         LookupElementBuilder element = createAnnotationAttributeElement(method, null);
709         if (defText != null) {
710           element = element.withTailText(" default " + defText, true);
711         }
712         result.addElement(element);
713       }
714     }
715   }
716
717   @NotNull
718   private static LookupElementBuilder createAnnotationAttributeElement(PsiMethod annoMethod, @Nullable String value) {
719     String space = getSpace(CodeStyle.getLanguageSettings(annoMethod.getContainingFile()).SPACE_AROUND_ASSIGNMENT_OPERATORS);
720     String lookupString = annoMethod.getName() + (value == null ? "" : space + "=" + space + value);
721     return LookupElementBuilder.create(annoMethod, lookupString).withIcon(annoMethod.getIcon(0))
722       .withStrikeoutness(PsiImplUtil.isDeprecated(annoMethod))
723       .withInsertHandler(new InsertHandler<LookupElement>() {
724         @Override
725         public void handleInsert(@NotNull InsertionContext context, @NotNull LookupElement item) {
726           final Editor editor = context.getEditor();
727           if (value == null) {
728             EqTailType.INSTANCE.processTail(editor, editor.getCaretModel().getOffset());
729           }
730           context.setAddCompletionChar(false);
731
732           context.commitDocument();
733           PsiAnnotationParameterList paramList =
734             PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiAnnotationParameterList.class, false);
735           if (paramList != null && paramList.getAttributes().length > 0 && paramList.getAttributes()[0].getName() == null) {
736             int valueOffset = paramList.getAttributes()[0].getTextRange().getStartOffset();
737             context.getDocument().insertString(valueOffset, PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME);
738             EqTailType.INSTANCE.processTail(editor, valueOffset + PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.length());
739           }
740         }
741       });
742   }
743
744   @Override
745   public String advertise(@NotNull final CompletionParameters parameters) {
746     if (!(parameters.getOriginalFile() instanceof PsiJavaFile)) return null;
747
748     if (parameters.getCompletionType() == CompletionType.BASIC && parameters.getInvocationCount() > 0) {
749       PsiElement position = parameters.getPosition();
750       if (psiElement().withParent(psiReferenceExpression().withFirstChild(psiReferenceExpression().referencing(psiClass()))).accepts(position)) {
751         if (CompletionUtil.shouldShowFeature(parameters, JavaCompletionFeatures.GLOBAL_MEMBER_NAME)) {
752           final String shortcut = KeymapUtil.getFirstKeyboardShortcutText(IdeActions.ACTION_CODE_COMPLETION);
753           if (StringUtil.isNotEmpty(shortcut)) {
754             return JavaBundle.message("pressing.0.twice.without.a.class.qualifier", shortcut);
755           }
756         }
757       }
758     }
759
760     if (parameters.getCompletionType() != CompletionType.SMART && shouldSuggestSmartCompletion(parameters.getPosition())) {
761       if (CompletionUtil.shouldShowFeature(parameters, CodeCompletionFeatures.EDITING_COMPLETION_SMARTTYPE_GENERAL)) {
762         final String shortcut = KeymapUtil.getFirstKeyboardShortcutText(IdeActions.ACTION_SMART_TYPE_COMPLETION);
763         if (StringUtil.isNotEmpty(shortcut)) {
764           return JavaBundle.message("completion.smart.hint", shortcut);
765         }
766       }
767     }
768
769     if (parameters.getCompletionType() == CompletionType.SMART && parameters.getInvocationCount() == 1) {
770       final PsiType[] psiTypes = ExpectedTypesGetter.getExpectedTypes(parameters.getPosition(), true);
771       if (psiTypes.length > 0) {
772         if (CompletionUtil.shouldShowFeature(parameters, JavaCompletionFeatures.SECOND_SMART_COMPLETION_TOAR)) {
773           final String shortcut = KeymapUtil.getFirstKeyboardShortcutText(IdeActions.ACTION_SMART_TYPE_COMPLETION);
774           if (StringUtil.isNotEmpty(shortcut)) {
775             for (final PsiType psiType : psiTypes) {
776               final PsiType type = PsiUtil.extractIterableTypeParameter(psiType, false);
777               if (type != null) {
778                 return JavaBundle.message("completion.smart.aslist.hint", shortcut, type.getPresentableText());
779               }
780             }
781           }
782         }
783         if (CompletionUtil.shouldShowFeature(parameters, JavaCompletionFeatures.SECOND_SMART_COMPLETION_ASLIST)) {
784           final String shortcut = KeymapUtil.getFirstKeyboardShortcutText(IdeActions.ACTION_SMART_TYPE_COMPLETION);
785           if (StringUtil.isNotEmpty(shortcut)) {
786             for (final PsiType psiType : psiTypes) {
787               if (psiType instanceof PsiArrayType) {
788                 final PsiType componentType = ((PsiArrayType)psiType).getComponentType();
789                 if (!(componentType instanceof PsiPrimitiveType)) {
790                   return JavaBundle.message("completion.smart.toar.hint", shortcut, componentType.getPresentableText());
791                 }
792               }
793             }
794           }
795         }
796
797         if (CompletionUtil.shouldShowFeature(parameters, JavaCompletionFeatures.SECOND_SMART_COMPLETION_CHAIN)) {
798           final String shortcut = KeymapUtil.getFirstKeyboardShortcutText(IdeActions.ACTION_SMART_TYPE_COMPLETION);
799           if (StringUtil.isNotEmpty(shortcut)) {
800             return JavaBundle.message("completion.smart.chain.hint", shortcut);
801           }
802         }
803       }
804     }
805     return null;
806   }
807
808   @Override
809   public String handleEmptyLookup(@NotNull final CompletionParameters parameters, final Editor editor) {
810     if (!(parameters.getOriginalFile() instanceof PsiJavaFile)) return null;
811
812     final String ad = advertise(parameters);
813     final String suffix = ad == null ? "" : "; " + StringUtil.decapitalize(ad);
814     if (parameters.getCompletionType() == CompletionType.SMART) {
815       PsiExpression expression = PsiTreeUtil.getContextOfType(parameters.getPosition(), PsiExpression.class, true);
816       if (expression instanceof PsiLiteralExpression) {
817         return LangBundle.message("completion.no.suggestions") + suffix;
818       }
819
820       if (expression instanceof PsiInstanceOfExpression) {
821         final PsiInstanceOfExpression instanceOfExpression = (PsiInstanceOfExpression)expression;
822         if (PsiTreeUtil.isAncestor(instanceOfExpression.getCheckType(), parameters.getPosition(), false)) {
823           return LangBundle.message("completion.no.suggestions") + suffix;
824         }
825       }
826
827       final Set<PsiType> expectedTypes = JavaCompletionUtil.getExpectedTypes(parameters);
828       if (expectedTypes != null) {
829         PsiType type = expectedTypes.size() == 1 ? expectedTypes.iterator().next() : null;
830         if (type != null) {
831           final PsiType deepComponentType = type.getDeepComponentType();
832           String expectedType = type.getPresentableText();
833           if (expectedType.contains(CompletionUtil.DUMMY_IDENTIFIER_TRIMMED)) {
834             return null;
835           }
836
837           if (deepComponentType instanceof PsiClassType) {
838             if (((PsiClassType)deepComponentType).resolve() != null) {
839               return JavaBundle.message("completion.no.suggestions.of.type", expectedType) + suffix;
840             }
841             return JavaBundle.message("completion.unknown.type", expectedType) + suffix;
842           }
843           if (!PsiType.NULL.equals(type)) {
844             return JavaBundle.message("completion.no.suggestions.of.type", expectedType) + suffix;
845           }
846         }
847       }
848     }
849     return LangBundle.message("completion.no.suggestions") + suffix;
850   }
851
852   @Override
853   public boolean invokeAutoPopup(@NotNull PsiElement position, char typeChar) {
854     return typeChar == ':' && JavaTokenType.COLON == PsiUtilCore.getElementType(position);
855   }
856
857   private static boolean shouldSuggestSmartCompletion(final PsiElement element) {
858     if (shouldSuggestClassNameCompletion(element)) return false;
859
860     final PsiElement parent = element.getParent();
861     if (parent instanceof PsiReferenceExpression && ((PsiReferenceExpression)parent).getQualifier() != null) return false;
862     if (parent instanceof PsiReferenceExpression && parent.getParent() instanceof PsiReferenceExpression) return true;
863
864     return ExpectedTypesGetter.getExpectedTypes(element, false).length > 0;
865   }
866
867   private static boolean shouldSuggestClassNameCompletion(final PsiElement element) {
868     if (element == null) return false;
869     final PsiElement parent = element.getParent();
870     if (parent == null) return false;
871     return parent.getParent() instanceof PsiTypeElement || parent.getParent() instanceof PsiExpressionStatement ||
872            parent.getParent() instanceof PsiReferenceList;
873   }
874
875   @Override
876   public void beforeCompletion(@NotNull final CompletionInitializationContext context) {
877     final PsiFile file = context.getFile();
878
879     if (file instanceof PsiJavaFile) {
880       String dummyIdentifier = customizeDummyIdentifier(context, file);
881       if (dummyIdentifier != null) {
882         context.setDummyIdentifier(dummyIdentifier);
883       }
884
885       PsiLiteralExpression literal =
886         PsiTreeUtil.findElementOfClassAtOffset(file, context.getStartOffset(), PsiLiteralExpression.class, false);
887       if (literal != null) {
888         TextRange range = literal.getTextRange();
889         if (range.getStartOffset() == context.getStartOffset()) {
890           context.setReplacementOffset(range.getEndOffset());
891         }
892       }
893
894       PsiJavaCodeReferenceElement ref = getAnnotationNameIfInside(file.findElementAt(context.getStartOffset()));
895       if (ref != null) {
896         context.setReplacementOffset(ref.getTextRange().getEndOffset());
897       }
898     }
899
900     if (context.getCompletionType() == CompletionType.SMART) {
901       JavaSmartCompletionContributor.beforeSmartCompletion(context);
902     }
903   }
904
905   @Nullable
906   static PsiJavaCodeReferenceElement getAnnotationNameIfInside(@Nullable PsiElement position) {
907     PsiAnnotation anno = PsiTreeUtil.getParentOfType(position, PsiAnnotation.class);
908     PsiJavaCodeReferenceElement ref = anno == null ? null : anno.getNameReferenceElement();
909     return ref != null && PsiTreeUtil.isAncestor(ref, position, false) ? ref : null;
910   }
911
912   @Nullable
913   private static String customizeDummyIdentifier(@NotNull CompletionInitializationContext context, PsiFile file) {
914     if (context.getCompletionType() != CompletionType.BASIC) return null;
915
916     int offset = context.getStartOffset();
917     if (PsiTreeUtil.findElementOfClassAtOffset(file, offset - 1, PsiReferenceParameterList.class, false) != null) {
918       return CompletionInitializationContext.DUMMY_IDENTIFIER_TRIMMED;
919     }
920
921     if (semicolonNeeded(file, offset)) {
922       return CompletionInitializationContext.DUMMY_IDENTIFIER_TRIMMED + ";";
923     }
924
925     PsiElement leaf = file.findElementAt(offset);
926     if (leaf instanceof PsiIdentifier || leaf instanceof PsiKeyword) {
927       return CompletionInitializationContext.DUMMY_IDENTIFIER_TRIMMED;
928     }
929
930     return null;
931   }
932
933   public static boolean semicolonNeeded(PsiFile file, int startOffset) {
934     return semicolonNeeded(null, file, startOffset);
935   }
936
937   /**
938    * @deprecated use {@link #semicolonNeeded(PsiFile, int)}
939    */
940   @Deprecated
941   public static boolean semicolonNeeded(@Nullable Editor editor, PsiFile file, int startOffset) {
942     PsiJavaCodeReferenceElement ref = PsiTreeUtil.findElementOfClassAtOffset(file, startOffset, PsiJavaCodeReferenceElement.class, false);
943     if (ref != null && !(ref instanceof PsiReferenceExpression)) {
944       if (ref.getParent() instanceof PsiTypeElement) {
945         return true;
946       }
947     }
948     PsiElement at = file.findElementAt(startOffset);
949     if (psiElement(PsiIdentifier.class).withParent(psiParameter()).accepts(at)) {
950       return true;
951     }
952
953     if (PsiUtilCore.getElementType(at) == JavaTokenType.IDENTIFIER) {
954       at = PsiTreeUtil.nextLeaf(at);
955     }
956
957     at = skipWhitespacesAndComments(at);
958
959     if (PsiUtilCore.getElementType(at) == JavaTokenType.LPARENTH &&
960         PsiTreeUtil.getParentOfType(ref, PsiExpression.class, PsiClass.class) == null) {
961       // looks like a method declaration, e.g. StringBui<caret>methodName() inside a class
962       return true;
963     }
964
965     if (PsiUtilCore.getElementType(at) == JavaTokenType.COLON &&
966         PsiTreeUtil.findElementOfClassAtOffset(file, startOffset, PsiConditionalExpression.class, false) == null) {
967       return true;
968     }
969
970     at = skipWhitespacesAndComments(at);
971
972     if (PsiUtilCore.getElementType(at) != JavaTokenType.IDENTIFIER) {
973       return false;
974     }
975
976     at = PsiTreeUtil.nextLeaf(at);
977     at = skipWhitespacesAndComments(at);
978
979     // <caret> foo = something, we don't want the reference to be treated as a type
980     return at != null && at.getNode().getElementType() == JavaTokenType.EQ;
981   }
982
983   @Nullable
984   private static PsiElement skipWhitespacesAndComments(@Nullable PsiElement at) {
985     PsiElement nextLeaf = at;
986     while (nextLeaf != null && (nextLeaf instanceof PsiWhiteSpace ||
987                                 nextLeaf instanceof PsiComment ||
988                                 nextLeaf instanceof PsiErrorElement ||
989                                 nextLeaf.getTextLength() == 0)) {
990       nextLeaf = PsiTreeUtil.nextLeaf(nextLeaf, true);
991     }
992     return nextLeaf;
993   }
994
995   private static boolean addExpectedTypeMembers(CompletionParameters parameters,
996                                                 boolean searchInheritors,
997                                                 Collection<ExpectedTypeInfo> types,
998                                                 Consumer<? super LookupElement> result) {
999     boolean[] added = new boolean[1];
1000     boolean smart = parameters.getCompletionType() == CompletionType.SMART;
1001     if (smart || parameters.getInvocationCount() <= 1) { // on second basic completion, StaticMemberProcessor will suggest those
1002       Consumer<LookupElement> consumer = e -> {
1003         added[0] = true;
1004         result.consume(smart ? JavaSmartCompletionContributor.decorate(e, types) : e);
1005       };
1006       for (ExpectedTypeInfo info : types) {
1007         new JavaMembersGetter(info.getType(), parameters).addMembers(searchInheritors, consumer);
1008         if (!info.getType().equals(info.getDefaultType())) {
1009           new JavaMembersGetter(info.getDefaultType(), parameters).addMembers(searchInheritors, consumer);
1010         }
1011       }
1012     }
1013     return added[0];
1014   }
1015
1016   private static void addModuleReferences(PsiElement moduleRef, PsiFile originalFile, CompletionResultSet result) {
1017     PsiElement statement = moduleRef.getParent();
1018     boolean requires;
1019     if ((requires = statement instanceof PsiRequiresStatement) || statement instanceof PsiPackageAccessibilityStatement) {
1020       PsiElement parent = statement.getParent();
1021       if (parent != null) {
1022         Project project = moduleRef.getProject();
1023         Set<String> filter = new HashSet<>();
1024         filter.add(((PsiJavaModule)parent).getName());
1025
1026         JavaModuleNameIndex index = JavaModuleNameIndex.getInstance();
1027         GlobalSearchScope scope = ProjectScope.getAllScope(project);
1028         for (String name : index.getAllKeys(project)) {
1029           if (index.get(name, project, scope).size() > 0 && filter.add(name)) {
1030             LookupElement lookup = LookupElementBuilder.create(name).withIcon(AllIcons.Nodes.JavaModule);
1031             if (requires) lookup = TailTypeDecorator.withTail(lookup, TailType.SEMICOLON);
1032             result.addElement(lookup);
1033           }
1034         }
1035
1036         if (requires) {
1037           Module module = ModuleUtilCore.findModuleForFile(originalFile);
1038           if (module != null) {
1039             scope = GlobalSearchScope.projectScope(project);
1040             for (String name : JavaSourceModuleNameIndex.getAllKeys(project)) {
1041               if (JavaSourceModuleNameIndex.getFilesByKey(name, scope).size() > 0) {
1042                 addAutoModuleReference(name, parent, filter, result);
1043               }
1044             }
1045             VirtualFile[] roots = ModuleRootManager.getInstance(module).orderEntries().withoutSdk().librariesOnly().getClassesRoots();
1046             scope = GlobalSearchScope.filesScope(project, Arrays.asList(roots));
1047             for (String name : JavaAutoModuleNameIndex.getAllKeys(project)) {
1048               if (JavaAutoModuleNameIndex.getFilesByKey(name, scope).size() > 0) {
1049                 addAutoModuleReference(name, parent, filter, result);
1050               }
1051             }
1052           }
1053         }
1054       }
1055     }
1056   }
1057
1058   private static void addAutoModuleReference(String name, PsiElement parent, Set<String> filter, CompletionResultSet result) {
1059     if (PsiNameHelper.isValidModuleName(name, parent) && filter.add(name)) {
1060       LookupElement lookup = LookupElementBuilder.create(name).withIcon(AllIcons.FileTypes.Archive);
1061       lookup = TailTypeDecorator.withTail(lookup, TailType.SEMICOLON);
1062       lookup = PrioritizedLookupElement.withPriority(lookup, -1);
1063       result.addElement(lookup);
1064     }
1065   }
1066
1067   static class IndentingDecorator extends LookupElementDecorator<LookupElement> {
1068     IndentingDecorator(LookupElement delegate) {
1069       super(delegate);
1070     }
1071
1072     @Override
1073     public void handleInsert(@NotNull InsertionContext context) {
1074       super.handleInsert(context);
1075       Project project = context.getProject();
1076       Document document = context.getDocument();
1077       int lineStartOffset = DocumentUtil.getLineStartOffset(context.getStartOffset(), document);
1078       PsiDocumentManager.getInstance(project).commitDocument(document);
1079       CodeStyleManager.getInstance(project).adjustLineIndent(context.getFile(), lineStartOffset);
1080     }
1081   }
1082
1083   private static class SearchScopeFilter implements ElementFilter {
1084     private final GlobalSearchScope myScope;
1085
1086     SearchScopeFilter(GlobalSearchScope scope) {
1087       myScope = scope;
1088     }
1089
1090     @Override
1091     public boolean isAcceptable(Object element, @Nullable PsiElement context) {
1092       if (element instanceof PsiPackage) {
1093         return ((PsiDirectoryContainer)element).getDirectories(myScope).length > 0;
1094       }
1095       else if (element instanceof PsiElement) {
1096         PsiFile psiFile = ((PsiElement)element).getContainingFile();
1097         if (psiFile != null) {
1098           VirtualFile file = psiFile.getVirtualFile();
1099           return file != null && myScope.contains(file);
1100         }
1101       }
1102
1103       return false;
1104     }
1105
1106     @Override
1107     public boolean isClassAcceptable(Class hintClass) {
1108       return true;
1109     }
1110   }
1111 }