How to apply printf(...) inspection hint to a custom function when using IntelliJ Reshaper in Visual C++?

Viewed 175

IntelliJ Reshaper will offer fantastic inspection hints for the following:

printf("%s", 5); // have warning inspection hint.

Which will indicate that the format string does not match the type of its arguments. I love this.

Now I want to make a custom function have the same feature, how to implement it?

https://www.jetbrains.com/help/resharper/Code_Analysis__String_Formatting_Methods.html#custom

Similar to the custom string formatting methods mentioned in the link above, I tried to use the following code in Visual C++, but it didn't work. It seems that it only has an effect on C#.

#include <string>

std::string format_v(const char* formatString, va_list args)
{
    std::string result;
    auto len = _vscprintf(formatString, args);
    if (len == -1)
        return result;
    result.resize(len);
    vsprintf_s(&result[0], result.size() + 1, formatString, args);
    return result;
}

[StringFormatMethod("formatString")]
std::string format(const char* formatString, ...)
{
    std::string result;
    if (!formatString)
        return result;
    va_list args;
    va_start(args, formatString);
    result = format_v(formatString, args);
    va_end(args);

    return result;
}

int main()
{
    printf("%s", 5); // have warning inspection hint.
    std::string msg = format("%s", 122); // no inspection hint.
    return 0; 
}

build failed:

warning C4467: usage of ATL attributes is deprecated
error C2337: 'StringFormatMethod': attribute not found

I try to clarify this problem, and hope you can understand it. Sorry for my bad English.

2 Answers

AFAIK, unless they have implemented them in very recent versions, format warnings have never been supported by MSVC (Microsoft's C++ compiler). GCC has had them (as an extension) for years, and so has Clang:

__attribute__((format(printf, 1, 2)))
void my_print_func(const char *const s, ...) {
    // ...
}

You could try to work around this by compiling your code with Clang/LLVM on Windows (clang-cl has achieved an extremely high degree of compatibility with MSVC's cl). After you are certain there are no errors in your strings, you may switch back to cl.exe or stick with using clang-cl.

In order to keep those GCC-specific attributes from breaking your code under MSVC, you may use a macro like the following one, which I've found in the Chromium codebase:

#if defined(__GNUC__) || defined(__clang__)
#define PRINTF_FORMAT(format_param, dots_param) \
  __attribute__((format(printf, format_param, dots_param)))
#else
#define PRINTF_FORMAT(format_param, dots_param)
#endif

PRINTF_FORMAT will be ignored under MSVC, while it will trigger format warnings under GCC and Clang.

Bonus: C++20 includes std::format, which provides you a newer, type safe way to format strings, as previously implemented by the {fmt} library. You may give a look to {fmt}, or consider switching to C++20 and use std::format (which MSVC has recently implemented and it is going to be released soon).

You can use for example the [[rscpp::format]] attribute or a number of other supported attributes. See RSCPP-15890 for discussion and examples.

Related