@Nullable
    public static FormatArgument extract(@NotNull PsiCallExpression expression,
                                         @NotNull List<String> methodNames,
                                         @NotNull List<String> classNames,
                                         boolean allowNotConstant) {
      final PsiExpressionList argumentList = expression.getArgumentList();
      if (argumentList == null) return null;
      PsiExpression[] arguments = argumentList.getExpressions();

      final PsiExpression formatArgument;
      int formatArgumentIndex;
      if (expression instanceof PsiMethodCallExpression && FormatUtils.STRING_FORMATTED.matches(expression)) {
        formatArgument = ((PsiMethodCallExpression)expression).getMethodExpression().getQualifierExpression();
        formatArgumentIndex = 0;
      }
      else {
        if (!(expression instanceof PsiMethodCallExpression) ||
            !FormatUtils.isFormatCall((PsiMethodCallExpression)expression, methodNames, classNames)) {
          return fromPrintFormatAnnotation(expression);
        }

        formatArgumentIndex =
          IntStream.range(0, arguments.length).filter(i -> ExpressionUtils.hasStringType(arguments[i])).findFirst().orElse(-1);
        if (formatArgumentIndex < 0) {
          return null;
        }

        formatArgument = arguments[formatArgumentIndex];
        formatArgumentIndex++;
      }
      if (!ExpressionUtils.hasStringType(formatArgument) || (!allowNotConstant && !PsiUtil.isConstantExpression(formatArgument))) {
        return null;
      }
      return new FormatArgument(formatArgumentIndex, formatArgument);
    }
@Nullable
    public static FormatArgument extract(@NotNull PsiCallExpression expression,
                                         @NotNull List<String> methodNames,
                                         @NotNull List<String> classNames,
                                         boolean allowNotConstant)