@NotNull
  @Override
  public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
    return new JavaElementVisitor() {
      @Override
      public void visitAssignmentExpression(@NotNull PsiAssignmentExpression expression) {
        checkNulls(expression.getType(), expression.getRExpression(),
                   JavaBundle.message("inspection.null.value.for.optional.context.assignment"));
      }

      @Override
      public void visitMethodCallExpression(@NotNull PsiMethodCallExpression call) {
        PsiExpression[] args = call.getArgumentList().getExpressions();
        if (args.length == 0) return;
        PsiMethod method = call.resolveMethod();
        if (method == null) return;
        PsiParameter[] parameters = method.getParameterList().getParameters();
        if (parameters.length > args.length) return;
        boolean varArgCall = method.isVarArgs() && MethodCallUtils.isVarArgCall(call);
        if (!varArgCall && parameters.length < args.length) return;
        for (int i = 0; i < args.length; i++) {
          PsiParameter parameter = parameters[Math.min(parameters.length - 1, i)];
          PsiType type = parameter.getType();
          if (varArgCall && i >= parameters.length - 1 && type instanceof PsiEllipsisType) {
            type = ((PsiEllipsisType)type).getComponentType();
          }
          checkNulls(type, args[i], JavaBundle.message("inspection.null.value.for.optional.context.parameter"));
        }
      }

      @Override
      public void visitLambdaExpression(@NotNull PsiLambdaExpression lambda) {
        PsiElement body = lambda.getBody();
        if (body instanceof PsiExpression) {
          checkNulls(LambdaUtil.getFunctionalInterfaceReturnType(lambda), (PsiExpression)body,
                     JavaBundle.message("inspection.null.value.for.optional.context.lambda"));
        }
      }

      @Override
      public void visitReturnStatement(@NotNull PsiReturnStatement statement) {
        checkNulls(PsiTypesUtil.getMethodReturnType(statement), statement.getReturnValue(),
                   JavaBundle.message("inspection.null.value.for.optional.context.return"));
      }

      @Override
      public void visitVariable(@NotNull PsiVariable variable) {
        checkNulls(variable.getType(), variable.getInitializer(),
                   JavaBundle.message("inspection.null.value.for.optional.context.declaration"));
      }

      @Override
      public void visitBinaryExpression(@NotNull PsiBinaryExpression binOp) {
        if (!WARN_ON_COMPARISON) return;
        PsiExpression value = ExpressionUtils.getValueComparedWithNull(binOp);
        if (value != null &&
            TypeUtils.isOptional(value.getType()) &&
            !hasSubsequentIsPresentCall(value, binOp, JavaTokenType.EQEQ.equals(binOp.getOperationTokenType())) &&
            !comesFromMapGet(value)) {
          boolean useIsEmpty =
            binOp.getOperationTokenType().equals(JavaTokenType.EQEQ) &&
            PsiUtil.getLanguageLevel(binOp).isAtLeast(LanguageLevel.JDK_11);
          holder.problem(binOp, JavaBundle.message("inspection.null.value.for.optional.assigned.message"))
            .fix(new ReplaceWithIsPresentFix(useIsEmpty))
            .fix(new UpdateInspectionOptionFix(OptionalAssignedToNullInspection.this, "WARN_ON_COMPARISON",
                                               JavaBundle.message("inspection.null.value.for.optional.assigned.ignore.fix.name"), false))
            .register();
        }
      }

      private static boolean comesFromMapGet(PsiExpression value) {
        PsiLocalVariable local = ExpressionUtils.resolveLocalVariable(value);
        if (local != null) {
          PsiExpression initializer = ContainerUtil.getOnlyItem(DfaUtil.getVariableValues(local, value));
          if (initializer != null) {
            value = initializer;
          }
        }
        return MAP_GET.matches(ExpressionUtils.resolveExpression(value));
      }

      private static boolean hasSubsequentIsPresentCall(@NotNull PsiExpression optionalExpression,
                                                        @NotNull PsiExpression previousExpression,
                                                        boolean negated) {
        PsiPolyadicExpression parent =
          ObjectUtils.tryCast(PsiUtil.skipParenthesizedExprUp(previousExpression.getParent()), PsiPolyadicExpression.class);
        if (parent == null) return false;
        IElementType expectedToken = negated ? JavaTokenType.OROR : JavaTokenType.ANDAND;
        if (!parent.getOperationTokenType().equals(expectedToken)) return false;
        PsiExpression nextExpression =
          StreamEx.of(parent.getOperands()).dropWhile(op -> !PsiTreeUtil.isAncestor(op, previousExpression, false))
                  .skip(1)
                  .findFirst()
                  .orElse(null);
        nextExpression = PsiUtil.skipParenthesizedExprDown(nextExpression);
        if (nextExpression == null) return false;
        if (negated) {
          if (!BoolUtils.isNegation(nextExpression)) return false;
          nextExpression = BoolUtils.getNegated(nextExpression);
        }
        if (!(nextExpression instanceof PsiMethodCallExpression call)) return false;
        if (!"isPresent".equals(call.getMethodExpression().getReferenceName()) || !call.getArgumentList().isEmpty()) return false;
        PsiExpression qualifier = call.getMethodExpression().getQualifierExpression();
        return qualifier != null && PsiEquivalenceUtil.areElementsEquivalent(qualifier, optionalExpression);
      }

      private void checkNulls(PsiType type, PsiExpression expression, String declaration) {
        if (expression != null && TypeUtils.isOptional(type)) {
          ExpressionUtils.nonStructuralChildren(expression).filter(ExpressionUtils::isNullLiteral)
            .forEach(nullLiteral -> register(nullLiteral, (PsiClassType)type, declaration));
        }
      }

      private void register(PsiExpression expression, PsiClassType type, String contextName) {
        holder.registerProblem(expression,
                               JavaBundle.message("inspection.null.value.for.optional.message", contextName),
                               new ReplaceWithEmptyOptionalFix(type));
      }
    };
  }
@NotNull
  @Override
  public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly)