@NotNull
 public static LookupElement highlightIfNeeded(
     @Nullable PsiType qualifierType,
     @NotNull LookupElement item,
     @NotNull Object object,
     @NotNull PsiElement place) {
   if (shouldMarkRed(object, place)) {
     return PrioritizedLookupElement.withExplicitProximity(
         LookupElementDecorator.withRenderer(
             item,
             new LookupElementRenderer<LookupElementDecorator<LookupElement>>() {
               @Override
               public void renderElement(
                   LookupElementDecorator<LookupElement> element,
                   LookupElementPresentation presentation) {
                 element.getDelegate().renderElement(presentation);
                 presentation.setItemTextForeground(JBColor.RED);
               }
             }),
         -1);
   }
   if (containsMember(qualifierType, object)) {
     LookupElementRenderer<LookupElementDecorator<LookupElement>> boldRenderer =
         new LookupElementRenderer<LookupElementDecorator<LookupElement>>() {
           @Override
           public void renderElement(
               LookupElementDecorator<LookupElement> element,
               LookupElementPresentation presentation) {
             element.getDelegate().renderElement(presentation);
             presentation.setItemTextBold(true);
           }
         };
     return PrioritizedLookupElement.withExplicitProximity(
         LookupElementDecorator.withRenderer(item, boldRenderer), 1);
   }
   return item;
 }
  @Override
  public void renderElement(LookupElementPresentation presentation) {
    super.renderElement(presentation);
    final LookupElementPresentation qualifierPresentation = new LookupElementPresentation();
    myQualifier.renderElement(qualifierPresentation);
    String name = maybeAddParentheses(qualifierPresentation.getItemText());
    final String qualifierText =
        myQualifier.as(CastingLookupElementDecorator.CLASS_CONDITION_KEY) != null
            ? "(" + name + ")"
            : name;
    presentation.setItemText(qualifierText + "." + presentation.getItemText());

    if (myQualifier instanceof LookupItem && getQualifierObject() instanceof PsiClass) {
      String locationString =
          JavaPsiClassReferenceElement.getLocationString((LookupItem) myQualifier);
      presentation.setTailText(StringUtil.notNullize(presentation.getTailText()) + locationString);
    }
  }
  public void fillCompletions(
      CompletionParameters parameters, final Consumer<LookupElement> result) {
    final PsiElement position = parameters.getPosition();
    if (PsiTreeUtil.getParentOfType(position, PsiComment.class, false) != null) {
      return;
    }

    PsiStatement statement = PsiTreeUtil.getParentOfType(position, PsiExpressionStatement.class);
    if (statement == null) {
      statement = PsiTreeUtil.getParentOfType(position, PsiDeclarationStatement.class);
    }
    PsiElement prevLeaf = PsiTreeUtil.prevVisibleLeaf(position);
    if (statement != null
        && statement.getTextRange().getStartOffset() == position.getTextRange().getStartOffset()) {
      if (!psiElement()
          .withSuperParent(2, PsiSwitchStatement.class)
          .afterLeaf("{")
          .accepts(statement)) {
        PsiTryStatement tryStatement = PsiTreeUtil.getParentOfType(prevLeaf, PsiTryStatement.class);
        if (tryStatement == null
            || tryStatement.getCatchSections().length > 0
            || tryStatement.getFinallyBlock() != null) {
          result.consume(
              new OverrideableSpace(
                  createKeyword(position, PsiKeyword.FINAL), TailType.HUMBLE_SPACE_BEFORE_WORD));
        }
      }
    }

    if (isStatementPosition(position)) {
      if (PsiTreeUtil.getParentOfType(position, PsiSwitchStatement.class, false, PsiMember.class)
          != null) {
        result.consume(
            new OverrideableSpace(createKeyword(position, PsiKeyword.CASE), TailType.INSERT_SPACE));
        result.consume(
            new OverrideableSpace(
                createKeyword(position, PsiKeyword.DEFAULT), TailType.CASE_COLON));
        if (START_SWITCH.accepts(position)) {
          return;
        }
      }

      addBreakContinue(result, position);
      addStatementKeywords(result, position);
    }

    if (SUPER_OR_THIS_PATTERN.accepts(position)) {
      final boolean afterDot = AFTER_DOT.accepts(position);
      final boolean insideQualifierClass = isInsideQualifierClass(position);
      final boolean insideInheritorClass =
          PsiUtil.isLanguageLevel8OrHigher(position) && isInsideInheritorClass(position);
      if (!afterDot || insideQualifierClass || insideInheritorClass) {
        if (!afterDot || insideQualifierClass) {
          result.consume(createKeyword(position, PsiKeyword.THIS));
        }

        final LookupItem superItem = (LookupItem) createKeyword(position, PsiKeyword.SUPER);
        if (psiElement()
            .afterLeaf(psiElement().withText("{").withSuperParent(2, psiMethod().constructor(true)))
            .accepts(position)) {
          final PsiMethod method =
              PsiTreeUtil.getParentOfType(position, PsiMethod.class, false, PsiClass.class);
          assert method != null;
          final boolean hasParams = superConstructorHasParameters(method);
          superItem.setInsertHandler(
              new ParenthesesInsertHandler<LookupElement>() {
                @Override
                protected boolean placeCaretInsideParentheses(
                    InsertionContext context, LookupElement item) {
                  return hasParams;
                }

                @Override
                public void handleInsert(InsertionContext context, LookupElement item) {
                  super.handleInsert(context, item);
                  TailType.insertChar(context.getEditor(), context.getTailOffset(), ';');
                }
              });
        }

        result.consume(superItem);
      }
    }

    if (isExpressionPosition(position)) {
      if (PsiTreeUtil.getParentOfType(position, PsiAnnotation.class) == null) {
        result.consume(
            TailTypeDecorator.withTail(
                createKeyword(position, PsiKeyword.NEW), TailType.INSERT_SPACE));
        result.consume(createKeyword(position, PsiKeyword.NULL));
      }
      if (mayExpectBoolean(parameters)) {
        result.consume(createKeyword(position, PsiKeyword.TRUE));
        result.consume(createKeyword(position, PsiKeyword.FALSE));
      }
    }

    PsiFile file = position.getContainingFile();
    if (!(file instanceof PsiExpressionCodeFragment)
        && !(file instanceof PsiJavaCodeReferenceCodeFragment)
        && !(file instanceof PsiTypeCodeFragment)) {
      if (prevLeaf == null) {
        result.consume(
            new OverrideableSpace(
                createKeyword(position, PsiKeyword.PACKAGE), TailType.HUMBLE_SPACE_BEFORE_WORD));
        result.consume(
            new OverrideableSpace(
                createKeyword(position, PsiKeyword.IMPORT), TailType.HUMBLE_SPACE_BEFORE_WORD));
      } else if (END_OF_BLOCK.getValue().isAcceptable(position, position)
          && PsiTreeUtil.getParentOfType(position, PsiMember.class) == null) {
        result.consume(
            new OverrideableSpace(
                createKeyword(position, PsiKeyword.IMPORT), TailType.HUMBLE_SPACE_BEFORE_WORD));
      }
    }

    if ((isInsideParameterList(position)
            || isAtResourceVariableStart(position)
            || isAtCatchVariableStart(position))
        && !psiElement().afterLeaf(PsiKeyword.FINAL).accepts(position)
        && !AFTER_DOT.accepts(position)) {
      result.consume(
          TailTypeDecorator.withTail(
              createKeyword(position, PsiKeyword.FINAL), TailType.HUMBLE_SPACE_BEFORE_WORD));
    }

    if (isInstanceofPlace(position)) {
      result.consume(
          LookupElementDecorator.withInsertHandler(
              createKeyword(position, PsiKeyword.INSTANCEOF),
              new InsertHandler<LookupElementDecorator<LookupElement>>() {
                @Override
                public void handleInsert(
                    InsertionContext context, LookupElementDecorator<LookupElement> item) {
                  TailType tailType = TailType.HUMBLE_SPACE_BEFORE_WORD;
                  if (tailType.isApplicable(context)) {
                    tailType.processTail(context.getEditor(), context.getTailOffset());
                  }

                  if ('!' == context.getCompletionChar()) {
                    context.setAddCompletionChar(false);
                    context.commitDocument();
                    PsiInstanceOfExpression expr =
                        PsiTreeUtil.findElementOfClassAtOffset(
                            context.getFile(),
                            context.getStartOffset(),
                            PsiInstanceOfExpression.class,
                            false);
                    if (expr != null) {
                      String space =
                          context.getCodeStyleSettings().SPACE_WITHIN_PARENTHESES ? " " : "";
                      context
                          .getDocument()
                          .insertString(expr.getTextRange().getStartOffset(), "!(" + space);
                      context.getDocument().insertString(context.getTailOffset(), space + ")");
                    }
                  }
                }
              }));
    }

    if (isSuitableForClass(position)) {
      for (String s : ModifierChooser.getKeywords(position)) {
        result.consume(
            new OverrideableSpace(createKeyword(position, s), TailType.HUMBLE_SPACE_BEFORE_WORD));
      }
      result.consume(
          new OverrideableSpace(
              createKeyword(position, PsiKeyword.CLASS), TailType.HUMBLE_SPACE_BEFORE_WORD));
      if (PsiTreeUtil.getParentOfType(position, PsiCodeBlock.class, true, PsiMember.class)
          == null) {
        result.consume(
            new OverrideableSpace(
                createKeyword(position, PsiKeyword.INTERFACE), TailType.HUMBLE_SPACE_BEFORE_WORD));
        if (PsiUtil.getLanguageLevel(position).isAtLeast(LanguageLevel.JDK_1_5)) {
          result.consume(
              new OverrideableSpace(
                  createKeyword(position, PsiKeyword.ENUM), TailType.INSERT_SPACE));
        }
      }
    }

    addPrimitiveTypes(result, position);

    if (isAfterTypeDot(position)) {
      result.consume(createKeyword(position, PsiKeyword.CLASS));
    }

    addUnfinishedMethodTypeParameters(position, result);

    if (JavaMemberNameCompletionContributor.INSIDE_TYPE_PARAMS_PATTERN.accepts(position)) {
      result.consume(
          new OverrideableSpace(
              createKeyword(position, PsiKeyword.EXTENDS), TailType.HUMBLE_SPACE_BEFORE_WORD));
      result.consume(
          new OverrideableSpace(
              createKeyword(position, PsiKeyword.SUPER), TailType.HUMBLE_SPACE_BEFORE_WORD));
    }
  }
  @NotNull
  private static LookupElement castQualifier(
      @NotNull LookupElement item,
      @Nullable final PsiTypeLookupItem castTypeItem,
      @Nullable PsiType plainQualifier,
      JavaCompletionProcessor processor) {
    if (castTypeItem == null) {
      return item;
    }
    if (plainQualifier != null) {
      Object o = item.getObject();
      if (o instanceof PsiMethod) {
        PsiType castType = castTypeItem.getType();
        if (plainQualifier instanceof PsiClassType && castType instanceof PsiClassType) {
          PsiMethod method = (PsiMethod) o;
          PsiClassType.ClassResolveResult plainResult =
              ((PsiClassType) plainQualifier).resolveGenerics();
          PsiClass plainClass = plainResult.getElement();
          if (plainClass != null && plainClass.findMethodBySignature(method, true) != null) {
            PsiClass castClass = ((PsiClassType) castType).resolveGenerics().getElement();

            if (castClass == null || !castClass.isInheritor(plainClass, true)) {
              return item;
            }

            PsiSubstitutor plainSub = plainResult.getSubstitutor();
            PsiSubstitutor castSub =
                TypeConversionUtil.getSuperClassSubstitutor(plainClass, (PsiClassType) castType);
            PsiType returnType = method.getReturnType();
            if (method.getSignature(plainSub).equals(method.getSignature(castSub))) {
              PsiType typeAfterCast = toRaw(castSub.substitute(returnType));
              PsiType typeDeclared = toRaw(plainSub.substitute(returnType));
              if (typeAfterCast != null
                  && typeDeclared != null
                  && typeAfterCast.isAssignableFrom(typeDeclared)
                  && processor.isAccessible(plainClass.findMethodBySignature(method, true))) {
                return item;
              }
            }
          }
        }
      } else if (containsMember(plainQualifier, o)) {
        return item;
      }
    }

    return LookupElementDecorator.withInsertHandler(
        item,
        new InsertHandlerDecorator<LookupElement>() {
          @Override
          public void handleInsert(
              InsertionContext context, LookupElementDecorator<LookupElement> item) {
            final Document document = context.getEditor().getDocument();
            context.commitDocument();
            final PsiFile file = context.getFile();
            final PsiJavaCodeReferenceElement ref =
                PsiTreeUtil.findElementOfClassAtOffset(
                    file, context.getStartOffset(), PsiJavaCodeReferenceElement.class, false);
            if (ref != null) {
              final PsiElement qualifier = ref.getQualifier();
              if (qualifier != null) {
                final CommonCodeStyleSettings settings = context.getCodeStyleSettings();

                final String parenSpace = settings.SPACE_WITHIN_PARENTHESES ? " " : "";
                document.insertString(qualifier.getTextRange().getEndOffset(), parenSpace + ")");

                final String spaceWithin = settings.SPACE_WITHIN_CAST_PARENTHESES ? " " : "";
                final String prefix = "(" + parenSpace + "(" + spaceWithin;
                final String spaceAfter = settings.SPACE_AFTER_TYPE_CAST ? " " : "";
                final int exprStart = qualifier.getTextRange().getStartOffset();
                document.insertString(exprStart, prefix + spaceWithin + ")" + spaceAfter);

                CompletionUtil.emulateInsertion(context, exprStart + prefix.length(), castTypeItem);
                PsiDocumentManager.getInstance(file.getProject())
                    .doPostponedOperationsAndUnblockDocument(document);
                context.getEditor().getCaretModel().moveToOffset(context.getTailOffset());
              }
            }

            item.getDelegate().handleInsert(context);
          }
        });
  }