@Override
  public String handleEmptyLookup(
      @NotNull final CompletionParameters parameters, final Editor editor) {
    if (!(parameters.getOriginalFile() instanceof PsiJavaFile)) return null;

    final String ad = advertise(parameters);
    final String suffix = ad == null ? "" : "; " + StringUtil.decapitalize(ad);
    if (parameters.getCompletionType() == CompletionType.SMART) {
      if (!ApplicationManager.getApplication().isUnitTestMode()) {

        final Project project = parameters.getPosition().getProject();
        final PsiFile file = parameters.getOriginalFile();

        PsiExpression expression =
            PsiTreeUtil.getContextOfType(parameters.getPosition(), PsiExpression.class, true);
        if (expression != null && expression.getParent() instanceof PsiExpressionList) {
          int lbraceOffset = expression.getParent().getTextRange().getStartOffset();
          ShowParameterInfoHandler.invoke(project, editor, file, lbraceOffset, null);
        }

        if (expression instanceof PsiLiteralExpression) {
          return LangBundle.message("completion.no.suggestions") + suffix;
        }

        if (expression instanceof PsiInstanceOfExpression) {
          final PsiInstanceOfExpression instanceOfExpression = (PsiInstanceOfExpression) expression;
          if (PsiTreeUtil.isAncestor(
              instanceOfExpression.getCheckType(), parameters.getPosition(), false)) {
            return LangBundle.message("completion.no.suggestions") + suffix;
          }
        }
      }

      final Set<PsiType> expectedTypes = JavaCompletionUtil.getExpectedTypes(parameters);
      if (expectedTypes != null) {
        PsiType type = expectedTypes.size() == 1 ? expectedTypes.iterator().next() : null;
        if (type != null) {
          final PsiType deepComponentType = type.getDeepComponentType();
          if (deepComponentType instanceof PsiClassType) {
            if (((PsiClassType) deepComponentType).resolve() != null) {
              return CompletionBundle.message(
                      "completion.no.suggestions.of.type", type.getPresentableText())
                  + suffix;
            }
            return CompletionBundle.message("completion.unknown.type", type.getPresentableText())
                + suffix;
          }
          if (!PsiType.NULL.equals(type)) {
            return CompletionBundle.message(
                    "completion.no.suggestions.of.type", type.getPresentableText())
                + suffix;
          }
        }
      }
    }
    return LangBundle.message("completion.no.suggestions") + suffix;
  }
  public static void addAllClasses(
      CompletionParameters parameters,
      final CompletionResultSet result,
      final InheritorsHolder inheritors) {
    if (!isClassNamePossible(parameters) || !mayStartClassName(result)) {
      return;
    }

    if (parameters.getInvocationCount() >= 2) {
      JavaClassNameCompletionContributor.addAllClasses(
          parameters,
          parameters.getInvocationCount() <= 2,
          result.getPrefixMatcher(),
          new Consumer<LookupElement>() {
            @Override
            public void consume(LookupElement element) {
              if (!inheritors.alreadyProcessed(element)) {
                result.addElement(element);
              }
            }
          });
    } else {
      advertiseSecondCompletion(parameters.getPosition().getProject(), result);
    }
  }
  public static void fillCompletionVariants(
      CompletionParameters parameters, CompletionResultSet result) {
    if (parameters.getCompletionType() != CompletionType.BASIC
        && parameters.getCompletionType() != CompletionType.SMART) {
      return;
    }

    PsiElement position = parameters.getPosition();
    if (psiElement(PsiIdentifier.class)
        .withParents(PsiJavaCodeReferenceElement.class, PsiTypeElement.class, PsiClass.class)
        .andNot(JavaCompletionData.AFTER_DOT)
        .andNot(psiElement().afterLeaf(psiElement().inside(PsiModifierList.class)))
        .accepts(position)) {
      suggestGeneratedMethods(result, position);
    } else if (psiElement(PsiIdentifier.class)
        .withParents(
            PsiJavaCodeReferenceElement.class,
            PsiAnnotation.class,
            PsiModifierList.class,
            PsiClass.class)
        .accepts(position)) {
      PsiAnnotation annotation =
          ObjectUtils.assertNotNull(PsiTreeUtil.getParentOfType(position, PsiAnnotation.class));
      int annoStart = annotation.getTextRange().getStartOffset();
      suggestGeneratedMethods(
          result.withPrefixMatcher(
              annotation.getText().substring(0, parameters.getOffset() - annoStart)),
          position);
    }
  }
 public static String findAlphanumericPrefix(CompletionParameters parameters) {
   return findIdentifierPrefix(
       parameters.getPosition().getContainingFile(),
       parameters.getOffset(),
       character().letterOrDigit(),
       character().letterOrDigit());
 }
 public static boolean shouldShowFeature(
     final CompletionParameters parameters, @NonNls final String id) {
   if (FeatureUsageTracker.getInstance()
       .isToBeAdvertisedInLookup(id, parameters.getPosition().getProject())) {
     FeatureUsageTracker.getInstance().triggerFeatureShown(id);
     return true;
   }
   return false;
 }
 @Nullable
 public static Set<PsiType> getExpectedTypes(final CompletionParameters parameters) {
   final PsiExpression expr =
       PsiTreeUtil.getContextOfType(parameters.getPosition(), PsiExpression.class, true);
   if (expr != null) {
     final Set<PsiType> set = new THashSet<PsiType>();
     for (final ExpectedTypeInfo expectedInfo :
         JavaSmartCompletionContributor.getExpectedTypes(parameters)) {
       set.add(expectedInfo.getType());
     }
     return set;
   }
   return null;
 }
  private static void addKeywords(CompletionParameters parameters, CompletionResultSet result) {
    PsiElement position = parameters.getPosition();
    final Set<LookupElement> lookupSet = new LinkedHashSet<LookupElement>();
    final Set<CompletionVariant> keywordVariants = new HashSet<CompletionVariant>();
    final JavaCompletionData completionData = getCompletionData(PsiUtil.getLanguageLevel(position));
    completionData.addKeywordVariants(keywordVariants, position, parameters.getOriginalFile());
    completionData.completeKeywordsBySet(
        lookupSet,
        keywordVariants,
        position,
        result.getPrefixMatcher(),
        parameters.getOriginalFile());
    completionData.fillCompletions(parameters, result);

    for (final LookupElement item : lookupSet) {
      result.addElement(item);
    }
  }
  static boolean isClassNamePossible(CompletionParameters parameters) {
    boolean isSecondCompletion = parameters.getInvocationCount() >= 2;

    PsiElement position = parameters.getPosition();
    if (JavaCompletionData.isInstanceofPlace(position)) return false;

    final PsiElement parent = position.getParent();
    if (!(parent instanceof PsiJavaCodeReferenceElement)) return isSecondCompletion;
    if (((PsiJavaCodeReferenceElement) parent).getQualifier() != null) return isSecondCompletion;

    if (parent instanceof PsiJavaCodeReferenceElementImpl
        && ((PsiJavaCodeReferenceElementImpl) parent).getKind()
            == PsiJavaCodeReferenceElementImpl.PACKAGE_NAME_KIND) {
      return false;
    }

    PsiElement grand = parent.getParent();
    if (grand instanceof PsiSwitchLabelStatement) {
      return false;
    }

    if (psiElement().inside(PsiImportStatement.class).accepts(parent)) {
      return isSecondCompletion;
    }

    if (grand instanceof PsiAnonymousClass) {
      grand = grand.getParent();
    }
    if (grand instanceof PsiNewExpression && ((PsiNewExpression) grand).getQualifier() != null) {
      return false;
    }

    if (JavaCompletionData.isAfterPrimitiveOrArrayType(position)) {
      return false;
    }

    return true;
  }
  @Override
  public String advertise(@NotNull final CompletionParameters parameters) {
    if (!(parameters.getOriginalFile() instanceof PsiJavaFile)) return null;

    if (parameters.getCompletionType() == CompletionType.BASIC
        && parameters.getInvocationCount() > 0) {
      PsiElement position = parameters.getPosition();
      if (psiElement()
          .withParent(
              psiReferenceExpression()
                  .withFirstChild(psiReferenceExpression().referencing(psiClass())))
          .accepts(position)) {
        if (CompletionUtil.shouldShowFeature(
            parameters, JavaCompletionFeatures.GLOBAL_MEMBER_NAME)) {
          final String shortcut = getActionShortcut(IdeActions.ACTION_CODE_COMPLETION);
          if (shortcut != null) {
            return "Pressing "
                + shortcut
                + " twice without a class qualifier would show all accessible static methods";
          }
        }
      }
    }

    if (parameters.getCompletionType() != CompletionType.SMART
        && shouldSuggestSmartCompletion(parameters.getPosition())) {
      if (CompletionUtil.shouldShowFeature(
          parameters, CodeCompletionFeatures.EDITING_COMPLETION_SMARTTYPE_GENERAL)) {
        final String shortcut = getActionShortcut(IdeActions.ACTION_SMART_TYPE_COMPLETION);
        if (shortcut != null) {
          return CompletionBundle.message("completion.smart.hint", shortcut);
        }
      }
    }

    if (parameters.getCompletionType() == CompletionType.SMART
        && parameters.getInvocationCount() == 1) {
      final PsiType[] psiTypes =
          ExpectedTypesGetter.getExpectedTypes(parameters.getPosition(), true);
      if (psiTypes.length > 0) {
        if (CompletionUtil.shouldShowFeature(
            parameters, JavaCompletionFeatures.SECOND_SMART_COMPLETION_TOAR)) {
          final String shortcut = getActionShortcut(IdeActions.ACTION_SMART_TYPE_COMPLETION);
          if (shortcut != null) {
            for (final PsiType psiType : psiTypes) {
              final PsiType type = PsiUtil.extractIterableTypeParameter(psiType, false);
              if (type != null) {
                return CompletionBundle.message(
                    "completion.smart.aslist.hint", shortcut, type.getPresentableText());
              }
            }
          }
        }
        if (CompletionUtil.shouldShowFeature(
            parameters, JavaCompletionFeatures.SECOND_SMART_COMPLETION_ASLIST)) {
          final String shortcut = getActionShortcut(IdeActions.ACTION_SMART_TYPE_COMPLETION);
          if (shortcut != null) {
            for (final PsiType psiType : psiTypes) {
              if (psiType instanceof PsiArrayType) {
                final PsiType componentType = ((PsiArrayType) psiType).getComponentType();
                if (!(componentType instanceof PsiPrimitiveType)) {
                  return CompletionBundle.message(
                      "completion.smart.toar.hint", shortcut, componentType.getPresentableText());
                }
              }
            }
          }
        }

        if (CompletionUtil.shouldShowFeature(
            parameters, JavaCompletionFeatures.SECOND_SMART_COMPLETION_CHAIN)) {
          final String shortcut = getActionShortcut(IdeActions.ACTION_SMART_TYPE_COMPLETION);
          if (shortcut != null) {
            return CompletionBundle.message("completion.smart.chain.hint", shortcut);
          }
        }
      }
    }
    return null;
  }
  private static Set<String> addReferenceVariants(
      final CompletionParameters parameters,
      CompletionResultSet result,
      final InheritorsHolder inheritors) {
    final Set<String> usedWords = new HashSet<String>();
    final PsiElement position = parameters.getPosition();
    final boolean first = parameters.getInvocationCount() <= 1;
    final boolean isSwitchLabel = SWITCH_LABEL.accepts(position);
    final boolean isAfterNew = JavaClassNameCompletionContributor.AFTER_NEW.accepts(position);
    final boolean pkgContext = JavaCompletionUtil.inSomePackage(position);
    LegacyCompletionContributor.processReferences(
        parameters,
        result,
        new PairConsumer<PsiReference, CompletionResultSet>() {
          @Override
          public void consume(final PsiReference reference, final CompletionResultSet result) {
            if (reference instanceof PsiJavaReference) {
              final ElementFilter filter = getReferenceFilter(position);
              if (filter != null) {
                final PsiFile originalFile = parameters.getOriginalFile();
                JavaCompletionProcessor.Options options =
                    JavaCompletionProcessor.Options.DEFAULT_OPTIONS
                        .withCheckAccess(first)
                        .withFilterStaticAfterInstance(first)
                        .withShowInstanceInStaticContext(!first);
                for (LookupElement element :
                    JavaCompletionUtil.processJavaReference(
                        position,
                        (PsiJavaReference) reference,
                        new ElementExtractorFilter(filter),
                        options,
                        result.getPrefixMatcher(),
                        parameters)) {
                  if (inheritors.alreadyProcessed(element)) {
                    continue;
                  }

                  if (isSwitchLabel) {
                    result.addElement(
                        TailTypeDecorator.withTail(element, TailType.createSimpleTailType(':')));
                  } else {
                    final LookupItem item = element.as(LookupItem.CLASS_CONDITION_KEY);
                    if (originalFile instanceof PsiJavaCodeReferenceCodeFragment
                        && !((PsiJavaCodeReferenceCodeFragment) originalFile).isClassesAccepted()
                        && item != null) {
                      item.setTailType(TailType.NONE);
                    }

                    result.addElement(element);
                  }
                }
              }
              return;
            }
            if (reference instanceof PsiLabelReference) {
              processLabelReference(result, (PsiLabelReference) reference);
              return;
            }

            final Object[] variants = reference.getVariants();
            if (variants == null) {
              LOG.error("Reference=" + reference);
            }
            for (Object completion : variants) {
              if (completion == null) {
                LOG.error(
                    "Position="
                        + position
                        + "\n;Reference="
                        + reference
                        + "\n;variants="
                        + Arrays.toString(variants));
              }
              if (completion instanceof LookupElement
                  && !inheritors.alreadyProcessed((LookupElement) completion)) {
                usedWords.add(((LookupElement) completion).getLookupString());
                result.addElement((LookupElement) completion);
              } else if (completion instanceof PsiClass) {
                for (JavaPsiClassReferenceElement item :
                    JavaClassNameCompletionContributor.createClassLookupItems(
                        (PsiClass) completion,
                        isAfterNew,
                        JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER,
                        new Condition<PsiClass>() {
                          @Override
                          public boolean value(PsiClass psiClass) {
                            return !inheritors.alreadyProcessed(psiClass)
                                && JavaCompletionUtil.isSourceLevelAccessible(
                                    position, psiClass, pkgContext);
                          }
                        })) {
                  usedWords.add(item.getLookupString());
                  result.addElement(item);
                }

              } else {
                LookupElement element = LookupItemUtil.objectToLookupItem(completion);
                usedWords.add(element.getLookupString());
                result.addElement(element);
              }
            }
          }
        });
    return usedWords;
  }
  @Override
  public void fillCompletionVariants(
      final CompletionParameters parameters, final CompletionResultSet _result) {
    if (parameters.getCompletionType() != CompletionType.BASIC) {
      return;
    }

    final PsiElement position = parameters.getPosition();
    if (!isInJavaContext(position)) {
      return;
    }

    if (AFTER_NUMBER_LITERAL.accepts(position)
        || UNEXPECTED_REFERENCE_AFTER_DOT.accepts(position)) {
      _result.stopHere();
      return;
    }

    final CompletionResultSet result = JavaCompletionSorting.addJavaSorting(parameters, _result);

    if (ANNOTATION_ATTRIBUTE_NAME.accepts(position)
        && !JavaCompletionData.isAfterPrimitiveOrArrayType(position)) {
      JavaCompletionData.addExpectedTypeMembers(parameters, result);
      completeAnnotationAttributeName(result, position, parameters);
      result.stopHere();
      return;
    }

    final InheritorsHolder inheritors = new InheritorsHolder(position, result);
    if (JavaSmartCompletionContributor.IN_TYPE_ARGS.accepts(position)) {
      new TypeArgumentCompletionProvider(false, inheritors)
          .addCompletions(parameters, new ProcessingContext(), result);
    }

    PrefixMatcher matcher = result.getPrefixMatcher();
    if (JavaSmartCompletionContributor.AFTER_NEW.accepts(position)) {
      new JavaInheritorsGetter(ConstructorInsertHandler.BASIC_INSTANCE)
          .generateVariants(parameters, matcher, inheritors);
    }

    if (IMPORT_REFERENCE.accepts(position)) {
      result.addElement(LookupElementBuilder.create("*"));
    }

    addKeywords(parameters, result);

    Set<String> usedWords = addReferenceVariants(parameters, result, inheritors);

    if (psiElement().inside(PsiLiteralExpression.class).accepts(position)) {
      PsiReference reference = position.getContainingFile().findReferenceAt(parameters.getOffset());
      if (reference == null || reference.isSoft()) {
        WordCompletionContributor.addWordCompletionVariants(result, parameters, usedWords);
      }
    }

    JavaGenerateMemberCompletionContributor.fillCompletionVariants(parameters, result);

    addAllClasses(parameters, result, inheritors);

    final PsiElement parent = position.getParent();
    if (parent instanceof PsiReferenceExpression
        && !((PsiReferenceExpression) parent).isQualified()
        && parameters.isExtendedCompletion()
        && StringUtil.isNotEmpty(matcher.getPrefix())) {
      new JavaStaticMemberProcessor(parameters).processStaticMethodsGlobally(matcher, result);
    }
    result.stopHere();
  }
 @Nullable
 public static String findReferencePrefix(CompletionParameters parameters) {
   return CompletionData.getReferencePrefix(parameters.getPosition(), parameters.getOffset());
 }
 public static String findJavaIdentifierPrefix(CompletionParameters parameters) {
   return findJavaIdentifierPrefix(parameters.getPosition(), parameters.getOffset());
 }