@Override
  public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
    boolean java11 = PsiUtil.getLanguageLevel(holder.getFile()).isAtLeast(LanguageLevel.JDK_11);
    return new JavaElementVisitor() {
      @Override
      public void visitLambdaExpression(@NotNull PsiLambdaExpression lambda) {
        super.visitLambdaExpression(lambda);
        PsiElement body = lambda.getBody();
        if (body == null) return;
        PsiType type = lambda.getFunctionalInterfaceType();
        if (!(type instanceof PsiClassType)) return;
        PsiElement parent = PsiUtil.skipParenthesizedExprUp(lambda.getParent());
        if(parent instanceof PsiTypeCastExpression &&
           InheritanceUtil.isInheritor(((PsiTypeCastExpression)parent).getType(), CommonClassNames.JAVA_IO_SERIALIZABLE)) return;
        PsiExpression expression = PsiUtil.skipParenthesizedExprDown(LambdaUtil.extractSingleExpressionFromBody(body));
        if (expression == null) return;
        PsiParameter[] parameters = lambda.getParameterList().getParameters();
        if (parameters.length == 1) {
          PsiParameter parameter = parameters[0];
          if (ExpressionUtils.isReferenceTo(expression, parameter)) {
            handleFunctionIdentity(lambda, (PsiClassType)type);
          }
          if (expression instanceof PsiMethodCallExpression call) {
            PsiClass aClass = ((PsiClassType)type).resolve();
            if (aClass != null && CommonClassNames.JAVA_UTIL_FUNCTION_PREDICATE.equals(aClass.getQualifiedName())) {
              handlePredicateIsEqual(lambda, parameter, call);
              handlePatternAsPredicate(lambda, parameter, call);
            }
          }
          handlePatternNegate(lambda, parameter, expression);
        }
      }

      private void handlePatternNegate(PsiLambdaExpression lambda, PsiParameter parameter, PsiExpression expression) {
        if (!BoolUtils.isNegation(expression)) return;
        PsiMethodCallExpression negated = ObjectUtils.tryCast(BoolUtils.getNegated(expression), PsiMethodCallExpression.class);
        if (!PREDICATE_TEST.test(negated)) return;
        if (!ExpressionUtils.isReferenceTo(negated.getArgumentList().getExpressions()[0], parameter)) return;

        PsiExpression qualifier = negated.getMethodExpression().getQualifierExpression();
        if (!ExpressionUtils.isSafelyRecomputableExpression(qualifier) || ExpressionUtils.isReferenceTo(qualifier, parameter)) return;

        PsiType lambdaType = ExpectedTypeUtils.findExpectedType(lambda, false);
        if (lambdaType == null || qualifier.getType() == null || !lambdaType.isAssignableFrom(qualifier.getType())) return;

        registerProblem(lambda, "Pattern.negate()",
                        ParenthesesUtils.getText(qualifier, PsiPrecedenceUtil.METHOD_CALL_PRECEDENCE) + ".negate()");
      }

      private void handleFunctionIdentity(PsiLambdaExpression lambda, PsiClassType type) {
        PsiClass aClass = type.resolve();
        if (aClass == null || !CommonClassNames.JAVA_UTIL_FUNCTION_FUNCTION.equals(aClass.getQualifiedName())) return;
        PsiType[] typeParameters = type.getParameters();
        if (typeParameters.length != 2 || !typeParameters[1].isAssignableFrom(typeParameters[0])) return;
        @NlsSafe String replacement = CommonClassNames.JAVA_UTIL_FUNCTION_FUNCTION + ".identity()";
        if (!LambdaUtil.isSafeLambdaReplacement(lambda, replacement)) return;
        registerProblem(lambda, "Function.identity()", replacement);
      }

      private void handlePatternAsPredicate(PsiLambdaExpression lambda, PsiParameter parameter, PsiMethodCallExpression call) {
        if (!MATCHER_FIND.test(call) && (!java11 || !MATCHER_MATCHES.test(call))) return;
        PsiMethodCallExpression matcherCall = MethodCallUtils.getQualifierMethodCall(call);
        if (!PATTERN_MATCHER.test(matcherCall)) return;
        PsiExpression matcherArg = matcherCall.getArgumentList().getExpressions()[0];
        if (!ExpressionUtils.isReferenceTo(matcherArg, parameter)) return;
        PsiExpression pattern = matcherCall.getMethodExpression().getQualifierExpression();
        if (pattern == null || !LambdaCanBeMethodReferenceInspection.checkQualifier(pattern)) return;
        String methodName = "find".equalsIgnoreCase(call.getMethodExpression().getReferenceName()) ? "asPredicate" : "asMatchPredicate";
        registerProblem(lambda, "Pattern." + methodName + "()",
                        ParenthesesUtils.getText(pattern, ParenthesesUtils.POSTFIX_PRECEDENCE) + "." + methodName + "()");
      }

      private void handlePredicateIsEqual(PsiLambdaExpression lambda, PsiParameter parameter, PsiMethodCallExpression call) {
        if (MethodCallUtils.isCallToStaticMethod(call, "java.util.Objects", "equals", 2)) {
          PsiExpression[] args = call.getArgumentList().getExpressions();
          if (args.length == 2) {
            PsiExpression comparedWith;
            if (ExpressionUtils.isReferenceTo(args[0], parameter)) {
              comparedWith = args[1];
            }
            else if (ExpressionUtils.isReferenceTo(args[1], parameter)) {
              comparedWith = args[0];
            }
            else return;
            if (LambdaCanBeMethodReferenceInspection.checkQualifier(comparedWith)) {
              registerProblem(lambda, "Predicate.isEqual()",
                              CommonClassNames.JAVA_UTIL_FUNCTION_PREDICATE + ".isEqual(" + comparedWith.getText() + ")");
            }
          }
        }
      }

      private void registerProblem(PsiLambdaExpression lambda, @NlsSafe String displayReplacement, @NlsSafe String replacement) {
        holder.registerProblem(lambda, JavaAnalysisBundle.message("inspection.can.be.replaced.with.message", displayReplacement),
                               new ReplaceWithFunctionCallFix(replacement, displayReplacement));
      }
    };
  }
@Override
  public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly)