Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,9 @@ FormatStringConverter::FormatStringConverter(
ArgsOffset(FormatArgOffset + 1), LangOpts(LO) {
assert(ArgsOffset <= NumArgs);
FormatExpr = llvm::dyn_cast<StringLiteral>(
Args[FormatArgOffset]->IgnoreImplicitAsWritten());
Args[FormatArgOffset]->IgnoreUnlessSpelledInSource());

if (!FormatExpr || !FormatExpr->isOrdinary()) {
// Function must have a narrow string literal as its first argument.
conversionNotPossible("first argument is not a narrow string literal");
return;
}
assert(FormatExpr && FormatExpr->isOrdinary());

if (const std::optional<StringRef> MaybeMacroName =
formatStringContainsUnreplaceableMacro(Call, FormatExpr, SM, PP);
Expand Down
10 changes: 10 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,16 @@ Changes in existing checks
- Improved :doc:`misc-header-include-cycle
<clang-tidy/checks/misc/header-include-cycle>` check performance.

- Improved :doc:`modernize-use-std-format
<clang-tidy/checks/modernize/use-std-format>` check to correctly match
when the format string is converted to a different type by an implicit
constructor call.

- Improved :doc:`modernize-use-std-print
<clang-tidy/checks/modernize/use-std-print>` check to correctly match
when the format string is converted to a different type by an implicit
constructor call.

- Improved :doc:`portability-template-virtual-member-function
<clang-tidy/checks/portability/template-virtual-member-function>` check to
avoid false positives on pure virtual member functions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
// RUN: -std=c++20 %s modernize-use-std-format %t -- \
// RUN: -config="{CheckOptions: { \
// RUN: modernize-use-std-format.StrictMode: true, \
// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2; bad_format_type_strprintf', \
// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2; any_format_type_strprintf', \
// RUN: modernize-use-std-format.ReplacementFormatFunction: 'fmt::format', \
// RUN: modernize-use-std-format.FormatHeader: '<fmt/core.h>' \
// RUN: }}" \
// RUN: -- -isystem %clang_tidy_headers
// RUN: %check_clang_tidy -check-suffixes=,NOTSTRICT \
// RUN: -std=c++20 %s modernize-use-std-format %t -- \
// RUN: -config="{CheckOptions: { \
// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2; bad_format_type_strprintf', \
// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2; any_format_type_strprintf', \
// RUN: modernize-use-std-format.ReplacementFormatFunction: 'fmt::format', \
// RUN: modernize-use-std-format.FormatHeader: '<fmt/core.h>' \
// RUN: }}" \
Expand Down Expand Up @@ -56,12 +56,17 @@ std::string A(const std::string &in)
struct S {
S(...);
};
std::string bad_format_type_strprintf(const S &, ...);
std::string any_format_type_strprintf(const S &, ...);

std::string unsupported_format_parameter_type()
void unsupported_format_parameter_types()
{
// No fixes here because the format parameter of the function called is not a
// string.
return bad_format_type_strprintf("");
// CHECK-MESSAGES: [[@LINE-1]]:10: warning: unable to use 'fmt::format' instead of 'bad_format_type_strprintf' because first argument is not a narrow string literal [modernize-use-std-format]
auto s1 = any_format_type_strprintf(L"");
auto s2 = any_format_type_strprintf(42);

// But if we do pass a character string then that ought to be acceptable.
auto s3 = any_format_type_strprintf("Hello %s", "world");
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'fmt::format' instead of 'any_format_type_strprintf' [modernize-use-std-format]
// CHECK-FIXES: auto s3 = fmt::format("Hello {}", "world");
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

namespace absl
{
template <typename S, typename... Args>
std::string StrFormat(const S &format, const Args&... args);
template <typename... Args>
std::string StrFormat(const std::string_view &format, const Args&... args);
} // namespace absl

template <typename T>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@

#include <cstdio>
#include <string.h>
#include <string>

namespace absl
{
// Use const char * for the format since the real type is hard to mock up.
template <typename... Args>
int PrintF(const char *format, const Args&... args);
int PrintF(const std::string_view &format, const Args&... args);

template <typename... Args>
int FPrintF(FILE* output, const char *format, const Args&... args);
int FPrintF(FILE* output, const std::string_view &format, const Args&... args);
}

void printf_simple() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// RUN: %check_clang_tidy -std=c++23 %s modernize-use-std-print %t -- \
// RUN: -config="{CheckOptions: \
// RUN: { \
// RUN: modernize-use-std-print.PrintfLikeFunctions: 'unqualified_printf;::myprintf; mynamespace::myprintf2; bad_format_type_printf; fmt::printf', \
// RUN: modernize-use-std-print.FprintfLikeFunctions: '::myfprintf; mynamespace::myfprintf2; bad_format_type_fprintf; fmt::fprintf' \
// RUN: modernize-use-std-print.PrintfLikeFunctions: 'unqualified_printf;::myprintf; mynamespace::myprintf2; any_format_type_printf; fmt::printf', \
// RUN: modernize-use-std-print.FprintfLikeFunctions: '::myfprintf; mynamespace::myfprintf2; any_format_type_fprintf; fmt::fprintf' \
// RUN: } \
// RUN: }" \
// RUN: -- -isystem %clang_tidy_headers
Expand Down Expand Up @@ -98,18 +98,25 @@ void wide_string_not_supported() {
struct S {
S(...) {}
};
int bad_format_type_printf(const S &, ...);
int bad_format_type_fprintf(FILE *, const S &, ...);
int any_format_type_printf(const S &, ...);
int any_format_type_fprintf(FILE *, const S &, ...);

void unsupported_format_parameter_type()
{
// No fixes here because the format parameter of the function called is not a
// string.
bad_format_type_printf("Hello %s", "world");
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: unable to use 'std::print' instead of 'bad_format_type_printf' because first argument is not a narrow string literal [modernize-use-std-print]

bad_format_type_fprintf(stderr, "Hello %s", "world");
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: unable to use 'std::print' instead of 'bad_format_type_fprintf' because first argument is not a narrow string literal [modernize-use-std-print]
any_format_type_printf(L"Hello %s", "world");
any_format_type_fprintf(stderr, L"Hello %s", "world");
any_format_type_printf(42);
any_format_type_fprintf(stderr, 42L);

// But if we do pass a character string then that ought to be acceptable.
any_format_type_printf("Hello %s\n", "world");
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'any_format_type_printf' [modernize-use-std-print]
// CHECK-FIXES: std::println("Hello {}", "world");
any_format_type_fprintf(stderr, "Hello %s\n", "world");
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'any_format_type_fprintf' [modernize-use-std-print]
// CHECK-FIXES: std::println(stderr, "Hello {}", "world");
}

namespace fmt {
Expand Down