static List<? extends LookupElement> createLookupElements(
      CompletionElement completionElement, PsiJavaReference reference) {
    Object completion = completionElement.getElement();
    assert !(completion instanceof LookupElement);

    if (reference instanceof PsiJavaCodeReferenceElement) {
      if (completion instanceof PsiMethod
          && ((PsiJavaCodeReferenceElement) reference).getParent()
              instanceof PsiImportStaticStatement) {
        return Collections.singletonList(
            JavaLookupElementBuilder.forMethod((PsiMethod) completion, PsiSubstitutor.EMPTY));
      }

      if (completion instanceof PsiClass) {
        return JavaClassNameCompletionContributor.createClassLookupItems(
            (PsiClass) completion,
            JavaClassNameCompletionContributor.AFTER_NEW.accepts(reference),
            JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER,
            Conditions.<PsiClass>alwaysTrue());
      }
    }

    if (reference instanceof PsiMethodReferenceExpression
        && completion instanceof PsiMethod
        && ((PsiMethod) completion).isConstructor()) {
      return Collections.singletonList(
          JavaLookupElementBuilder.forMethod(
              (PsiMethod) completion, "new", PsiSubstitutor.EMPTY, null));
    }

    PsiSubstitutor substitutor = completionElement.getSubstitutor();
    if (substitutor == null) substitutor = PsiSubstitutor.EMPTY;
    if (completion instanceof PsiClass) {
      return Collections.singletonList(
          JavaClassNameCompletionContributor.createClassLookupItem((PsiClass) completion, true)
              .setSubstitutor(substitutor));
    }
    if (completion instanceof PsiMethod) {
      return Collections.singletonList(
          new JavaMethodCallElement((PsiMethod) completion).setQualifierSubstitutor(substitutor));
    }
    if (completion instanceof PsiVariable) {
      return Collections.singletonList(
          new VariableLookupItem((PsiVariable) completion).setSubstitutor(substitutor));
    }

    return Collections.singletonList(LookupItemUtil.objectToLookupItem(completion));
  }
  private static List<? extends LookupElement> createLookupElements(
      CompletionElement completionElement, PsiJavaReference reference) {
    Object completion = completionElement.getElement();
    assert !(completion instanceof LookupElement);

    if (reference instanceof PsiJavaCodeReferenceElement) {
      if (completion instanceof PsiMethod
          && ((PsiJavaCodeReferenceElement) reference).getParent()
              instanceof PsiImportStaticStatement) {
        return Collections.singletonList(
            JavaLookupElementBuilder.forMethod((PsiMethod) completion, PsiSubstitutor.EMPTY));
      }

      if (completion instanceof PsiClass) {
        return JavaClassNameCompletionContributor.createClassLookupItems(
            (PsiClass) completion,
            JavaClassNameCompletionContributor.AFTER_NEW.accepts(reference),
            JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER,
            Conditions.<PsiClass>alwaysTrue());
      }
    }

    if (reference instanceof PsiMethodReferenceExpression
        && completion instanceof PsiMethod
        && ((PsiMethod) completion).isConstructor()) {
      return Collections.singletonList(
          JavaLookupElementBuilder.forMethod(
              (PsiMethod) completion, "new", PsiSubstitutor.EMPTY, null));
    }

    LookupElement _ret = LookupItemUtil.objectToLookupItem(completion);
    if (_ret instanceof LookupItem) {
      final PsiSubstitutor substitutor = completionElement.getSubstitutor();
      if (substitutor != null) {
        ((LookupItem<?>) _ret).setAttribute(LookupItem.SUBSTITUTOR, substitutor);
      }
    }
    return Collections.singletonList(_ret);
  }
  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;
  }