Skip to content

Commit b334ec4

Browse files
committed
[clang-tidy] modernize-use-std-print,format: Fix checks with Abseil functions
These checks previously failed with absl::StrFormat and absl::PrintF etc. with: Unable to use 'std::format' instead of 'StrFormat' because first argument is not a narrow string literal [modernize-use-std-format] because FormatStringConverter was rejecting the format string if it had already converted into a different type. Fix the tests so that they check this case properly by accepting string_view rather than const char * and fix the check so that these tests pass. Update the existing tests that checked for the error message that can no longer happen. Fixes: #129484
1 parent 33bbce5 commit b334ec4

File tree

6 files changed

+44
-25
lines changed

6 files changed

+44
-25
lines changed

clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,13 +207,9 @@ FormatStringConverter::FormatStringConverter(
207207
ArgsOffset(FormatArgOffset + 1), LangOpts(LO) {
208208
assert(ArgsOffset <= NumArgs);
209209
FormatExpr = llvm::dyn_cast<StringLiteral>(
210-
Args[FormatArgOffset]->IgnoreImplicitAsWritten());
210+
Args[FormatArgOffset]->IgnoreUnlessSpelledInSource());
211211

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

218214
if (const std::optional<StringRef> MaybeMacroName =
219215
formatStringContainsUnreplaceableMacro(Call, FormatExpr, SM, PP);

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,10 +232,20 @@ Changes in existing checks
232232
matched scenarios of ``find`` and ``rfind`` methods and fixing false
233233
positives when those methods were called with 3 arguments.
234234

235+
- Improved :doc:`modernize-use-std-format
236+
<clang-tidy/checks/modernize/use-std-format>` check to correctly match
237+
when the format string is converted to a different type by an implicit
238+
constructor call.
239+
235240
- Improved :doc:`modernize-use-std-numbers
236241
<clang-tidy/checks/modernize/use-std-numbers>` check to support math
237242
functions of different precisions.
238243

244+
- Improved :doc:`modernize-use-std-print
245+
<clang-tidy/checks/modernize/use-std-print>` check to correctly match
246+
when the format string is converted to a different type by an implicit
247+
constructor call.
248+
239249
- Improved :doc:`performance-move-const-arg
240250
<clang-tidy/checks/performance/move-const-arg>` check by fixing false
241251
negatives on ternary operators calling ``std::move``.

clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
// RUN: -std=c++20 %s modernize-use-std-format %t -- \
33
// RUN: -config="{CheckOptions: { \
44
// RUN: modernize-use-std-format.StrictMode: true, \
5-
// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2; bad_format_type_strprintf', \
5+
// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2; any_format_type_strprintf', \
66
// RUN: modernize-use-std-format.ReplacementFormatFunction: 'fmt::format', \
77
// RUN: modernize-use-std-format.FormatHeader: '<fmt/core.h>' \
88
// RUN: }}" \
99
// RUN: -- -isystem %clang_tidy_headers
1010
// RUN: %check_clang_tidy -check-suffixes=,NOTSTRICT \
1111
// RUN: -std=c++20 %s modernize-use-std-format %t -- \
1212
// RUN: -config="{CheckOptions: { \
13-
// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2; bad_format_type_strprintf', \
13+
// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2; any_format_type_strprintf', \
1414
// RUN: modernize-use-std-format.ReplacementFormatFunction: 'fmt::format', \
1515
// RUN: modernize-use-std-format.FormatHeader: '<fmt/core.h>' \
1616
// RUN: }}" \
@@ -56,12 +56,17 @@ std::string A(const std::string &in)
5656
struct S {
5757
S(...);
5858
};
59-
std::string bad_format_type_strprintf(const S &, ...);
59+
std::string any_format_type_strprintf(const S &, ...);
6060

61-
std::string unsupported_format_parameter_type()
61+
void unsupported_format_parameter_types()
6262
{
6363
// No fixes here because the format parameter of the function called is not a
6464
// string.
65-
return bad_format_type_strprintf("");
66-
// 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]
65+
auto s1 = any_format_type_strprintf(L"");
66+
auto s2 = any_format_type_strprintf(42);
67+
68+
// But if we do pass a character string then that ought to be acceptable.
69+
auto s3 = any_format_type_strprintf("Hello %s", "world");
70+
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'fmt::format' instead of 'any_format_type_strprintf' [modernize-use-std-format]
71+
// CHECK-FIXES: auto s3 = fmt::format("Hello {}", "world");
6772
}

clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616

1717
namespace absl
1818
{
19-
template <typename S, typename... Args>
20-
std::string StrFormat(const S &format, const Args&... args);
19+
template <typename... Args>
20+
std::string StrFormat(const std::string &format, const Args&... args);
2121
} // namespace absl
2222

2323
template <typename T>

clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-absl.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@
99

1010
#include <cstdio>
1111
#include <string.h>
12+
#include <string>
1213

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

1920
template <typename... Args>
20-
int FPrintF(FILE* output, const char *format, const Args&... args);
21+
int FPrintF(FILE* output, const std::string_view &format, const Args&... args);
2122
}
2223

2324
void printf_simple() {

clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// RUN: %check_clang_tidy -std=c++23 %s modernize-use-std-print %t -- \
22
// RUN: -config="{CheckOptions: \
33
// RUN: { \
4-
// RUN: modernize-use-std-print.PrintfLikeFunctions: 'unqualified_printf;::myprintf; mynamespace::myprintf2; bad_format_type_printf; fmt::printf', \
5-
// RUN: modernize-use-std-print.FprintfLikeFunctions: '::myfprintf; mynamespace::myfprintf2; bad_format_type_fprintf; fmt::fprintf' \
4+
// RUN: modernize-use-std-print.PrintfLikeFunctions: 'unqualified_printf;::myprintf; mynamespace::myprintf2; any_format_type_printf; fmt::printf', \
5+
// RUN: modernize-use-std-print.FprintfLikeFunctions: '::myfprintf; mynamespace::myfprintf2; any_format_type_fprintf; fmt::fprintf' \
66
// RUN: } \
77
// RUN: }" \
88
// RUN: -- -isystem %clang_tidy_headers
@@ -98,18 +98,25 @@ void wide_string_not_supported() {
9898
struct S {
9999
S(...) {}
100100
};
101-
int bad_format_type_printf(const S &, ...);
102-
int bad_format_type_fprintf(FILE *, const S &, ...);
101+
int any_format_type_printf(const S &, ...);
102+
int any_format_type_fprintf(FILE *, const S &, ...);
103103

104104
void unsupported_format_parameter_type()
105105
{
106106
// No fixes here because the format parameter of the function called is not a
107107
// string.
108-
bad_format_type_printf("Hello %s", "world");
109-
// 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]
110-
111-
bad_format_type_fprintf(stderr, "Hello %s", "world");
112-
// 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]
108+
any_format_type_printf(L"Hello %s", "world");
109+
any_format_type_fprintf(stderr, L"Hello %s", "world");
110+
any_format_type_printf(42);
111+
any_format_type_fprintf(stderr, 42L);
112+
113+
// But if we do pass a character string then that ought to be acceptable.
114+
any_format_type_printf("Hello %s\n", "world");
115+
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'any_format_type_printf' [modernize-use-std-print]
116+
// CHECK-FIXES: std::println("Hello {}", "world");
117+
any_format_type_fprintf(stderr, "Hello %s\n", "world");
118+
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'any_format_type_fprintf' [modernize-use-std-print]
119+
// CHECK-FIXES: std::println(stderr, "Hello {}", "world");
113120
}
114121

115122
namespace fmt {

0 commit comments

Comments
 (0)