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);
    }
  }
  private static Set<LookupElement> suggestQualifierItems(
      CompletionParameters parameters,
      PsiJavaCodeReferenceElement qualifier,
      ElementFilter filter) {
    String referenceName = qualifier.getReferenceName();
    if (referenceName == null) {
      return Collections.emptySet();
    }

    PrefixMatcher qMatcher = new CamelHumpMatcher(referenceName);
    Set<LookupElement> plainVariants =
        JavaSmartCompletionContributor.completeReference(
            qualifier, qualifier, filter, true, true, parameters, qMatcher);

    for (PsiClass aClass :
        PsiShortNamesCache.getInstance(qualifier.getProject())
            .getClassesByName(referenceName, qualifier.getResolveScope())) {
      plainVariants.add(JavaClassNameCompletionContributor.createClassLookupItem(aClass, true));
    }

    if (!plainVariants.isEmpty()) {
      return plainVariants;
    }

    final Set<LookupElement> allClasses = new LinkedHashSet<LookupElement>();
    PsiElement qualifierName = qualifier.getReferenceNameElement();
    if (qualifierName != null) {
      JavaClassNameCompletionContributor.addAllClasses(
          parameters.withPosition(qualifierName, qualifierName.getTextRange().getEndOffset()),
          true,
          qMatcher,
          new CollectConsumer<LookupElement>(allClasses));
    }
    return allClasses;
  }
  @Override
  public void fillCompletionVariants(CompletionParameters parameters, CompletionResultSet result) {
    PsiElement position = parameters.getPosition();
    JavaClassReference reference =
        findJavaClassReference(position.getContainingFile(), parameters.getOffset());
    if (reference == null) {
      return;
    }

    String[] extendClassNames = reference.getExtendClassNames();
    PsiElement context = reference.getCompletionContext();
    if (extendClassNames != null && context instanceof PsiJavaPackage) {
      if (parameters.getCompletionType() == CompletionType.SMART) {
        JavaClassReferenceSet set = reference.getJavaClassReferenceSet();
        int setStart =
            set.getRangeInElement().getStartOffset()
                + set.getElement().getTextRange().getStartOffset();
        String fullPrefix =
            parameters
                .getPosition()
                .getContainingFile()
                .getText()
                .substring(setStart, parameters.getOffset());
        reference.processSubclassVariants(
            (PsiJavaPackage) context, extendClassNames, result.withPrefixMatcher(fullPrefix));
        return;
      }
      result.addLookupAdvertisement(
          "Press "
              + getActionShortcut(IdeActions.ACTION_SMART_TYPE_COMPLETION)
              + " to see inheritors of "
              + StringUtil.join(extendClassNames, ", "));
    }

    if (parameters.getCompletionType() == CompletionType.SMART) {
      return;
    }

    if (parameters.isExtendedCompletion()
        || parameters.getCompletionType() == CompletionType.CLASS_NAME) {
      JavaClassNameCompletionContributor.addAllClasses(parameters, result);
    } else {
      LegacyCompletionContributor.completeReference(parameters, result);
    }
    result.stopHere();
  }
  private static void suggestNonImportedClasses(
      CompletionParameters parameters,
      CompletionResultSet result,
      @Nullable JavaCompletionSession session) {
    JavaClassNameCompletionContributor.addAllClasses(
        parameters,
        true,
        result.getPrefixMatcher(),
        element -> {
          if (session != null && session.alreadyProcessed(element)) {
            return;
          }
          JavaPsiClassReferenceElement classElement =
              element.as(JavaPsiClassReferenceElement.CLASS_CONDITION_KEY);
          if (classElement != null) {
            classElement.setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE);
            element =
                JavaClassNameCompletionContributor.highlightIfNeeded(classElement, parameters);
          }

          result.addElement(element);
        });
  }
  private static void suggestNonImportedClasses(
      CompletionParameters parameters, CompletionResultSet result) {
    final ClassByNameMerger merger =
        new ClassByNameMerger(parameters.getInvocationCount() == 0, result);

    JavaClassNameCompletionContributor.addAllClasses(
        parameters,
        true,
        JavaCompletionSorting.addJavaSorting(parameters, result).getPrefixMatcher(),
        new Consumer<LookupElement>() {
          @Override
          public void consume(LookupElement element) {
            JavaPsiClassReferenceElement classElement =
                element.as(JavaPsiClassReferenceElement.CLASS_CONDITION_KEY);
            if (classElement != null) {
              classElement.setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE);
            }

            merger.consume(classElement);
          }
        });

    merger.finishedClassProcessing();
  }