1 // RUN: %check_clang_tidy \ 2 // RUN: -std=c++20 %s modernize-use-std-format %t -- \ 3 // RUN: -config="{CheckOptions: {StrictMode: true}}" \ 4 // RUN: -- -isystem %clang_tidy_headers 5 // RUN: %check_clang_tidy \ 6 // RUN: -std=c++20 %s modernize-use-std-format %t -- \ 7 // RUN: -config="{CheckOptions: {StrictMode: false}}" \ 8 // RUN: -- -isystem %clang_tidy_headers 9 #include <string> 10 // CHECK-FIXES: #include <format> 11 12 namespace absl 13 { 14 // Use const char * for the format since the real type is hard to mock up. 15 template <typename... Args> 16 std::string StrFormat(const char *format, const Args&... args); 17 } // namespace absl 18 19 template <typename T> 20 struct iterator { 21 T *operator->(); 22 T &operator*(); 23 }; 24 25 std::string StrFormat_simple() { 26 return absl::StrFormat("Hello"); 27 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] 28 // CHECK-FIXES: return std::format("Hello"); 29 } 30 31 std::string StrFormat_complex(const char *name, double value) { 32 return absl::StrFormat("'%s'='%f'", name, value); 33 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] 34 // CHECK-FIXES: return std::format("'{}'='{:f}'", name, value); 35 } 36 37 std::string StrFormat_integer_conversions() { 38 return absl::StrFormat("int:%d int:%d char:%c char:%c", 65, 'A', 66, 'B'); 39 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] 40 // CHECK-FIXES: return std::format("int:{} int:{:d} char:{:c} char:{}", 65, 'A', 66, 'B'); 41 } 42 43 // FormatConverter is capable of removing newlines from the end of the format 44 // string. Ensure that isn't incorrectly happening for std::format. 45 std::string StrFormat_no_newline_removal() { 46 return absl::StrFormat("a line\n"); 47 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] 48 // CHECK-FIXES: return std::format("a line\n"); 49 } 50 51 // FormatConverter is capable of removing newlines from the end of the format 52 // string. Ensure that isn't incorrectly happening for std::format. 53 std::string StrFormat_cstr_removal(const std::string &s1, const std::string *s2) { 54 return absl::StrFormat("%s %s %s %s", s1.c_str(), s1.data(), s2->c_str(), s2->data()); 55 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] 56 // CHECK-FIXES: return std::format("{} {} {} {}", s1, s1, *s2, *s2); 57 } 58 59 std::string StrFormat_strict_conversion() { 60 const unsigned char uc = 'A'; 61 return absl::StrFormat("Integer %hhd from unsigned char\n", uc); 62 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] 63 // CHECK-FIXES: return std::format("Integer {} from unsigned char\n", uc); 64 } 65 66 std::string StrFormat_field_width_and_precision() { 67 auto s1 = absl::StrFormat("width only:%*d width and precision:%*.*f precision only:%.*f", 3, 42, 4, 2, 3.14159265358979323846, 5, 2.718); 68 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] 69 // CHECK-FIXES: std::format("width only:{:{}} width and precision:{:{}.{}f} precision only:{:.{}f}", 42, 3, 3.14159265358979323846, 4, 2, 2.718, 5); 70 71 auto s2 = absl::StrFormat("width and precision positional:%1$*2$.*3$f after", 3.14159265358979323846, 4, 2); 72 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] 73 // CHECK-FIXES: std::format("width and precision positional:{0:{1}.{2}f} after", 3.14159265358979323846, 4, 2); 74 75 const int width = 10, precision = 3; 76 const unsigned int ui1 = 42, ui2 = 43, ui3 = 44; 77 auto s3 = absl::StrFormat("casts width only:%*d width and precision:%*.*d precision only:%.*d\n", 3, ui1, 4, 2, ui2, 5, ui3); 78 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] 79 // CHECK-FIXES-NOTSTRICT: std::format("casts width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", ui1, 3, ui2, 4, 2, ui3, 5); 80 // CHECK-FIXES-STRICT: std::format("casts width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", static_cast<int>(ui1), 3, static_cast<int>(ui2), 4, 2, static_cast<int>(ui3), 5); 81 82 auto s4 = absl::StrFormat("c_str removal width only:%*s width and precision:%*.*s precision only:%.*s", 3, s1.c_str(), 4, 2, s2.c_str(), 5, s3.c_str()); 83 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] 84 // CHECK-FIXES: std::format("c_str removal width only:{:>{}} width and precision:{:>{}.{}} precision only:{:.{}}", s1, 3, s2, 4, 2, s3, 5); 85 86 const std::string *ps1 = &s1, *ps2 = &s2, *ps3 = &s3; 87 auto s5 = absl::StrFormat("c_str() removal pointer width only:%-*s width and precision:%-*.*s precision only:%-.*s", 3, ps1->c_str(), 4, 2, ps2->c_str(), 5, ps3->c_str()); 88 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] 89 // CHECK-FIXES: std::format("c_str() removal pointer width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", *ps1, 3, *ps2, 4, 2, *ps3, 5); 90 91 iterator<std::string> is1, is2, is3; 92 auto s6 = absl::StrFormat("c_str() removal iterator width only:%-*s width and precision:%-*.*s precision only:%-.*s", 3, is1->c_str(), 4, 2, is2->c_str(), 5, is3->c_str()); 93 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] 94 // CHECK-FIXES: std::format("c_str() removal iterator width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", *is1, 3, *is2, 4, 2, *is3, 5); 95 96 return s1 + s2 + s3 + s4 + s5 + s6; 97 } 98 99 std::string StrFormat_macros() { 100 // The function call is replaced even though it comes from a macro. 101 #define FORMAT absl::StrFormat 102 auto s1 = FORMAT("Hello %d", 42); 103 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] 104 // CHECK-FIXES: std::format("Hello {}", 42); 105 106 // The format string is replaced even though it comes from a macro, this 107 // behaviour is required so that that <inttypes.h> macros are replaced. 108 #define FORMAT_STRING "Hello %s" 109 auto s2 = absl::StrFormat(FORMAT_STRING, 42); 110 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] 111 // CHECK-FIXES: std::format("Hello {}", 42); 112 113 // Arguments that are macros aren't replaced with their value, even if they are rearranged. 114 #define VALUE 3.14159265358979323846 115 #define WIDTH 10 116 #define PRECISION 4 117 auto s3 = absl::StrFormat("Hello %*.*f", WIDTH, PRECISION, VALUE); 118 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] 119 // CHECK-FIXES: std::format("Hello {:{}.{}f}", VALUE, WIDTH, PRECISION); 120 } 121