181 lines · cpp
1// RUN: %check_clang_tidy \2// RUN: -std=c++20-or-later %s modernize-use-std-format %t -- \3// RUN: -config="{CheckOptions: {modernize-use-std-format.StrictMode: true}}" \4// RUN: -- -isystem %clang_tidy_headers \5// RUN: -DPRI_CMDLINE_MACRO="\"s\"" \6// RUN: -D__PRI_CMDLINE_MACRO="\"s\""7// RUN: %check_clang_tidy \8// RUN: -std=c++20-or-later %s modernize-use-std-format %t -- \9// RUN: -config="{CheckOptions: {modernize-use-std-format.StrictMode: false}}" \10// RUN: -- -isystem %clang_tidy_headers \11// RUN: -DPRI_CMDLINE_MACRO="\"s\"" \12// RUN: -D__PRI_CMDLINE_MACRO="\"s\""13#include <string>14// CHECK-FIXES: #include <format>15#include <inttypes.h>16 17namespace absl18{19template <typename... Args>20std::string StrFormat(const std::string_view &format, const Args&... args);21} // namespace absl22 23template <typename T>24struct iterator {25 T *operator->();26 T &operator*();27};28 29std::string StrFormat_simple() {30 return absl::StrFormat("Hello");31 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]32 // CHECK-FIXES: return std::format("Hello");33}34 35std::string StrFormat_complex(const char *name, double value) {36 return absl::StrFormat("'%s'='%f'", name, value);37 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]38 // CHECK-FIXES: return std::format("'{}'='{:f}'", name, value);39}40 41std::string StrFormat_integer_conversions() {42 return absl::StrFormat("int:%d int:%d char:%c char:%c", 65, 'A', 66, 'B');43 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]44 // CHECK-FIXES: return std::format("int:{} int:{:d} char:{:c} char:{}", 65, 'A', 66, 'B');45}46 47// FormatConverter is capable of removing newlines from the end of the format48// string. Ensure that isn't incorrectly happening for std::format.49std::string StrFormat_no_newline_removal() {50 return absl::StrFormat("a line\n");51 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]52 // CHECK-FIXES: return std::format("a line\n");53}54 55// FormatConverter is capable of removing newlines from the end of the format56// string. Ensure that isn't incorrectly happening for std::format.57std::string StrFormat_cstr_removal(const std::string &s1, const std::string *s2) {58 return absl::StrFormat("%s %s %s %s", s1.c_str(), s1.data(), s2->c_str(), s2->data());59 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]60 // CHECK-FIXES: return std::format("{} {} {} {}", s1, s1, *s2, *s2);61}62 63std::string StrFormat_strict_conversion() {64 const unsigned char uc = 'A';65 return absl::StrFormat("Integer %hhd from unsigned char\n", uc);66 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]67 // CHECK-FIXES: return std::format("Integer {} from unsigned char\n", uc);68}69 70std::string StrFormat_field_width_and_precision() {71 auto s1 = absl::StrFormat("width only:%*d width and precision:%*.*f precision only:%.*f", 3, 42, 4, 2, 3.14159265358979323846, 5, 2.718);72 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]73 // CHECK-FIXES: auto s1 = std::format("width only:{:{}} width and precision:{:{}.{}f} precision only:{:.{}f}", 42, 3, 3.14159265358979323846, 4, 2, 2.718, 5);74 75 auto s2 = absl::StrFormat("width and precision positional:%1$*2$.*3$f after", 3.14159265358979323846, 4, 2);76 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]77 // CHECK-FIXES: auto s2 = std::format("width and precision positional:{0:{1}.{2}f} after", 3.14159265358979323846, 4, 2);78 79 const int width = 10, precision = 3;80 const unsigned int ui1 = 42, ui2 = 43, ui3 = 44;81 auto s3 = absl::StrFormat("casts width only:%*d width and precision:%*.*d precision only:%.*d\n", 3, ui1, 4, 2, ui2, 5, ui3);82 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]83 // CHECK-FIXES-NOTSTRICT: auto s3 = std::format("casts width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", ui1, 3, ui2, 4, 2, ui3, 5);84 // CHECK-FIXES-STRICT: auto s3 = 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);85 86 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());87 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]88 // CHECK-FIXES: auto s4 = std::format("c_str removal width only:{:>{}} width and precision:{:>{}.{}} precision only:{:.{}}", s1, 3, s2, 4, 2, s3, 5);89 90 const std::string *ps1 = &s1, *ps2 = &s2, *ps3 = &s3;91 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());92 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]93 // CHECK-FIXES: auto s5 = std::format("c_str() removal pointer width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", *ps1, 3, *ps2, 4, 2, *ps3, 5);94 95 iterator<std::string> is1, is2, is3;96 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());97 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]98 // CHECK-FIXES: auto s6 = std::format("c_str() removal iterator width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", *is1, 3, *is2, 4, 2, *is3, 5);99 100 return s1 + s2 + s3 + s4 + s5 + s6;101}102 103void StrFormat_macros() {104 // The function call is replaced even though it comes from a macro.105#define FORMAT absl::StrFormat106 auto s1 = FORMAT("Hello %d", 42);107 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]108 // CHECK-FIXES: auto s1 = std::format("Hello {}", 42);109 110 // Arguments that are macros aren't replaced with their value, even if they are rearranged.111#define VALUE 3.14159265358979323846112#define WIDTH 10113#define PRECISION 4114 auto s3 = absl::StrFormat("Hello %*.*f", WIDTH, PRECISION, VALUE);115 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]116 // CHECK-FIXES: auto s3 = std::format("Hello {:{}.{}f}", VALUE, WIDTH, PRECISION);117 118 const uint64_t u64 = 42;119 const uint32_t u32 = 32;120 std::string s;121 122 auto s4 = absl::StrFormat("Replaceable macro at end %" PRIu64, u64);123 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]124 // CHECK-FIXES: auto s4 = std::format("Replaceable macro at end {}", u64);125 126 auto s5 = absl::StrFormat("Replaceable macros in middle %" PRIu64 " %" PRIu32 "\n", u64, u32);127 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]128 // CHECK-FIXES: auto s5 = std::format("Replaceable macros in middle {} {}\n", u64, u32);129 130// These need PRI and __PRI prefixes so that the check get as far as looking for131// where the macro comes from.132#define PRI_FMT_MACRO "s"133#define __PRI_FMT_MACRO "s"134 135 auto s6 = absl::StrFormat("Unreplaceable macro at end %" PRI_FMT_MACRO, s.c_str());136 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: unable to use 'std::format' instead of 'StrFormat' because format string contains unreplaceable macro 'PRI_FMT_MACRO' [modernize-use-std-format]137 138 auto s7 = absl::StrFormat(__PRI_FMT_MACRO " Unreplaceable macro at beginning %s", s);139 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: unable to use 'std::format' instead of 'StrFormat' because format string contains unreplaceable macro '__PRI_FMT_MACRO' [modernize-use-std-format]140 141 auto s8 = absl::StrFormat("Unreplacemable macro %" PRI_FMT_MACRO " in the middle", s);142 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: unable to use 'std::format' instead of 'StrFormat' because format string contains unreplaceable macro 'PRI_FMT_MACRO' [modernize-use-std-format]143 144 auto s9 = absl::StrFormat("First macro is replaceable %" PRIu64 " but second one is not %" __PRI_FMT_MACRO, u64, s);145 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: unable to use 'std::format' instead of 'StrFormat' because format string contains unreplaceable macro '__PRI_FMT_MACRO' [modernize-use-std-format]146 147 // Needs a PRI prefix so that we get as far as looking for where the macro comes from148 auto s10 = absl::StrFormat(" macro from command line %" PRI_CMDLINE_MACRO, s);149 // CHECK-MESSAGES: [[@LINE-1]]:14: warning: unable to use 'std::format' instead of 'StrFormat' because format string contains unreplaceable macro 'PRI_CMDLINE_MACRO' [modernize-use-std-format]150 151 // Needs a __PRI prefix so that we get as far as looking for where the macro comes from152 auto s11 = absl::StrFormat(" macro from command line %" __PRI_CMDLINE_MACRO, s);153 // CHECK-MESSAGES: [[@LINE-1]]:14: warning: unable to use 'std::format' instead of 'StrFormat' because format string contains unreplaceable macro '__PRI_CMDLINE_MACRO' [modernize-use-std-format]154 155 // We ought to be able to fix this since the macro surrounds the whole call156 // and therefore can't change the format string independently. This is157 // required to be able to fix calls inside Catch2 macros for example.158#define SURROUND_ALL(x) x159 auto s12 = SURROUND_ALL(absl::StrFormat("Macro surrounding entire invocation %" PRIu64, u64));160 // CHECK-MESSAGES: [[@LINE-1]]:27: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]161 // CHECK-FIXES: auto s12 = SURROUND_ALL(std::format("Macro surrounding entire invocation {}", u64));162 163 // But having that surrounding macro shouldn't stop us ignoring an164 // unreplaceable macro elsewhere.165 auto s13 = SURROUND_ALL(absl::StrFormat("Macro surrounding entire invocation with unreplaceable macro %" PRI_FMT_MACRO, s));166 // CHECK-MESSAGES: [[@LINE-1]]:27: warning: unable to use 'std::format' instead of 'StrFormat' because format string contains unreplaceable macro 'PRI_FMT_MACRO' [modernize-use-std-format]167 168 // At the moment at least the check will replace occurrences where the169 // function name is the result of expanding a macro.170#define SURROUND_FUNCTION_NAME(x) absl:: x171 auto s14 = SURROUND_FUNCTION_NAME(StrFormat)("Hello %d", 4442);172 // CHECK-MESSAGES: [[@LINE-1]]:14: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]173 // CHECK-FIXES: auto s14 = std::format("Hello {}", 4442);174 175 // We can't safely fix occurrences where the macro may affect the format176 // string differently in different builds.177#define SURROUND_FORMAT(x) "!" x178 auto s15 = absl::StrFormat(SURROUND_FORMAT("Hello %d"), 4443);179 // CHECK-MESSAGES: [[@LINE-1]]:14: warning: unable to use 'std::format' instead of 'StrFormat' because format string contains unreplaceable macro 'SURROUND_FORMAT' [modernize-use-std-format]180}181