Skip to content

Commit bbcb625

Browse files
authored
[clang-tidy] Support member functions with modernize-use-std-print/format (#104675)
These checks can be made to work on member functions quite easily and it's not unknown to have at least printf-style functions as members. Let's remove the restriction.
1 parent dd40632 commit bbcb625

File tree

7 files changed

+140
-16
lines changed

7 files changed

+140
-16
lines changed

clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ void UseStdFormatCheck::registerMatchers(MatchFinder *Finder) {
5050
Finder->addMatcher(
5151
callExpr(argumentCountAtLeast(1),
5252
hasArgument(0, stringLiteral(isOrdinary())),
53-
callee(functionDecl(unless(cxxMethodDecl()),
54-
matchers::matchesAnyListedName(
53+
callee(functionDecl(matchers::matchesAnyListedName(
5554
StrFormatLikeFunctions))
5655
.bind("func_decl")))
5756
.bind("strformat"),
@@ -93,7 +92,8 @@ void UseStdFormatCheck::check(const MatchFinder::MatchResult &Result) {
9392
diag(StrFormatCall->getBeginLoc(), "use '%0' instead of %1")
9493
<< ReplacementFormatFunction << OldFunction->getIdentifier();
9594
Diag << FixItHint::CreateReplacement(
96-
CharSourceRange::getTokenRange(StrFormatCall->getSourceRange()),
95+
CharSourceRange::getTokenRange(StrFormatCall->getExprLoc(),
96+
StrFormatCall->getEndLoc()),
9797
ReplacementFormatFunction);
9898
Converter.applyFixes(Diag, *Result.SourceManager);
9999

clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,7 @@ void UseStdPrintCheck::registerMatchers(MatchFinder *Finder) {
100100
unusedReturnValue(
101101
callExpr(argumentCountAtLeast(1),
102102
hasArgument(0, stringLiteral(isOrdinary())),
103-
callee(functionDecl(unless(cxxMethodDecl()),
104-
matchers::matchesAnyListedName(
103+
callee(functionDecl(matchers::matchesAnyListedName(
105104
PrintfLikeFunctions))
106105
.bind("func_decl")))
107106
.bind("printf")),
@@ -112,8 +111,7 @@ void UseStdPrintCheck::registerMatchers(MatchFinder *Finder) {
112111
unusedReturnValue(
113112
callExpr(argumentCountAtLeast(2),
114113
hasArgument(1, stringLiteral(isOrdinary())),
115-
callee(functionDecl(unless(cxxMethodDecl()),
116-
matchers::matchesAnyListedName(
114+
callee(functionDecl(matchers::matchesAnyListedName(
117115
FprintfLikeFunctions))
118116
.bind("func_decl")))
119117
.bind("fprintf")),
@@ -152,7 +150,7 @@ void UseStdPrintCheck::check(const MatchFinder::MatchResult &Result) {
152150
<< ReplacementFunction << OldFunction->getIdentifier();
153151

154152
Diag << FixItHint::CreateReplacement(
155-
CharSourceRange::getTokenRange(PrintfCall->getBeginLoc(),
153+
CharSourceRange::getTokenRange(PrintfCall->getExprLoc(),
156154
PrintfCall->getEndLoc()),
157155
ReplacementFunction);
158156
Converter.applyFixes(Diag, *Result.SourceManager);

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ New check aliases
104104
Changes in existing checks
105105
^^^^^^^^^^^^^^^^^^^^^^^^^^
106106

107+
- Improved :doc:`modernize-use-std-format
108+
<clang-tidy/checks/modernize/use-std-format>` check to support replacing
109+
member function calls too.
110+
111+
- Improved :doc:`modernize-use-std-print
112+
<clang-tidy/checks/modernize/use-std-print>` check to support replacing
113+
member function calls too.
114+
107115
- Improved :doc:`readability-redundant-smartptr-get
108116
<clang-tidy/checks/readability/redundant-smartptr-get>` check to
109117
remove `->`, when redundant `get()` is removed.

clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-format.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,9 @@ Options
6464
A semicolon-separated list of (fully qualified) function names to
6565
replace, with the requirement that the first parameter contains the
6666
printf-style format string and the arguments to be formatted follow
67-
immediately afterwards. The default value for this option is
68-
`absl::StrFormat`.
67+
immediately afterwards. Qualified member function names are supported,
68+
but the replacement function name must be unqualified. The default value
69+
for this option is `absl::StrFormat`.
6970

7071
.. option:: ReplacementFormatFunction
7172

clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,19 +121,22 @@ Options
121121
A semicolon-separated list of (fully qualified) function names to
122122
replace, with the requirement that the first parameter contains the
123123
printf-style format string and the arguments to be formatted follow
124-
immediately afterwards. If neither this option nor
125-
`FprintfLikeFunctions` are set then the default value for this option
126-
is `printf; absl::PrintF`, otherwise it is empty.
124+
immediately afterwards. Qualified member function names are supported,
125+
but the replacement function name must be unqualified. If neither this
126+
option nor `FprintfLikeFunctions` are set then the default value for
127+
this option is `printf; absl::PrintF`, otherwise it is empty.
127128

128129

129130
.. option:: FprintfLikeFunctions
130131

131132
A semicolon-separated list of (fully qualified) function names to
132133
replace, with the requirement that the first parameter is retained, the
133134
second parameter contains the printf-style format string and the
134-
arguments to be formatted follow immediately afterwards. If neither this
135-
option nor `PrintfLikeFunctions` are set then the default value for
136-
this option is `fprintf; absl::FPrintF`, otherwise it is empty.
135+
arguments to be formatted follow immediately afterwards. Qualified
136+
member function names are supported, but the replacement function name
137+
must be unqualified. If neither this option nor `PrintfLikeFunctions`
138+
are set then the default value for this option is `fprintf;
139+
absl::FPrintF`, otherwise it is empty.
137140

138141
.. option:: ReplacementPrintFunction
139142

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: %check_clang_tidy %s modernize-use-std-format %t -- \
2+
// RUN: -config="{CheckOptions: \
3+
// RUN: { \
4+
// RUN: modernize-use-std-format.StrFormatLikeFunctions: 'MyClass::StrFormat', \
5+
// RUN: modernize-use-std-format.ReplacementFormatFunction: 'format', \
6+
// RUN: } \
7+
// RUN: }" \
8+
// RUN: -- -isystem %clang_tidy_headers
9+
10+
#include <cstdio>
11+
#include <string.h>
12+
#include <string>
13+
14+
struct MyClass
15+
{
16+
template <typename S, typename... Args>
17+
std::string StrFormat(const S &format, const Args&... args);
18+
};
19+
20+
std::string StrFormat_simple(MyClass &myclass, MyClass *pmyclass) {
21+
std::string s;
22+
23+
s += myclass.StrFormat("MyClass::StrFormat dot %d", 42);
24+
// CHECK-MESSAGES: [[@LINE-1]]:8: warning: use 'format' instead of 'StrFormat' [modernize-use-std-format]
25+
// CHECK-FIXES: s += myclass.format("MyClass::StrFormat dot {}", 42);
26+
27+
s += pmyclass->StrFormat("MyClass::StrFormat pointer %d", 43);
28+
// CHECK-MESSAGES: [[@LINE-1]]:8: warning: use 'format' instead of 'StrFormat' [modernize-use-std-format]
29+
// CHECK-FIXES: s += pmyclass->format("MyClass::StrFormat pointer {}", 43);
30+
31+
s += (*pmyclass).StrFormat("MyClass::StrFormat deref pointer %d", 44);
32+
// CHECK-MESSAGES: [[@LINE-1]]:8: warning: use 'format' instead of 'StrFormat' [modernize-use-std-format]
33+
// CHECK-FIXES: s += (*pmyclass).format("MyClass::StrFormat deref pointer {}", 44);
34+
35+
return s;
36+
}
37+
38+
struct MyDerivedClass : public MyClass {};
39+
40+
std::string StrFormat_derived(MyDerivedClass &derived) {
41+
return derived.StrFormat("MyDerivedClass::StrFormat dot %d", 42);
42+
// CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'format' instead of 'StrFormat' [modernize-use-std-format]
43+
// CHECK-FIXES: return derived.format("MyDerivedClass::StrFormat dot {}", 42);
44+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// RUN: %check_clang_tidy %s modernize-use-std-print %t -- \
2+
// RUN: -config="{CheckOptions: \
3+
// RUN: { \
4+
// RUN: modernize-use-std-print.PrintfLikeFunctions: 'MyClass::printf', \
5+
// RUN: modernize-use-std-print.FprintfLikeFunctions: 'MyClass::fprintf', \
6+
// RUN: modernize-use-std-print.ReplacementPrintFunction: 'print', \
7+
// RUN: modernize-use-std-print.ReplacementPrintlnFunction: 'println', \
8+
// RUN: } \
9+
// RUN: }" \
10+
// RUN: -- -isystem %clang_tidy_headers
11+
12+
#include <cstdio>
13+
#include <string.h>
14+
15+
struct MyStruct {};
16+
17+
struct MyClass
18+
{
19+
template <typename... Args>
20+
void printf(const char *fmt, Args &&...);
21+
template <typename... Args>
22+
int fprintf(MyStruct *param1, const char *fmt, Args &&...);
23+
};
24+
25+
void printf_simple(MyClass &myclass, MyClass *pmyclass) {
26+
myclass.printf("printf dot %d", 42);
27+
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'print' instead of 'printf' [modernize-use-std-print]
28+
// CHECK-FIXES: myclass.print("printf dot {}", 42);
29+
30+
pmyclass->printf("printf pointer %d", 43);
31+
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'print' instead of 'printf' [modernize-use-std-print]
32+
// CHECK-FIXES: pmyclass->print("printf pointer {}", 43);
33+
34+
(*pmyclass).printf("printf deref pointer %d", 44);
35+
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'print' instead of 'printf' [modernize-use-std-print]
36+
// CHECK-FIXES: (*pmyclass).print("printf deref pointer {}", 44);
37+
}
38+
39+
void printf_newline(MyClass &myclass, MyClass *pmyclass) {
40+
myclass.printf("printf dot newline %c\n", 'A');
41+
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'println' instead of 'printf' [modernize-use-std-print]
42+
// CHECK-FIXES: myclass.println("printf dot newline {}", 'A');
43+
44+
pmyclass->printf("printf pointer newline %c\n", 'B');
45+
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'println' instead of 'printf' [modernize-use-std-print]
46+
// CHECK-FIXES: pmyclass->println("printf pointer newline {}", 'B');
47+
}
48+
49+
void fprintf_simple(MyStruct *mystruct, MyClass &myclass, MyClass *pmyclass) {
50+
myclass.fprintf(mystruct, "fprintf dot %d", 142);
51+
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'print' instead of 'fprintf' [modernize-use-std-print]
52+
// CHECK-FIXES: myclass.print(mystruct, "fprintf dot {}", 142);
53+
54+
pmyclass->fprintf(mystruct, "fprintf pointer %d", 143);
55+
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'print' instead of 'fprintf' [modernize-use-std-print]
56+
// CHECK-FIXES: pmyclass->print(mystruct, "fprintf pointer {}", 143);
57+
58+
(*pmyclass).fprintf(mystruct, "fprintf deref pointer %d", 144);
59+
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'print' instead of 'fprintf' [modernize-use-std-print]
60+
// CHECK-FIXES: (*pmyclass).print(mystruct, "fprintf deref pointer {}", 144);
61+
}
62+
63+
struct MyDerivedClass : public MyClass {};
64+
65+
void printf_derived(MyDerivedClass &derived)
66+
{
67+
derived.printf("printf on derived class %d", 42);
68+
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'print' instead of 'printf' [modernize-use-std-print]
69+
// CHECK-FIXES: derived.print("printf on derived class {}", 42);
70+
}

0 commit comments

Comments
 (0)