@NotNull
  @Override
  public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
    return new JavaElementVisitor() {

      @Override
      public void visitNewExpression(@NotNull PsiNewExpression expression) {
        if (ConstructionUtils.isReferenceTo(expression.getClassReference(), "java.text.MessageFormat")) {
          PsiMethod method = expression.resolveMethod();
          if (method == null || !method.isConstructor()) {
            return;
          }

          PsiParameterList parameterList = method.getParameterList();
          if (parameterList.getParametersCount() < 1) {
            return;
          }
          PsiParameter[] parameters = parameterList.getParameters();
          if (parameters.length < 1 || parameters[0] == null) {
            return;
          }
          PsiType type = parameters[0].getType();
          if (!CommonClassNames.JAVA_LANG_STRING.equals(type.getCanonicalText())) {
            return;
          }
          PsiExpressionList argumentList = expression.getArgumentList();
          if (argumentList == null) {
            return;
          }
          checkStringFormatAndGetIndexes(argumentList.getExpressions()[0]);
        }
      }

      @Override
      public void visitMethodCallExpression(@NotNull PsiMethodCallExpression call) {
        if (PATTERN_METHODS.test(call)) {
          List<MessageFormatUtil.MessageFormatPlaceholder> indexes =
            checkStringFormatAndGetIndexes(call.getArgumentList().getExpressions()[0]);
          if (indexes != null) {
            checkIndexes(call, indexes);
          }
        }
      }

      private void checkIndexes(@NotNull PsiMethodCallExpression call,
                                @NotNull List<MessageFormatUtil.MessageFormatPlaceholder> indexes) {
        PsiExpression[] expressions = call.getArgumentList().getExpressions();
        for (PsiExpression expression : expressions) {
          if (expression == null || expression instanceof PsiEmptyExpressionImpl) {
            return;
          }
        }
        int count = call.getArgumentList().getExpressionCount();
        int argumentNumber = count - 1;
        List<Integer> notFoundArguments = new ArrayList<>();
        Set<Integer> usedArgumentIndexes = new HashSet<>();
        for (MessageFormatUtil.MessageFormatPlaceholder index : indexes) {
          if (index.index() >= argumentNumber) {
            notFoundArguments.add(index.index());
          }
          usedArgumentIndexes.add(index.index());
        }
        List<Integer> notUsedArguments = new ArrayList<>();
        for (int i = 0; i < argumentNumber; i++) {
          if (!usedArgumentIndexes.contains(i)) {
            notUsedArguments.add(i);
          }
        }
        if (notFoundArguments.isEmpty() && notUsedArguments.isEmpty()) {
          return;
        }

        PsiIdentifier[] identifiers = PsiTreeUtil.getChildrenOfType(call.getMethodExpression(), PsiIdentifier.class);
        if (identifiers == null || identifiers.length != 1) {
          return;
        }
        PsiIdentifier identifier = identifiers[0];
        if (!notFoundArguments.isEmpty()) {
          if (notFoundArguments.size() == 1) {
            holder.registerProblem(identifier, InspectionGadgetsBundle.message("inspection.incorrect.message.format.not.found.argument",
                                                                               notFoundArguments.iterator().next()));
          }
          else {
            StringJoiner joiner = new StringJoiner(", ");
            for (Integer notFoundArgument : notFoundArguments) {
              joiner.add(notFoundArgument.toString());
            }
            holder.registerProblem(identifier, InspectionGadgetsBundle.message("inspection.incorrect.message.format.not.found.arguments",
                                                                               joiner.toString()));
          }
        }

        if (!notUsedArguments.isEmpty()) {
          for (Integer notUsedArgument : notUsedArguments) {
            int expressionIndex = notUsedArgument + 1;
            PsiExpression expression = expressions[expressionIndex];
            holder.registerProblem(expression,
                                   InspectionGadgetsBundle.message("inspection.incorrect.message.format.not.used.argument",
                                                                   notUsedArgument));
          }
        }
      }

      @Nullable
      private List<MessageFormatUtil.MessageFormatPlaceholder> checkStringFormatAndGetIndexes(@Nullable PsiExpression expression) {
        if (expression == null) {
          return null;
        }
        boolean immediatePattern = true;
        String pattern = null;

        if (expression instanceof PsiLiteralExpression literalExpression) {
          pattern = literalExpression.getText();
        }

        if (pattern == null &&
            expression instanceof PsiReferenceExpression referenceExpression &&
            referenceExpression.resolve() instanceof PsiVariable variable &&
            variable.hasModifierProperty(PsiModifier.FINAL)) {
          PsiExpression initializer = variable.getInitializer();
          if (initializer instanceof PsiLiteralExpression literalExpression) {
            pattern = literalExpression.getText();
            expression = initializer;
          }
        }
        if (pattern == null) {
          immediatePattern = false;
          CommonDataflow.DataflowResult dataflowResult = CommonDataflow.getDataflowResult(expression);
          if (dataflowResult == null) return null;
          Set<Object> values = dataflowResult.getExpressionValues(expression);
          if (values.size() != 1) return null;
          if (!(values.iterator().next() instanceof String value)) {
            return null;
          }
          pattern = value;
        }

        MessageFormatUtil.MessageFormatResult result = MessageFormatUtil.checkFormat(pattern);
        if (result.valid()) {
          return result.placeholders();
        }

        if (!immediatePattern) {
          Optional<MessageFormatUtil.MessageFormatError> toHighlight =
            result.errors().stream()
              .filter(t -> t.errorType().getSeverity().ordinal() <= MessageFormatUtil.ErrorSeverity.WARNING.ordinal())
              .min(Comparator.comparing(t -> t.errorType().getSeverity()));
          if (toHighlight.isEmpty()) {
            return null;
          }
          MessageFormatUtil.MessageFormatError error = toHighlight.get();
          createError(expression, error, pattern, 0, expression.getTextLength());
        }
        else {
          for (MessageFormatUtil.MessageFormatError error : result.errors()) {
            createError(expression, error, pattern, -1, 0);
          }
        }

        if (!ContainerUtil.exists(result.errors(),
                                  error -> error.errorType().getSeverity() == MessageFormatUtil.ErrorSeverity.RUNTIME_EXCEPTION)) {
          return result.placeholders();
        }
        return null;
      }

      @Nullable
      private static String getRelatedText(@NotNull String pattern, @NotNull MessageFormatUtil.MessageFormatError error) {
        if (error.fromIndex() < 0 || error.toIndex() > pattern.length() || error.toIndex() < error.fromIndex()) {
          return null;
        }
        return pattern.substring(error.fromIndex(), error.toIndex());
      }

      private void createError(@NotNull PsiExpression expression,
                               @NotNull MessageFormatUtil.MessageFormatError error,
                               @NotNull String pattern,
                               int start, int end) {
        MessageFormatUtil.MessageFormatErrorType type = error.errorType();
        //it's relevant mostly for IDEA files
        if (type == MessageFormatUtil.MessageFormatErrorType.QUOTED_PLACEHOLDER) {
          return;
        }
        String relatedText = getRelatedText(pattern, error);
        if (relatedText == null) {
          return;
        }
        String errorText = getMessageFormatTemplate(type, relatedText);
        if (start >= 0) {
          errorText = InspectionGadgetsBundle.message("inspection.incorrect.message.format.pattern", errorText, pattern);
        }
        else {
          start = error.fromIndex();
          end = error.toIndex();
        }
        ProblemHighlightType highlightType = getCustomHighlightType(type);
        if (highlightType == null) {
          holder.registerProblem(expression, TextRange.create(start, end), errorText);
        }
        else {
          holder.registerProblem(expression, errorText, highlightType, TextRange.create(start, end));
        }
      }

      @Nullable
      private static ProblemHighlightType getCustomHighlightType(@NotNull MessageFormatUtil.MessageFormatErrorType type) {
        if (type.getSeverity() == MessageFormatUtil.ErrorSeverity.WARNING ||
            type.getSeverity() == MessageFormatUtil.ErrorSeverity.WEAK_WARNING) {
          return ProblemHighlightType.WEAK_WARNING;
        }
        return null;
      }
    };
  }
@NotNull
  @Override
  public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly)