1// RUN: %check_clang_tidy %s readability-redundant-string-cstr %t -- \
2// RUN: -config="{CheckOptions: \
3// RUN: {readability-redundant-string-cstr.StringParameterFunctions: \
4// RUN: '::fmt::format; ::fmt::print; ::BaseLogger::operator(); ::BaseLogger::Log'} \
5// RUN: }" \
6// RUN: -- -isystem %clang_tidy_headers
7#include <string>
8
9namespace fmt {
10 inline namespace v8 {
11 template<typename ...Args>
12 void print(const char *, Args &&...);
13 template<typename ...Args>
14 std::string format(const char *, Args &&...);
15 }
16}
17
18namespace notfmt {
19 inline namespace v8 {
20 template<typename ...Args>
21 void print(const char *, Args &&...);
22 template<typename ...Args>
23 std::string format(const char *, Args &&...);
24 }
25}
26
27void fmt_print(const std::string &s1, const std::string &s2, const std::string &s3) {
28 fmt::print("One:{}\n", s1.c_str());
29 // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
30 // CHECK-FIXES: {{^ }}fmt::print("One:{}\n", s1);
31
32 fmt::print("One:{} Two:{} Three:{}\n", s1.c_str(), s2, s3.c_str());
33 // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
34 // CHECK-MESSAGES: :[[@LINE-2]]:58: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
35 // CHECK-FIXES: {{^ }}fmt::print("One:{} Two:{} Three:{}\n", s1, s2, s3);
36}
37
38// There's no c_str() call here, so it shouldn't be touched
39void fmt_print_no_cstr(const std::string &s1, const std::string &s2) {
40 fmt::print("One: {}, Two: {}\n", s1, s2);
41}
42
43// This isn't fmt::print, so it shouldn't be fixed.
44void not_fmt_print(const std::string &s1) {
45 notfmt::print("One: {}\n", s1.c_str());
46}
47
48void fmt_format(const std::string &s1, const std::string &s2, const std::string &s3) {
49 auto r1 = fmt::format("One:{}\n", s1.c_str());
50 // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
51 // CHECK-FIXES: {{^ }}auto r1 = fmt::format("One:{}\n", s1);
52
53 auto r2 = fmt::format("One:{} Two:{} Three:{}\n", s1.c_str(), s2, s3.c_str());
54 // CHECK-MESSAGES: :[[@LINE-1]]:53: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
55 // CHECK-MESSAGES: :[[@LINE-2]]:69: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
56 // CHECK-FIXES: {{^ }}auto r2 = fmt::format("One:{} Two:{} Three:{}\n", s1, s2, s3);
57}
58
59// There's are c_str() calls here, so it shouldn't be touched
60void fmt_format_no_cstr(const std::string &s1, const std::string &s2) {
61 fmt::format("One: {}, Two: {}\n", s1, s2);
62}
63
64// This is not fmt::format, so it shouldn't be fixed
65std::string not_fmt_format(const std::string &s1) {
66 return notfmt::format("One: {}\n", s1.c_str());
67}
68
69class BaseLogger {
70public:
71 template <typename... Args>
72 void operator()(const char *fmt, Args &&...args) {
73 }
74
75 template <typename... Args>
76 void Log(const char *fmt, Args &&...args) {
77 }
78};
79
80class DerivedLogger : public BaseLogger {};
81class DoubleDerivedLogger : public DerivedLogger {};
82typedef DerivedLogger TypedefDerivedLogger;
83
84void logger1(const std::string &s1, const std::string &s2, const std::string &s3) {
85 BaseLogger LOGGER;
86
87 LOGGER("%s\n", s1.c_str(), s2, s3.c_str());
88 // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
89 // CHECK-MESSAGES: :[[@LINE-2]]:34: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
90 // CHECK-FIXES: {{^ }}LOGGER("%s\n", s1, s2, s3);
91
92 DerivedLogger LOGGER2;
93 LOGGER2("%d %s\n", 42, s1.c_str(), s2.c_str(), s3);
94 // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
95 // CHECK-MESSAGES: :[[@LINE-2]]:38: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
96 // CHECK-FIXES: {{^ }}LOGGER2("%d %s\n", 42, s1, s2, s3);
97
98 DoubleDerivedLogger LOGGERD;
99 LOGGERD("%d %s\n", 42, s1.c_str(), s2, s3.c_str());
100 // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
101 // CHECK-MESSAGES: :[[@LINE-2]]:42: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
102 // CHECK-FIXES: {{^ }}LOGGERD("%d %s\n", 42, s1, s2, s3);
103
104 TypedefDerivedLogger LOGGERT;
105 LOGGERT("%d %s\n", 42, s1.c_str(), s2, s3.c_str());
106 // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
107 // CHECK-MESSAGES: :[[@LINE-2]]:42: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
108 // CHECK-FIXES: {{^ }}LOGGERT("%d %s\n", 42, s1, s2, s3);
109}
110
111void logger2(const std::string &s1, const std::string &s2) {
112 BaseLogger LOGGER3;
113
114 LOGGER3.Log(fmt: "%s\n", args: s1.c_str(), args: s2.c_str());
115 // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
116 // CHECK-MESSAGES: :[[@LINE-2]]:35: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
117 // CHECK-FIXES: {{^ }}LOGGER3.Log("%s\n", s1, s2);
118
119 DerivedLogger LOGGER4;
120 LOGGER4.Log(fmt: "%d %s\n", args: 42, args: s1.c_str(), args: s2.c_str());
121 // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
122 // CHECK-MESSAGES: :[[@LINE-2]]:42: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
123 // CHECK-FIXES: {{^ }}LOGGER4.Log("%d %s\n", 42, s1, s2);
124}
125
126class NotLogger {
127public:
128 template <typename... Args>
129 void operator()(const char *fmt, Args &&...args) {
130 }
131
132 template <typename... Args>
133 void Log(const char *fmt, Args &&...args) {
134 }
135};
136
137void Log(const char *fmt, ...);
138
139void logger3(const std::string &s1)
140{
141 // Not BaseLogger or something derived from it
142 NotLogger LOGGER;
143 LOGGER("%s\n", s1.c_str());
144 LOGGER.Log(fmt: "%s\n", args: s1.c_str());
145
146 // Free function not in StringParameterFunctions list
147 Log(fmt: "%s\n", s1.c_str());
148}
149

source code of clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-function.cpp