@NotNull
  @Override
  public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
    return new JavaElementVisitor() {
      @Override
      public void visitLiteralExpression(@NotNull PsiLiteralExpression expression) {
        if (ChronoUtil.isPatternForDateFormat(expression)) {
          processLiteral(expression);
        }
      }

      private void processLiteral(@NotNull PsiLiteralExpression expression) {
        String pattern = ObjectUtils.tryCast(expression.getValue(), String.class);
        if (pattern == null) return;
        List<Token> tokens = new ArrayList<>();
        char lastChar = 0;
        int countNonFormat = 0;
        char[] array = pattern.toCharArray();
        boolean inQuote = false;
        for (int pos = 0; pos < array.length; pos++) {
          char c = array[pos];
          if (c == '\'') inQuote = !inQuote;
          if (c == lastChar) continue;
          lastChar = c;
          if (!inQuote && (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')) {
            countNonFormat = 0;
            tokens.add(new Token(pos, array));
            continue;
          }
          countNonFormat++;
          if (countNonFormat > 3) {
            tokens.add(null);
          }
        }
        for (int i = 0; i < tokens.size(); i++) {
          Token token = tokens.get(i);
          Token prev = i > 0 ? tokens.get(i - 1) : null;
          Token next = i < tokens.size() - 1 ? tokens.get(i + 1) : null;
          Problem problem = getProblem(token, prev, next);
          if (problem != null) {
            TextRange range = ExpressionUtils.findStringLiteralRange(expression, token.pos, token.pos + token.length);
            if (range != null) {
              holder.registerProblem(expression, range, problem.toString(), new IncorrectDateFormatFix(token, range));
            }
          }
        }
      }

      @Contract("null, _, _ -> null")
      private static Problem getProblem(@Nullable Token token, @Nullable Token prev, @Nullable Token next) {
        if (token == null) return null;
        switch (token.character) {
          case 'Y' -> {
            if (!hasNeighbor("w", prev, next)) {
              return new Problem(token, "week year", "year");
            }
          }
          case 'M' -> {
            if (hasNeighbor("HhKk", prev, next) && !hasNeighbor("yd", prev, next)) {
              return new Problem(token, "month", "minute");
            }
          }
          case 'm' -> {
            if (hasNeighbor("yd", prev, next) && !hasNeighbor("HhKk", prev, next)) {
              return new Problem(token, "minute", "month");
            }
          }
          case 'D' -> {
            if (hasNeighbor("ML", prev, next)) {
              return new Problem(token, "day of year", "day of month");
            }
          }
          case 'S' -> {
            if (hasNeighbor("m", prev, next)) {
              return new Problem(token, "milliseconds", "seconds");
            }
          }
        }
        return null;
      }

      private static boolean hasNeighbor(@NotNull @NonNls String neighbors, @Nullable Token prev, @Nullable Token next) {
        return prev != null && neighbors.indexOf(prev.character) >= 0 ||
               next != null && neighbors.indexOf(next.character) >= 0;
      }
    };
  }
@NotNull
  @Override
  public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly)