[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-02-05 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
mikecrowe added a reviewer: njames93.
mikecrowe added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, xazax.hun.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a subscriber: cfe-commits.

std::format (C++20) and std::print (C++23) are perfectly happy to accept
std::string parameters. Converting them to C-style strings by calling
c_str() is unnecessary and may cause extra walking of the string to
determine its length.

It's straightforward to teach readability-redundant-string-cstr to
identify the first such unnecessary call to c_str() in the parameter
list, but I was unable to come up with a way that worked for all the
parameters.

I was unable to come up with a way to make libstdc++'s format_string
first parameter to std::format and std::print work in the
redundant-string-cstr.cpp lit check. Using const char * is sufficient
though since that isn't the argument we're interested in.

I was able to successfully run the readability-redundant-string-cstr
check on a real source file that compiled successfully with what is
destined to become GCC 13, and saw the expected:

--8<--
/home/mac/git/llvm-project/build/bin/clang-tidy 
-checks=-*,readability-redundant-string-cstr format.cpp -- 
--gcc-toolchain=/home/mac/gcc-git
6 warnings generated.
/home/mac/src/random-hacks/std-format/format.cpp:13:39: warning: redundant call 
to 'c_str' [readability-redundant-string-cstr]

  std::puts(std::format("Hello {}", get().c_str()).c_str());
^
get()

Suppressed 5 warnings (5 with check filters).
-->8--


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D143342

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
@@ -291,3 +291,59 @@
   Foo.func2((Str.c_str()));
 }
 } // namespace PR45286
+
+namespace std {
+  template
+  void print(const char *, Args &&...);
+  template
+  std::string format(const char *, Args &&...);
+}
+
+namespace notstd {
+  template
+  void print(const char *, Args &&...);
+  template
+  std::string format(const char *, Args &&...);
+}
+
+void std_print(const std::string &s1, const std::string &s2, const std::string 
&s3) {
+  std::print("One:{}\n", s1.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: redundant call to 'c_str' 
[readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}std::print("One:{}\n", s1);
+
+  // Ideally we'd fix both the second and fourth parameters here, but that 
doesn't work.
+  std::print("One:{} Two:{} Three:{}\n", s1.c_str(), s2, s3.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: redundant call to 'c_str' 
[readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}std::print("One:{} Two:{} Three:{}\n", s1, s2, 
s3.c_str());
+}
+
+// There's no c_str() call here, so it shouldn't be touched.
+void std_print_no_cstr(const std::string &s1, const std::string &s2) {
+  std::print("One: {}, Two: {}\n", s1, s2);
+}
+
+// This isn't std::print, so it shouldn't be fixed.
+void not_std_print(const std::string &s1) {
+  notstd::print("One: {}\n", s1.c_str());
+}
+
+void std_format(const std::string &s1, const std::string &s2, const 
std::string &s3) {
+  auto r1 = std::format("One:{}\n", s1.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant call to 'c_str' 
[readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}auto r1 = std::format("One:{}\n", s1);
+
+  // Ideally we'd fix both the second and fourth parameters here, but that 
doesn't work.
+  auto r2 = std::format("One:{} Two:{} Three:{}\n", s1.c_str(), s2, 
s3.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:53: warning: redundant call to 'c_str' 
[readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}auto r2 = std::format("One:{} Two:{} Three:{}\n", s1, 
s2, s3.c_str());
+}
+
+// There's are c_str() calls here, so it shouldn't be touched.
+std::string std_format_no_cstr(const std::string &s1, const std::string &s2) {
+  return std::format("One: {}, Two: {}\n", s1, s2);
+}
+
+// This is not std::format, so it shouldn't be fixed.
+std::string not_std_format(const std::string &s1) {
+  return notstd::format("One: {}\n", s1.c_str());
+}
Index: clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
@@ -178,6 +178,14 @@
   //

[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-02-05 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

This check can also work trivially for fmt::format and fmt::print[1] too (in 
fact, that's what I'm actually using), if the project would allow them to be 
added too.

[1] https://fmt.dev/


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D143342/new/

https://reviews.llvm.org/D143342

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-02-05 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 494937.
mikecrowe added a comment.

carlosgalvezp wrote:

> Please document change in Release Notes, as well as in the check 
> documentation, together with its limitations (can only handle 1 argument at a 
> time).

Hopefully I've done those things.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D143342/new/

https://reviews.llvm.org/D143342

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/readability/redundant-string-cstr.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
@@ -291,3 +291,59 @@
   Foo.func2((Str.c_str()));
 }
 } // namespace PR45286
+
+namespace std {
+  template
+  void print(const char *, Args &&...);
+  template
+  std::string format(const char *, Args &&...);
+}
+
+namespace notstd {
+  template
+  void print(const char *, Args &&...);
+  template
+  std::string format(const char *, Args &&...);
+}
+
+void std_print(const std::string &s1, const std::string &s2, const std::string &s3) {
+  std::print("One:{}\n", s1.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}std::print("One:{}\n", s1);
+
+  // Ideally we'd fix both the second and fourth parameters here, but that doesn't work.
+  std::print("One:{} Two:{} Three:{}\n", s1.c_str(), s2, s3.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}std::print("One:{} Two:{} Three:{}\n", s1, s2, s3.c_str());
+}
+
+// There's no c_str() call here, so it shouldn't be touched.
+void std_print_no_cstr(const std::string &s1, const std::string &s2) {
+  std::print("One: {}, Two: {}\n", s1, s2);
+}
+
+// This isn't std::print, so it shouldn't be fixed.
+void not_std_print(const std::string &s1) {
+  notstd::print("One: {}\n", s1.c_str());
+}
+
+void std_format(const std::string &s1, const std::string &s2, const std::string &s3) {
+  auto r1 = std::format("One:{}\n", s1.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}auto r1 = std::format("One:{}\n", s1);
+
+  // Ideally we'd fix both the second and fourth parameters here, but that doesn't work.
+  auto r2 = std::format("One:{} Two:{} Three:{}\n", s1.c_str(), s2, s3.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:53: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}auto r2 = std::format("One:{} Two:{} Three:{}\n", s1, s2, s3.c_str());
+}
+
+// There's are c_str() calls here, so it shouldn't be touched.
+std::string std_format_no_cstr(const std::string &s1, const std::string &s2) {
+  return std::format("One: {}, Two: {}\n", s1, s2);
+}
+
+// This is not std::format, so it shouldn't be fixed.
+std::string not_std_format(const std::string &s1) {
+  return notstd::format("One: {}\n", s1.c_str());
+}
Index: clang-tools-extra/docs/clang-tidy/checks/readability/redundant-string-cstr.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/readability/redundant-string-cstr.rst
+++ clang-tools-extra/docs/clang-tidy/checks/readability/redundant-string-cstr.rst
@@ -5,3 +5,7 @@
 
 
 Finds unnecessary calls to ``std::string::c_str()`` and ``std::string::data()``.
+
+Only the first such call in an argument to ``std::print`` or
+``std::format`` will be detected, so it may be necessary to run the check
+more than once when applying fixes.
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -123,6 +123,12 @@
 
 Changes in existing checks
 ^^
+- Improved :doc:`readability-redundant-string-cstr
+  ` check to recognise
+  unnecessary ``std::string::c_str()`` and ``std::string::data()`` calls in
+  arguments to ``std::print`` and ``std::format``. Note that only the first
+  such argument is currently reported so it may be necessary to run the
+  check multiple times to fix all of them.
 
 Removed checks
 ^^
Index: clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
@@ -178,6 +178,16 @@
   /

[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-02-06 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

> The limitation about only transforming the first argument can be alleviated 
> by using the forEachArgumentWithParam matcher

I shall try to make that work. My initial attempts were not successful, but 
there's still more to try. If I can't make it work I'll ask for more help here.

Thanks.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D143342/new/

https://reviews.llvm.org/D143342

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156616: [clang-tidy] Fix c_str() removal and cast addition when re-ordering arguments

2023-07-30 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
mikecrowe added a reviewer: PiotrZSL.
Herald added subscribers: carlosgalvezp, xazax.hun.
Herald added a reviewer: njames93.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

The modernize-use-std-print check would get confused if it had to
re-order field-width and precision arguments at the same time as adding
casts or removing calls to c_str().

Fix this by tracking the argument indices and combining c_str() removal
with argument re-ordering. Add missing test cases to lit check.

Fixes https://github.com/llvm/llvm-project/issues/64033


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D156616

Files:
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.h
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
@@ -14,6 +14,12 @@
 #include 
 #include 
 
+template 
+struct iterator {
+  T *operator->();
+  T &operator*();
+};
+
 void printf_simple() {
   printf("Hello");
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
@@ -1121,11 +1127,32 @@
   // CHECK-FIXES: std::println("Hello {:.5}", 'G');
 }
 
-void printf_field_width_and_precision() {
+void printf_field_width_and_precision(const std::string &s1, const std::string &s2, const std::string &s3)
+{
   printf("width only:%*d width and precision:%*.*f precision only:%.*f\n", 3, 42, 4, 2, 3.14159265358979323846, 5, 2.718);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
   // CHECK-FIXES: std::println("width only:{:{}} width and precision:{:{}.{}f} precision only:{:.{}f}", 42, 3, 3.14159265358979323846, 4, 2, 2.718, 5);
 
+  const unsigned int ui1 = 42, ui2 = 43, ui3 = 44;
+  printf("casts width only:%*d width and precision:%*.*d precision only:%.*d\n", 3, ui1, 4, 2, ui2, 5, ui3);
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+  // CHECK-FIXES-NOTSTRICT: std::println("casts width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", ui1, 3, ui2, 4, 2, ui3, 5);
+  // CHECK-FIXES-STRICT: std::println("casts width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", static_cast(ui1), 3, static_cast(ui2), 4, 2, static_cast(ui3), 5);
+
+  printf("c_str removal width only:%*s width and precision:%*.*s precision only:%.*s\n", 3, s1.c_str(), 4, 2, s2.c_str(), 5, s3.c_str());
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+  // CHECK-FIXES: std::println("c_str removal width only:{:>{}} width and precision:{:>{}.{}} precision only:{:.{}}", s1, 3, s2, 4, 2, s3, 5);
+
+  const std::string *ps1 = &s1, *ps2 = &s2, *ps3 = &s3;
+  printf("c_str() removal pointer width only:%-*s width and precision:%-*.*s precision only:%-.*s\n", 3, ps1->c_str(), 4, 2, ps2->c_str(), 5, ps3->c_str());
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+  // CHECK-FIXES: std::println("c_str() removal pointer width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", *ps1, 3, *ps2, 4, 2, *ps3, 5);
+
+  iterator is1, is2, is3;
+  printf("c_str() removal iterator width only:%-*s width and precision:%-*.*s precision only:%-.*s\n", 3, is1->c_str(), 4, 2, is2->c_str(), 5, is3->c_str());
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+  // CHECK-FIXES: std::println("c_str() removal iterator width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", *is1, 3, *is2, 4, 2, *is3, 5);
+
   printf("width and precision positional:%1$*2$.*3$f after\n", 3.14159265358979323846, 4, 2);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
   // CHECK-FIXES: std::println("width and precision positional:{0:{1}.{2}f} after", 3.14159265358979323846, 4, 2);
@@ -1134,9 +1161,13 @@
   printf("width only:%3$*1$d width and precision:%4$*1$.*2$f precision only:%5$.*2$f\n", width, precision, 42, 3.1415926, 2.718);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
   // CHECK-FIXES: std::println("width only:{2:{0}} width and precision:{3:{0}.{1}f} precision only:{4:.{1}f}", width, precision, 42, 3.1415926, 2.718);
+
+  printf("c_str removal width only:%3$*1$s width and precision:%4$*1$.*2$s precision only:%5$.*2$s\n", width, precision, s1.c_str(), s2.c_str(), s3.c_str(

[PATCH] D156616: [clang-tidy] Fix c_str() removal and cast addition when re-ordering arguments

2023-07-30 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

Fixing this was rather messier than I expected, but this solution does seem to 
work for the test cases. Here's my original commit message before I trimmed it, 
in case it provides any more insight.

  [clang-tidy] Fix c_str() removal and cast addition when re-ordering arguments
  
  The modernize-use-std-print check would get confused if it had to
  re-order field-width and precision arguments at the same time as adding
  casts or removing calls to c_str(). For example applying the check with
  StrictMode enabled to:
  
   printf("%*s=%*d\n", 4, s.c_str(), 3, ui);
  
  yields:
  
   std::println("{:>{}}={:{}}", s.c_str(), s4, ui, static_cast(3));
  
  rather than the expected:
  
   std::println("{:>{}}={:{}}", s, 4, static_cast(ui), 3);
  
  Fix this by:
  
  - storing the ArgIndex rather than the Expr pointer for any arguments
that need casts to be added in ArgFixes so that the index can be
modified when the arguments are re-ordered. Use a struct rather than a
tuple for clarity.
  
  - Making applyFixes do argument re-ordering first, but also taking care
of c_str() removal at the same time if necessary. Update the argument
index of any ArgFixes too.
  
  - Apply the ArgFixes afterwards.
  
  - Finally apply and c_str() removals that remain.
  
  - Add lit check test cases for the combinations of argument reordering,
casts and c_str() removal. This required moving the definition of
struct iterator earlier in use-std-print.cpp.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156616/new/

https://reviews.llvm.org/D156616

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156616: [clang-tidy] Fix c_str() removal and cast addition when re-ordering arguments

2023-07-30 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 545446.
mikecrowe added a comment.

Rebase on top of D156616  and add more tests


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156616/new/

https://reviews.llvm.org/D156616

Files:
  clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
  clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
  clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp
  clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.h
  clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-format.rst
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-fmt.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp
@@ -0,0 +1,97 @@
+// RUN: %check_clang_tidy \
+// RUN:   -std=c++20 %s modernize-use-std-format %t -- \
+// RUN:   -config="{CheckOptions: [{key: StrictMode, value: true}]}" \
+// RUN:   -- -isystem %clang_tidy_headers
+// RUN: %check_clang_tidy \
+// RUN:   -std=c++20 %s modernize-use-std-format %t -- \
+// RUN:   -config="{CheckOptions: [{key: StrictMode, value: false}]}" \
+// RUN:   -- -isystem %clang_tidy_headers
+#include 
+// CHECK-FIXES: #include 
+
+namespace absl
+{
+// Use const char * for the format since the real type is hard to mock up.
+template 
+std::string StrFormat(const char *format, const Args&... args);
+} // namespace absl
+
+template 
+struct iterator {
+  T *operator->();
+  T &operator*();
+};
+
+std::string StrFormat_simple() {
+  return absl::StrFormat("Hello");
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("Hello");
+}
+
+std::string StrFormat_complex(const char *name, double value) {
+  return absl::StrFormat("'%s'='%f'", name, value);
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("'{}'='{:f}'", name, value);
+}
+
+std::string StrFormat_integer_conversions() {
+  return absl::StrFormat("int:%d int:%d char:%c char:%c", 65, 'A', 66, 'B');
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("int:{} int:{:d} char:{:c} char:{}", 65, 'A', 66, 'B');
+}
+
+// FormatConverter is capable of removing newlines from the end of the format
+// string. Ensure that isn't incorrectly happening for std::format.
+std::string StrFormat_no_newline_removal() {
+  return absl::StrFormat("a line\n");
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("a line\n");
+}
+
+// FormatConverter is capable of removing newlines from the end of the format
+// string. Ensure that isn't incorrectly happening for std::format.
+std::string StrFormat_cstr_removal(const std::string &s1, const std::string *s2) {
+  return absl::StrFormat("%s %s %s %s", s1.c_str(), s1.data(), s2->c_str(), s2->data());
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("{} {} {} {}", s1, s1, *s2, *s2);
+}
+
+std::string StrFormat_strict_conversion() {
+  const unsigned char uc = 'A';
+  return absl::StrFormat("Integer %hhd from unsigned char\n", uc);
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("Integer {} from unsigned char\n", uc);
+}
+
+std::string StrFormat_field_width_and_precision() {
+  auto s1 = absl::StrFormat("width only:%*d width and precision:%*.*f precision only:%.*f", 3, 42, 4, 2, 3.14159265358979323846, 5, 2.718);
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: std::format("width only:{:{}} width and precision:{:{}.{}f} precision only:{:.{}f}", 42, 3, 3.14159265358979323846, 4, 2, 2.718, 5);
+
+  auto s2 = absl::StrFormat("width and precision positional:%1$*2$.*3$f after", 3.14159265358979323846, 4, 2);
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: std::format("width and precision positional

[PATCH] D156616: [clang-tidy] Fix c_str() removal and cast addition when re-ordering arguments

2023-08-02 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 546414.
mikecrowe added a comment.

Reinstate version I incorrectly replaced with D154287 



Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156616/new/

https://reviews.llvm.org/D156616

Files:
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.h
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
@@ -14,6 +14,12 @@
 #include 
 #include 
 
+template 
+struct iterator {
+  T *operator->();
+  T &operator*();
+};
+
 void printf_simple() {
   printf("Hello");
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
@@ -1121,11 +1127,32 @@
   // CHECK-FIXES: std::println("Hello {:.5}", 'G');
 }
 
-void printf_field_width_and_precision() {
+void printf_field_width_and_precision(const std::string &s1, const std::string &s2, const std::string &s3)
+{
   printf("width only:%*d width and precision:%*.*f precision only:%.*f\n", 3, 42, 4, 2, 3.14159265358979323846, 5, 2.718);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
   // CHECK-FIXES: std::println("width only:{:{}} width and precision:{:{}.{}f} precision only:{:.{}f}", 42, 3, 3.14159265358979323846, 4, 2, 2.718, 5);
 
+  const unsigned int ui1 = 42, ui2 = 43, ui3 = 44;
+  printf("casts width only:%*d width and precision:%*.*d precision only:%.*d\n", 3, ui1, 4, 2, ui2, 5, ui3);
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+  // CHECK-FIXES-NOTSTRICT: std::println("casts width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", ui1, 3, ui2, 4, 2, ui3, 5);
+  // CHECK-FIXES-STRICT: std::println("casts width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", static_cast(ui1), 3, static_cast(ui2), 4, 2, static_cast(ui3), 5);
+
+  printf("c_str removal width only:%*s width and precision:%*.*s precision only:%.*s\n", 3, s1.c_str(), 4, 2, s2.c_str(), 5, s3.c_str());
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+  // CHECK-FIXES: std::println("c_str removal width only:{:>{}} width and precision:{:>{}.{}} precision only:{:.{}}", s1, 3, s2, 4, 2, s3, 5);
+
+  const std::string *ps1 = &s1, *ps2 = &s2, *ps3 = &s3;
+  printf("c_str() removal pointer width only:%-*s width and precision:%-*.*s precision only:%-.*s\n", 3, ps1->c_str(), 4, 2, ps2->c_str(), 5, ps3->c_str());
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+  // CHECK-FIXES: std::println("c_str() removal pointer width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", *ps1, 3, *ps2, 4, 2, *ps3, 5);
+
+  iterator is1, is2, is3;
+  printf("c_str() removal iterator width only:%-*s width and precision:%-*.*s precision only:%-.*s\n", 3, is1->c_str(), 4, 2, is2->c_str(), 5, is3->c_str());
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+  // CHECK-FIXES: std::println("c_str() removal iterator width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", *is1, 3, *is2, 4, 2, *is3, 5);
+
   printf("width and precision positional:%1$*2$.*3$f after\n", 3.14159265358979323846, 4, 2);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
   // CHECK-FIXES: std::println("width and precision positional:{0:{1}.{2}f} after", 3.14159265358979323846, 4, 2);
@@ -1134,9 +1161,13 @@
   printf("width only:%3$*1$d width and precision:%4$*1$.*2$f precision only:%5$.*2$f\n", width, precision, 42, 3.1415926, 2.718);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
   // CHECK-FIXES: std::println("width only:{2:{0}} width and precision:{3:{0}.{1}f} precision only:{4:.{1}f}", width, precision, 42, 3.1415926, 2.718);
+
+  printf("c_str removal width only:%3$*1$s width and precision:%4$*1$.*2$s precision only:%5$.*2$s\n", width, precision, s1.c_str(), s2.c_str(), s3.c_str());
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+  // CHECK-FIXES: std::println("c_str removal width only:{2:>{0}} width and precision:{3:>{0}.{1}} precision only:{4:.{1}}", width, precision, s1, s2, s3);
 }
 
-void fprintf_field_width_and_precision() {
+void fprintf_field_width_and_precision(const std::string &s1, const std::string &s2, const std::string &s3) {
   fprintf(stderr, 

[PATCH] D154287: [clang-tidy] Add modernize-use-std-format check

2023-08-02 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 546418.
mikecrowe added a comment.

Rebase on top of D156616  and add more tests


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154287/new/

https://reviews.llvm.org/D154287

Files:
  clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
  clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
  clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp
  clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.h
  clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-format.rst
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-fmt.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp
@@ -0,0 +1,97 @@
+// RUN: %check_clang_tidy \
+// RUN:   -std=c++20 %s modernize-use-std-format %t -- \
+// RUN:   -config="{CheckOptions: [{key: StrictMode, value: true}]}" \
+// RUN:   -- -isystem %clang_tidy_headers
+// RUN: %check_clang_tidy \
+// RUN:   -std=c++20 %s modernize-use-std-format %t -- \
+// RUN:   -config="{CheckOptions: [{key: StrictMode, value: false}]}" \
+// RUN:   -- -isystem %clang_tidy_headers
+#include 
+// CHECK-FIXES: #include 
+
+namespace absl
+{
+// Use const char * for the format since the real type is hard to mock up.
+template 
+std::string StrFormat(const char *format, const Args&... args);
+} // namespace absl
+
+template 
+struct iterator {
+  T *operator->();
+  T &operator*();
+};
+
+std::string StrFormat_simple() {
+  return absl::StrFormat("Hello");
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("Hello");
+}
+
+std::string StrFormat_complex(const char *name, double value) {
+  return absl::StrFormat("'%s'='%f'", name, value);
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("'{}'='{:f}'", name, value);
+}
+
+std::string StrFormat_integer_conversions() {
+  return absl::StrFormat("int:%d int:%d char:%c char:%c", 65, 'A', 66, 'B');
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("int:{} int:{:d} char:{:c} char:{}", 65, 'A', 66, 'B');
+}
+
+// FormatConverter is capable of removing newlines from the end of the format
+// string. Ensure that isn't incorrectly happening for std::format.
+std::string StrFormat_no_newline_removal() {
+  return absl::StrFormat("a line\n");
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("a line\n");
+}
+
+// FormatConverter is capable of removing newlines from the end of the format
+// string. Ensure that isn't incorrectly happening for std::format.
+std::string StrFormat_cstr_removal(const std::string &s1, const std::string *s2) {
+  return absl::StrFormat("%s %s %s %s", s1.c_str(), s1.data(), s2->c_str(), s2->data());
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("{} {} {} {}", s1, s1, *s2, *s2);
+}
+
+std::string StrFormat_strict_conversion() {
+  const unsigned char uc = 'A';
+  return absl::StrFormat("Integer %hhd from unsigned char\n", uc);
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("Integer {} from unsigned char\n", uc);
+}
+
+std::string StrFormat_field_width_and_precision() {
+  auto s1 = absl::StrFormat("width only:%*d width and precision:%*.*f precision only:%.*f", 3, 42, 4, 2, 3.14159265358979323846, 5, 2.718);
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: std::format("width only:{:{}} width and precision:{:{}.{}f} precision only:{:.{}f}", 42, 3, 3.14159265358979323846, 4, 2, 2.718, 5);
+
+  auto s2 = absl::StrFormat("width and precision positional:%1$*2$.*3$f after", 3.14159265358979323846, 4, 2);
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: std::format("width and precision positional

[PATCH] D154283: [clang-tidy] Fix width/precision argument order in modernize-use-std-print

2023-07-01 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
mikecrowe added a reviewer: PiotrZSL.
Herald added subscribers: carlosgalvezp, xazax.hun.
Herald added a reviewer: njames93.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

Victor Zverovich pointed out[1] that printf takes the field width and
precision arguments before the value to be printed whereas std::print
takes the value first (unless positional arguments are used.) Many of
the test cases in use-std-print.cpp were incorrect.

Teach the check to rotate the arguments when required to correct
this. Correct the test cases and add more.

[1] https://github.com/fmtlib/fmt/pull/3515#issuecomment-1615259893


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D154283

Files:
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.h
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
@@ -1024,7 +1024,7 @@
 
   printf("Right-justified integer with field width argument %*d after\n", 5, 424242);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
-  // CHECK-FIXES: std::println("Right-justified integer with field width argument {:{}} after", 5, 424242);
+  // CHECK-FIXES: std::println("Right-justified integer with field width argument {:{}} after", 424242, 5);
 
   printf("Right-justified integer with field width argument %2$*1$d after\n", 5, 424242);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
@@ -1061,7 +1061,7 @@
 
   printf("Left-justified integer with field width argument %-*d after\n", 5, 424242);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
-  // CHECK-FIXES: std::println("Left-justified integer with field width argument {:<{}} after", 5, 424242);
+  // CHECK-FIXES: std::println("Left-justified integer with field width argument {:<{}} after", 424242, 5);
 
   printf("Left-justified integer with field width argument %2$-*1$d after\n", 5, 424242);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
@@ -1087,15 +1087,15 @@
 
   printf("Hello %.*f after\n", 10, 3.14159265358979323846);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
-  // CHECK-FIXES: std::println("Hello {:.{}f} after", 10, 3.14159265358979323846);
+  // CHECK-FIXES: std::println("Hello {:.{}f} after", 3.14159265358979323846, 10);
 
   printf("Hello %10.*f after\n", 3, 3.14159265358979323846);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
-  // CHECK-FIXES: std::println("Hello {:10.{}f} after", 3, 3.14159265358979323846);
+  // CHECK-FIXES: std::println("Hello {:10.{}f} after", 3.14159265358979323846, 3);
 
   printf("Hello %*.*f after\n", 10, 4, 3.14159265358979323846);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
-  // CHECK-FIXES: std::println("Hello {:{}.{}f} after", 10, 4, 3.14159265358979323846);
+  // CHECK-FIXES: std::println("Hello {:{}.{}f} after", 3.14159265358979323846, 10, 4);
 
   printf("Hello %1$.*2$f after\n", 3.14159265358979323846, 4);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
@@ -1112,9 +1112,33 @@
 }
 
 void printf_field_width_and_precision() {
-  printf("Hello %1$*2$.*3$f after\n", 3.14159265358979323846, 4, 2);
+  printf("width only:%*d width and precision:%*.*f precision only:%.*f\n", 3, 42, 4, 2, 3.14159265358979323846, 5, 2.718);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
-  // CHECK-FIXES: std::println("Hello {0:{1}.{2}f} after", 3.14159265358979323846, 4, 2);
+  // CHECK-FIXES: std::println("width only:{:{}} width and precision:{:{}.{}f} precision only:{:.{}f}", 42, 3, 3.14159265358979323846, 4, 2, 2.718, 5);
+
+  printf("width and precision positional:%1$*2$.*3$f after\n", 3.14159265358979323846, 4, 2);
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+  // CHECK-FIXES: std::println("width and precision positional:{0:{1}.{2}f} after", 3.14159265358979323846, 4, 2);
+
+  const int width = 10, precision = 3;
+  printf("width only:%3$*1$d width and precision:%4$*1$.*2$f precision only:%5$.*2$f\n", width, precision, 42, 3.1415926, 2.718);
+  // CHECK-MESSAG

[PATCH] D154287: [clang-tidy] Add modernize-use-std-format check

2023-07-01 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
mikecrowe added a reviewer: PiotrZSL.
Herald added subscribers: carlosgalvezp, xazax.hun.
Herald added a reviewer: njames93.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

Add a new clang-tidy check that converts absl::StrFormat (and similar
functions) to std::format (and similar functions.)

Separate the configuration of FormatStringConverter out to a separate
Configuration class so that we don't risk confusion by passing two
boolean configuration parameters into the constructor. Add
AllowTrailingNewlineRemoval option since we never want to remove
trailing newlines in this check.

Depends on D154283 


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D154287

Files:
  clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
  clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
  clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp
  clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.h
  clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-format.rst
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-fmt.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp
@@ -0,0 +1,75 @@
+// RUN: %check_clang_tidy \
+// RUN:   -std=c++20 %s modernize-use-std-format %t -- \
+// RUN:   -config="{CheckOptions: [{key: StrictMode, value: true}]}" \
+// RUN:   -- -isystem %clang_tidy_headers
+// RUN: %check_clang_tidy \
+// RUN:   -std=c++20 %s modernize-use-std-format %t -- \
+// RUN:   -config="{CheckOptions: [{key: StrictMode, value: false}]}" \
+// RUN:   -- -isystem %clang_tidy_headers
+#include 
+// CHECK-FIXES: #include 
+
+namespace absl
+{
+// Use const char * for the format since the real type is hard to mock up.
+template 
+std::string StrFormat(const char *format, const Args&... args);
+} // namespace absl
+
+std::string StrFormat_simple() {
+  return absl::StrFormat("Hello");
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("Hello");
+}
+
+std::string StrFormat_complex(const char *name, double value) {
+  return absl::StrFormat("'%s'='%f'", name, value);
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("'{}'='{:f}'", name, value);
+}
+
+std::string StrFormat_integer_conversions() {
+  return absl::StrFormat("int:%d int:%d char:%c char:%c", 65, 'A', 66, 'B');
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("int:{} int:{:d} char:{:c} char:{}", 65, 'A', 66, 'B');
+}
+
+// FormatConverter is capable of removing newlines from the end of the format
+// string. Ensure that isn't incorrectly happening for std::format.
+std::string StrFormat_no_newline_removal() {
+  return absl::StrFormat("a line\n");
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("a line\n");
+}
+
+// FormatConverter is capable of removing newlines from the end of the format
+// string. Ensure that isn't incorrectly happening for std::format.
+std::string StrFormat_cstr_removal(const std::string &s1, const std::string *s2) {
+  return absl::StrFormat("%s %s %s %s", s1.c_str(), s1.data(), s2->c_str(), s2->data());
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("{} {} {} {}", s1, s1, *s2, *s2);
+}
+
+std::string StrFormat_strict_conversion() {
+  const unsigned char uc = 'A';
+  return absl::StrFormat("Integer %hhd from unsigned char\n", uc);
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("Integer {} from unsigned char\n", uc);
+}
+
+std::string StrFormat_field_width_and_precision() {
+  auto s1 = absl::StrFormat("width only:%*d width and precision:%*.*f precision only:%.*f", 3, 42, 4, 2, 3.14159265358979323846, 5, 2.718);
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' ins

[PATCH] D154283: [clang-tidy] Fix width/precision argument order in modernize-use-std-print

2023-07-02 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

Thanks for the review.




Comment at: clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp:356-357
+  if (ArgCount)
+ArgRotates.push_back(
+std::make_tuple(FS.getArgIndex() + ArgsOffset, ArgCount));
+}

PiotrZSL wrote:
> 
Good point.



Comment at: clang-tools-extra/clang-tidy/utils/FormatStringConverter.h:73
+  // puts the width and preicision first.
+  std::vector> ArgRotates;
+

PiotrZSL wrote:
> NOTE: You can use std::pair here.
True, but in my mind `std::pair` only exists because `std::tuple` couldn't be 
implemented in the C++98.

I was going to change it to use `std::pair` anyway, but I notice that I already 
use `std::tuple` for `ArgFixes` just above. Should I change both of them?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154283/new/

https://reviews.llvm.org/D154283

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D154283: [clang-tidy] Fix width/precision argument order in modernize-use-std-print

2023-07-02 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 536595.
mikecrowe added a comment.

Use emplace_back rather than push_back(make_tuple())


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154283/new/

https://reviews.llvm.org/D154283

Files:
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.h
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
@@ -1024,7 +1024,7 @@
 
   printf("Right-justified integer with field width argument %*d after\n", 5, 424242);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
-  // CHECK-FIXES: std::println("Right-justified integer with field width argument {:{}} after", 5, 424242);
+  // CHECK-FIXES: std::println("Right-justified integer with field width argument {:{}} after", 424242, 5);
 
   printf("Right-justified integer with field width argument %2$*1$d after\n", 5, 424242);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
@@ -1061,7 +1061,7 @@
 
   printf("Left-justified integer with field width argument %-*d after\n", 5, 424242);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
-  // CHECK-FIXES: std::println("Left-justified integer with field width argument {:<{}} after", 5, 424242);
+  // CHECK-FIXES: std::println("Left-justified integer with field width argument {:<{}} after", 424242, 5);
 
   printf("Left-justified integer with field width argument %2$-*1$d after\n", 5, 424242);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
@@ -1087,15 +1087,15 @@
 
   printf("Hello %.*f after\n", 10, 3.14159265358979323846);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
-  // CHECK-FIXES: std::println("Hello {:.{}f} after", 10, 3.14159265358979323846);
+  // CHECK-FIXES: std::println("Hello {:.{}f} after", 3.14159265358979323846, 10);
 
   printf("Hello %10.*f after\n", 3, 3.14159265358979323846);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
-  // CHECK-FIXES: std::println("Hello {:10.{}f} after", 3, 3.14159265358979323846);
+  // CHECK-FIXES: std::println("Hello {:10.{}f} after", 3.14159265358979323846, 3);
 
   printf("Hello %*.*f after\n", 10, 4, 3.14159265358979323846);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
-  // CHECK-FIXES: std::println("Hello {:{}.{}f} after", 10, 4, 3.14159265358979323846);
+  // CHECK-FIXES: std::println("Hello {:{}.{}f} after", 3.14159265358979323846, 10, 4);
 
   printf("Hello %1$.*2$f after\n", 3.14159265358979323846, 4);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
@@ -1112,9 +1112,33 @@
 }
 
 void printf_field_width_and_precision() {
-  printf("Hello %1$*2$.*3$f after\n", 3.14159265358979323846, 4, 2);
+  printf("width only:%*d width and precision:%*.*f precision only:%.*f\n", 3, 42, 4, 2, 3.14159265358979323846, 5, 2.718);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
-  // CHECK-FIXES: std::println("Hello {0:{1}.{2}f} after", 3.14159265358979323846, 4, 2);
+  // CHECK-FIXES: std::println("width only:{:{}} width and precision:{:{}.{}f} precision only:{:.{}f}", 42, 3, 3.14159265358979323846, 4, 2, 2.718, 5);
+
+  printf("width and precision positional:%1$*2$.*3$f after\n", 3.14159265358979323846, 4, 2);
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+  // CHECK-FIXES: std::println("width and precision positional:{0:{1}.{2}f} after", 3.14159265358979323846, 4, 2);
+
+  const int width = 10, precision = 3;
+  printf("width only:%3$*1$d width and precision:%4$*1$.*2$f precision only:%5$.*2$f\n", width, precision, 42, 3.1415926, 2.718);
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+  // CHECK-FIXES: std::println("width only:{2:{0}} width and precision:{3:{0}.{1}f} precision only:{4:.{1}f}", width, precision, 42, 3.1415926, 2.718);
+}
+
+void fprintf_field_width_and_precision() {
+  fprintf(stderr, "width only:%*d width and precision:%*.*f precision only:%.*f\n", 3, 42, 4, 2, 3.14159265358979323846, 5, 2.718);
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'fprintf' [modernize-use-std-print]
+  // CHECK-FIXES: s

[PATCH] D154283: [clang-tidy] Fix width/precision argument order in modernize-use-std-print

2023-07-02 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added inline comments.



Comment at: clang-tools-extra/clang-tidy/utils/FormatStringConverter.h:73
+  // puts the width and preicision first.
+  std::vector> ArgRotates;
+

PiotrZSL wrote:
> mikecrowe wrote:
> > PiotrZSL wrote:
> > > NOTE: You can use std::pair here.
> > True, but in my mind `std::pair` only exists because `std::tuple` couldn't 
> > be implemented in the C++98.
> > 
> > I was going to change it to use `std::pair` anyway, but I notice that I 
> > already use `std::tuple` for `ArgFixes` just above. Should I change both of 
> > them?
> It will be compiled to same thing anyway. So it's up to you. Keep it 
> consistent.
> I personally use std::pair for 2 arguments, and std::tuple for more than 2.
> But to be honest probably better would be to introduce some structure so that 
> those two `unsigned` could be named. And probably same for ArgFixes, but 
> there we got different types, so it's not a big problem.
I think that you're probably right, but the names won't be used from the call 
site since I use structured binding there. Do you mind if I do both together in 
a separate commit?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154283/new/

https://reviews.llvm.org/D154283

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D154287: [clang-tidy] Add modernize-use-std-format check

2023-07-09 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe marked 9 inline comments as done.
mikecrowe added a comment.

Thanks for the reviews!




Comment at: clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp:81
+ << ReplacementFormatFunction
+ << OldFunction->getIdentifier()
+ << Converter.conversionNotPossibleReason();

PiotrZSL wrote:
> using ``<< OldFunction`` should be sufficient and more safe, same in line 88
I don't think that's the same. If I use just `OldFunction` then I get the 
template arguments in strings like `StrFormat` and `sprintf` when I just want `StrFormat` 
and `sprintf` respectively.



Comment at: clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp:629-630
+  if (Config.AllowTrailingNewlineRemoval &&
+  StringRef(StandardFormatString).ends_with("\\n") &&
   !StringRef(StandardFormatString).ends_with("n")) {
 UsePrintNewlineFunction = true;

PiotrZSL wrote:
> what if it's ends with Windows new line style ? Will it work ?
Good point. Your question actually relates to the `modernize-use-std-print` 
check only since `config.AllowTrailingNewlineRemoval` is always `false` in this 
check.

`std::println` is [[ https://en.cppreference.com/w/cpp/io/println | described 
]] as just appending `\n` to the end of the formatted string when written to 
the desired output. The code here means that `printf("A\r\n")` would be 
converted to `std::println("A\r")` which would behave in the same way, though I 
would admit that it's rather confusing.

This situation isn't really Windows-specific. Most the of the time a POSIX tty 
would be in cooked mode, so the `\r` would be added automatically before the 
`\n`. However, when the tty is in raw mode using `\r\n` line endings would be 
necessary there too, just as they might be on Windows when writing to a binary 
stream.

I think that the least confusing outcome would be for this code to not consider 
format strings that end with `\r\n`  to be suitable for conversion to 
`std::println` and let them use `std::print` instead. I think that this better 
reflects the intent of the existing code.

I will prepare a separate change for this.



Comment at: 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-format.rst:27
+The check uses the same format-string-conversion algorithm as
+`modernize-use-std-print ` and its
+shortcomings are described in the documentation for that check.

PiotrZSL wrote:
> is this link correct ? shouldn't this be put into `doc:`, verify if its 
> working
It was wrong, but I believe that I've fixed it.



Comment at: 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-format.rst:33
+
+.. option:: StrictMode TODO
+

PiotrZSL wrote:
> If not implemented, do not add it
It is implemented, I just forgot to remove the TODO.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154287/new/

https://reviews.llvm.org/D154287

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D154788: [clang-tidy] Don't split \r\n in modernize-use-std-print check

2023-07-09 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
mikecrowe added a reviewer: PiotrZSL.
Herald added subscribers: carlosgalvezp, xazax.hun.
Herald added a reviewer: njames93.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

When given:
 printf("Hello\r\n");

it's clearer to leave the CRLF intact and convert this to:
 std::print("Hello\r\n");

than to remove the trailing newline and convert it to:
 std::println("Hello\r");

Update the documentation to match, and clarify the situations for using
println vs print which weren't previously explained.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D154788

Files:
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
  clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
@@ -44,6 +44,16 @@
   // CHECK-FIXES: std::println("Hello");
 }
 
+void printf_crlf_newline() {
+  printf("Hello\r\n");
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 
'printf' [modernize-use-std-print]
+  // CHECK-FIXES: std::print("Hello\r\n");
+
+  printf("Hello\r\\n");
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 
'printf' [modernize-use-std-print]
+  // CHECK-FIXES: std::print("Hello\r\\n");
+}
+
 // std::print returns nothing, so any callers that use the return
 // value cannot be automatically translated.
 int printf_uses_return_value(int choice) {
Index: clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst
+++ clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst
@@ -70,8 +70,10 @@
   `FprintfLikeFunctions` are replaced with the function specified by the
   `ReplacementPrintlnFunction` option if the format string ends with ``\n``
   or `ReplacementPrintFunction` otherwise.
-- the format string is rewritten to use the ``std::formatter`` language and
-  a ``\n`` is removed from the end.
+- the format string is rewritten to use the ``std::formatter`` language. If
+  a ``\n`` is found at the end of the format string not preceded by ``r``
+  then it is removed and `ReplacementPrintlnFunction` is used rather than
+  `ReplacementPrintFunction`.
 - any arguments that corresponded to ``%p`` specifiers that
   ``std::formatter`` wouldn't accept are wrapped in a ``static_cast``
   to ``const void *``.
Index: clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
===
--- clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
+++ clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
@@ -623,8 +623,11 @@
 PrintfFormatString.size() - PrintfFormatStringPos));
   PrintfFormatStringPos = PrintfFormatString.size();
 
+  // It's clearer to convert printf("Hello\r\n"); to std::print("Hello\r\n")
+  // than to std::println("Hello\r");
   if (StringRef(StandardFormatString).ends_with("\\n") &&
-  !StringRef(StandardFormatString).ends_with("n")) {
+  !StringRef(StandardFormatString).ends_with("n") &&
+  !StringRef(StandardFormatString).ends_with("\\r\\n")) {
 UsePrintNewlineFunction = true;
 FormatStringNeededRewriting = true;
 StandardFormatString.erase(StandardFormatString.end() - 2,


Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
@@ -44,6 +44,16 @@
   // CHECK-FIXES: std::println("Hello");
 }
 
+void printf_crlf_newline() {
+  printf("Hello\r\n");
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
+  // CHECK-FIXES: std::print("Hello\r\n");
+
+  printf("Hello\r\\n");
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
+  // CHECK-FIXES: std::print("Hello\r\\n");
+}
+
 // std::print returns nothing, so any callers that use the return
 // value cannot be automatically translated.
 int printf_uses_return_value(int choice) {
Index: clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst
+++ clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.

[PATCH] D154287: [clang-tidy] Add modernize-use-std-format check

2023-07-09 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 538427.
mikecrowe marked 3 inline comments as done.
mikecrowe added a comment.

Address review comments and improve documentation.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154287/new/

https://reviews.llvm.org/D154287

Files:
  clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
  clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
  clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp
  clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.h
  clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-format.rst
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-fmt.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp
@@ -0,0 +1,75 @@
+// RUN: %check_clang_tidy \
+// RUN:   -std=c++20 %s modernize-use-std-format %t -- \
+// RUN:   -config="{CheckOptions: [{key: StrictMode, value: true}]}" \
+// RUN:   -- -isystem %clang_tidy_headers
+// RUN: %check_clang_tidy \
+// RUN:   -std=c++20 %s modernize-use-std-format %t -- \
+// RUN:   -config="{CheckOptions: [{key: StrictMode, value: false}]}" \
+// RUN:   -- -isystem %clang_tidy_headers
+#include 
+// CHECK-FIXES: #include 
+
+namespace absl
+{
+// Use const char * for the format since the real type is hard to mock up.
+template 
+std::string StrFormat(const char *format, const Args&... args);
+} // namespace absl
+
+std::string StrFormat_simple() {
+  return absl::StrFormat("Hello");
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("Hello");
+}
+
+std::string StrFormat_complex(const char *name, double value) {
+  return absl::StrFormat("'%s'='%f'", name, value);
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("'{}'='{:f}'", name, value);
+}
+
+std::string StrFormat_integer_conversions() {
+  return absl::StrFormat("int:%d int:%d char:%c char:%c", 65, 'A', 66, 'B');
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("int:{} int:{:d} char:{:c} char:{}", 65, 'A', 66, 'B');
+}
+
+// FormatConverter is capable of removing newlines from the end of the format
+// string. Ensure that isn't incorrectly happening for std::format.
+std::string StrFormat_no_newline_removal() {
+  return absl::StrFormat("a line\n");
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("a line\n");
+}
+
+// FormatConverter is capable of removing newlines from the end of the format
+// string. Ensure that isn't incorrectly happening for std::format.
+std::string StrFormat_cstr_removal(const std::string &s1, const std::string *s2) {
+  return absl::StrFormat("%s %s %s %s", s1.c_str(), s1.data(), s2->c_str(), s2->data());
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("{} {} {} {}", s1, s1, *s2, *s2);
+}
+
+std::string StrFormat_strict_conversion() {
+  const unsigned char uc = 'A';
+  return absl::StrFormat("Integer %hhd from unsigned char\n", uc);
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("Integer {} from unsigned char\n", uc);
+}
+
+std::string StrFormat_field_width_and_precision() {
+  auto s1 = absl::StrFormat("width only:%*d width and precision:%*.*f precision only:%.*f", 3, 42, 4, 2, 3.14159265358979323846, 5, 2.718);
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: std::format("width only:{:{}} width and precision:{:{}.{}f} precision only:{:.{}f}", 42, 3, 3.14159265358979323846, 4, 2, 2.718, 5);
+
+  auto s2 = absl::StrFormat("width and precision positional:%1$*2$.*3$f after", 3.14159265358979323846, 4, 2);
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: std::format("width and precision positional:{0:{1}.{2}f} after", 3.14159265358979323846, 4, 2);
+
+  c

[PATCH] D154287: [clang-tidy] Add modernize-use-std-format check

2023-07-09 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added inline comments.



Comment at: clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp:46
+void UseStdFormatCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  callExpr(argumentCountAtLeast(1), hasArgument(0, stringLiteral()),

This matcher also matches the `operator+` call in:
```
std::string A(const std::string &in)


{   


return "_" + in;


}   


```
which causes an assertion failure:
```
clang-tidy: /home/mac/git/llvm-project/clang/include/clang/AST/Decl.h:275: 
llvm::StringRef clang::NamedDecl::getName() const: Assertion 
`Name.isIdentifier() && "Name is not a simple identifier"' failed.
```
when the `StrFormatLikeFunctions` option is set to an unqualified name:
```
-config="{CheckOptions: [{key: modernize-use-std-format.StrictMode, value: 
false}, {key: modernize-use-std-format.StrFormatLikeFunctions, value: 
'strprintf'}]}"
```

`MatchesAnyListedNameMatcher::NameMatcher::match` calls `NamedDecl.getName()` 
which presumably raises the assertion due to the `operator+` not having a name 
(that's mentioned in the source anyway.)

I'm unsure whether I should be narrowing the matcher here so that it guaranteed 
to not try calling `matchesAnyListedName` on something that lacks a name, or 
whether `MatchesAnyListedNameMatcher` ought to be more tolerant of being called 
in such situations.

I note that `HasNameMatcher` has rather more elaborate code for generating the 
name than `MatchesAnyListedNameMatcher` does.

This problem also affects `modernize-use-std-print`, but due to the need for 
there to be no return value in that check it requires somewhat-unlikely code 
like:
```
void A(const std::string &in)
{
  "_" + in;
}
```

Do you have any advice? Given that this problem affects a check that has 
already landed should I open a bug?



Comment at: clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp:47
+  Finder->addMatcher(
+  callExpr(argumentCountAtLeast(1), hasArgument(0, stringLiteral()),
+   callee(functionDecl(matchers::matchesAnyListedName(

I need to add an `isOrdinary()` call here like `modernize-use-std-print` has.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154287/new/

https://reviews.llvm.org/D154287

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D154884: [clang-tidy] Make MatchesAnyListedNameMatcher cope with unnamed Decl

2023-07-10 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
mikecrowe added a reviewer: PiotrZSL.
Herald added subscribers: carlosgalvezp, xazax.hun.
Herald added a reviewer: njames93.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

If MatchesAnyListedNameMatcher::NameMatcher::match() is called in
MatchMode::MatchUnqualified mode with a NamedDecl that has no name then
calling NamedDecl::getName() will assert with:
 `Name.isIdentifier() && "Name is not a simple identifier"'

This situation can be reproduced by running:
 clang-tidy '-checks=-*,modernize-use-std-print' -fix -config="{CheckOptions: 
[[:] + [modernize-use-std-print.PrintfLikeFunctions,] + [value:] + ['printf']]}"
on:
 void A(const std::string &in)
 {

  "A" + in;

}

It seems unfair to force all matchers using
matchers::matchesAnyListedName to defend against this, particularly
since test cases are unlikely to provoke the problem. Let's just check
whether the identifier has a name before attempting to use it instead.

Add test case that reproduces the problem to the
use-std-print-custom.cpp lit check.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D154884

Files:
  clang-tools-extra/clang-tidy/utils/Matchers.h
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp
@@ -3,7 +3,7 @@
 // RUN: [ \
 // RUN:  { \
 // RUN:   key: modernize-use-std-print.PrintfLikeFunctions, \
-// RUN:   value: '::myprintf; mynamespace::myprintf2' \
+// RUN:   value: 'unqualified_printf;::myprintf; 
mynamespace::myprintf2' \
 // RUN:  }, \
 // RUN:  { \
 // RUN:   key: modernize-use-std-print.FprintfLikeFunctions, \
@@ -14,7 +14,7 @@
 // RUN:   -- -isystem %clang_tidy_headers
 
 #include 
-#include 
+#include 
 
 int myprintf(const char *, ...);
 int myfprintf(FILE *fp, const char *, ...);
@@ -85,3 +85,10 @@
   // CHECK-MESSAGES-NOT: [[@LINE-1]]:10: warning: use 'std::println' instead 
of 'myprintf' [modernize-use-std-print]
   // CHECK-FIXES-NOT: std::println(stderr, "return value {}", i);
 }
+
+// Ensure that MatchesAnyListedNameMatcher::NameMatcher::match() can cope with 
a
+// NamedDecl that has no name when we're trying to match unqualified_printf.
+void no_name(const std::string &in)
+{
+  "A" + in;
+}
Index: clang-tools-extra/clang-tidy/utils/Matchers.h
===
--- clang-tools-extra/clang-tidy/utils/Matchers.h
+++ clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -112,7 +112,9 @@
   case MatchMode::MatchFullyQualified:
 return Regex.match("::" + ND.getQualifiedNameAsString());
   default:
-return Regex.match(ND.getName());
+if (const IdentifierInfo *II = ND.getIdentifier(); II)
+  return Regex.match(II->getName());
+return false;
   }
 }
 


Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp
@@ -3,7 +3,7 @@
 // RUN: [ \
 // RUN:  { \
 // RUN:   key: modernize-use-std-print.PrintfLikeFunctions, \
-// RUN:   value: '::myprintf; mynamespace::myprintf2' \
+// RUN:   value: 'unqualified_printf;::myprintf; mynamespace::myprintf2' \
 // RUN:  }, \
 // RUN:  { \
 // RUN:   key: modernize-use-std-print.FprintfLikeFunctions, \
@@ -14,7 +14,7 @@
 // RUN:   -- -isystem %clang_tidy_headers
 
 #include 
-#include 
+#include 
 
 int myprintf(const char *, ...);
 int myfprintf(FILE *fp, const char *, ...);
@@ -85,3 +85,10 @@
   // CHECK-MESSAGES-NOT: [[@LINE-1]]:10: warning: use 'std::println' instead of 'myprintf' [modernize-use-std-print]
   // CHECK-FIXES-NOT: std::println(stderr, "return value {}", i);
 }
+
+// Ensure that MatchesAnyListedNameMatcher::NameMatcher::match() can cope with a
+// NamedDecl that has no name when we're trying to match unqualified_printf.
+void no_name(const std::string &in)
+{
+  "A" + in;
+}
Index: clang-tools-extra/clang-tidy/utils/Matchers.h
===
--- clang-tools-extra/clang-tidy/utils/Matchers.h
+++ clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -112,7 +112,9 @@
   case MatchMode::MatchFullyQualified:
 return Regex.match("::" + ND.getQualifiedNameAsString());
   de

[PATCH] D154287: [clang-tidy] Add modernize-use-std-format check

2023-07-10 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added inline comments.



Comment at: clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp:46
+void UseStdFormatCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  callExpr(argumentCountAtLeast(1), hasArgument(0, stringLiteral()),

PiotrZSL wrote:
> mikecrowe wrote:
> > This matcher also matches the `operator+` call in:
> > ```
> > std::string A(const std::string &in)
> > 
> > 
> > {   
> > 
> > 
> > return "_" + in;
> > 
> > 
> > }   
> > 
> > 
> > ```
> > which causes an assertion failure:
> > ```
> > clang-tidy: /home/mac/git/llvm-project/clang/include/clang/AST/Decl.h:275: 
> > llvm::StringRef clang::NamedDecl::getName() const: Assertion 
> > `Name.isIdentifier() && "Name is not a simple identifier"' failed.
> > ```
> > when the `StrFormatLikeFunctions` option is set to an unqualified name:
> > ```
> > -config="{CheckOptions: [{key: modernize-use-std-format.StrictMode, value: 
> > false}, {key: modernize-use-std-format.StrFormatLikeFunctions, value: 
> > 'strprintf'}]}"
> > ```
> > 
> > `MatchesAnyListedNameMatcher::NameMatcher::match` calls 
> > `NamedDecl.getName()` which presumably raises the assertion due to the 
> > `operator+` not having a name (that's mentioned in the source anyway.)
> > 
> > I'm unsure whether I should be narrowing the matcher here so that it 
> > guaranteed to not try calling `matchesAnyListedName` on something that 
> > lacks a name, or whether `MatchesAnyListedNameMatcher` ought to be more 
> > tolerant of being called in such situations.
> > 
> > I note that `HasNameMatcher` has rather more elaborate code for generating 
> > the name than `MatchesAnyListedNameMatcher` does.
> > 
> > This problem also affects `modernize-use-std-print`, but due to the need 
> > for there to be no return value in that check it requires somewhat-unlikely 
> > code like:
> > ```
> > void A(const std::string &in)
> > {
> >   "_" + in;
> > }
> > ```
> > 
> > Do you have any advice? Given that this problem affects a check that has 
> > already landed should I open a bug?
> `unless(hasName(""))` could do a trick, or create own matcher to verify first 
> if function got name.
> Probably similar issues can be with cxxConversionDecl.
> 
> Other best option would be to change 
> MatchesAnyListedNameMatcher::NameMatcher::match to verify if NamedDecl got 
> name before calling it.
> `unless(hasName(""))` could do a trick, or create own matcher to verify first 
> if function got name.

That fails with a similar assertion failure.

> Probably similar issues can be with cxxConversionDecl.

I didn't really understand that one.

> Other best option would be to change 
> MatchesAnyListedNameMatcher::NameMatcher::match to verify if NamedDecl got 
> name before calling it.

That's easy and I think it's the best solution since it saves every check 
having to defend against this. I've done that in [[ 
https://reviews.llvm.org/D154884 | D154884 ]] .


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154287/new/

https://reviews.llvm.org/D154287

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D154287: [clang-tidy] Add modernize-use-std-format check

2023-07-10 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 538806.
mikecrowe added a comment.

Use isOrdinary in stringLiteral() match on first argument


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154287/new/

https://reviews.llvm.org/D154287

Files:
  clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
  clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
  clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp
  clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.h
  clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-format.rst
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-fmt.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp
@@ -0,0 +1,75 @@
+// RUN: %check_clang_tidy \
+// RUN:   -std=c++20 %s modernize-use-std-format %t -- \
+// RUN:   -config="{CheckOptions: [{key: StrictMode, value: true}]}" \
+// RUN:   -- -isystem %clang_tidy_headers
+// RUN: %check_clang_tidy \
+// RUN:   -std=c++20 %s modernize-use-std-format %t -- \
+// RUN:   -config="{CheckOptions: [{key: StrictMode, value: false}]}" \
+// RUN:   -- -isystem %clang_tidy_headers
+#include 
+// CHECK-FIXES: #include 
+
+namespace absl
+{
+// Use const char * for the format since the real type is hard to mock up.
+template 
+std::string StrFormat(const char *format, const Args&... args);
+} // namespace absl
+
+std::string StrFormat_simple() {
+  return absl::StrFormat("Hello");
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("Hello");
+}
+
+std::string StrFormat_complex(const char *name, double value) {
+  return absl::StrFormat("'%s'='%f'", name, value);
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("'{}'='{:f}'", name, value);
+}
+
+std::string StrFormat_integer_conversions() {
+  return absl::StrFormat("int:%d int:%d char:%c char:%c", 65, 'A', 66, 'B');
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("int:{} int:{:d} char:{:c} char:{}", 65, 'A', 66, 'B');
+}
+
+// FormatConverter is capable of removing newlines from the end of the format
+// string. Ensure that isn't incorrectly happening for std::format.
+std::string StrFormat_no_newline_removal() {
+  return absl::StrFormat("a line\n");
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("a line\n");
+}
+
+// FormatConverter is capable of removing newlines from the end of the format
+// string. Ensure that isn't incorrectly happening for std::format.
+std::string StrFormat_cstr_removal(const std::string &s1, const std::string *s2) {
+  return absl::StrFormat("%s %s %s %s", s1.c_str(), s1.data(), s2->c_str(), s2->data());
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("{} {} {} {}", s1, s1, *s2, *s2);
+}
+
+std::string StrFormat_strict_conversion() {
+  const unsigned char uc = 'A';
+  return absl::StrFormat("Integer %hhd from unsigned char\n", uc);
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("Integer {} from unsigned char\n", uc);
+}
+
+std::string StrFormat_field_width_and_precision() {
+  auto s1 = absl::StrFormat("width only:%*d width and precision:%*.*f precision only:%.*f", 3, 42, 4, 2, 3.14159265358979323846, 5, 2.718);
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: std::format("width only:{:{}} width and precision:{:{}.{}f} precision only:{:.{}f}", 42, 3, 3.14159265358979323846, 4, 2, 2.718, 5);
+
+  auto s2 = absl::StrFormat("width and precision positional:%1$*2$.*3$f after", 3.14159265358979323846, 4, 2);
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: std::format("width and precision positional:{0:{1}.{2}f} after", 3.14159265358979323846, 4, 2);
+
+  const int width = 10, precision = 3;
+

[PATCH] D154884: [clang-tidy] Make MatchesAnyListedNameMatcher cope with unnamed Decl

2023-07-11 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 538940.
mikecrowe marked an inline comment as done.
mikecrowe added a comment.

Remove unnecessary init-statement and test case in commit message


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154884/new/

https://reviews.llvm.org/D154884

Files:
  clang-tools-extra/clang-tidy/utils/Matchers.h
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp
@@ -3,7 +3,7 @@
 // RUN: [ \
 // RUN:  { \
 // RUN:   key: modernize-use-std-print.PrintfLikeFunctions, \
-// RUN:   value: '::myprintf; mynamespace::myprintf2' \
+// RUN:   value: 'unqualified_printf;::myprintf; 
mynamespace::myprintf2' \
 // RUN:  }, \
 // RUN:  { \
 // RUN:   key: modernize-use-std-print.FprintfLikeFunctions, \
@@ -14,7 +14,7 @@
 // RUN:   -- -isystem %clang_tidy_headers
 
 #include 
-#include 
+#include 
 
 int myprintf(const char *, ...);
 int myfprintf(FILE *fp, const char *, ...);
@@ -85,3 +85,10 @@
   // CHECK-MESSAGES-NOT: [[@LINE-1]]:10: warning: use 'std::println' instead 
of 'myprintf' [modernize-use-std-print]
   // CHECK-FIXES-NOT: std::println(stderr, "return value {}", i);
 }
+
+// Ensure that MatchesAnyListedNameMatcher::NameMatcher::match() can cope with 
a
+// NamedDecl that has no name when we're trying to match unqualified_printf.
+void no_name(const std::string &in)
+{
+  "A" + in;
+}
Index: clang-tools-extra/clang-tidy/utils/Matchers.h
===
--- clang-tools-extra/clang-tidy/utils/Matchers.h
+++ clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -112,7 +112,9 @@
   case MatchMode::MatchFullyQualified:
 return Regex.match("::" + ND.getQualifiedNameAsString());
   default:
-return Regex.match(ND.getName());
+if (const IdentifierInfo *II = ND.getIdentifier())
+  return Regex.match(II->getName());
+return false;
   }
 }
 


Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp
@@ -3,7 +3,7 @@
 // RUN: [ \
 // RUN:  { \
 // RUN:   key: modernize-use-std-print.PrintfLikeFunctions, \
-// RUN:   value: '::myprintf; mynamespace::myprintf2' \
+// RUN:   value: 'unqualified_printf;::myprintf; mynamespace::myprintf2' \
 // RUN:  }, \
 // RUN:  { \
 // RUN:   key: modernize-use-std-print.FprintfLikeFunctions, \
@@ -14,7 +14,7 @@
 // RUN:   -- -isystem %clang_tidy_headers
 
 #include 
-#include 
+#include 
 
 int myprintf(const char *, ...);
 int myfprintf(FILE *fp, const char *, ...);
@@ -85,3 +85,10 @@
   // CHECK-MESSAGES-NOT: [[@LINE-1]]:10: warning: use 'std::println' instead of 'myprintf' [modernize-use-std-print]
   // CHECK-FIXES-NOT: std::println(stderr, "return value {}", i);
 }
+
+// Ensure that MatchesAnyListedNameMatcher::NameMatcher::match() can cope with a
+// NamedDecl that has no name when we're trying to match unqualified_printf.
+void no_name(const std::string &in)
+{
+  "A" + in;
+}
Index: clang-tools-extra/clang-tidy/utils/Matchers.h
===
--- clang-tools-extra/clang-tidy/utils/Matchers.h
+++ clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -112,7 +112,9 @@
   case MatchMode::MatchFullyQualified:
 return Regex.match("::" + ND.getQualifiedNameAsString());
   default:
-return Regex.match(ND.getName());
+if (const IdentifierInfo *II = ND.getIdentifier())
+  return Regex.match(II->getName());
+return false;
   }
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D154884: [clang-tidy] Make MatchesAnyListedNameMatcher cope with unnamed Decl

2023-07-11 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

Thanks for the review.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154884/new/

https://reviews.llvm.org/D154884

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156616: [clang-tidy] Fix c_str() removal and cast addition when re-ordering arguments

2023-08-28 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

@PiotrZSL, I think that this is quite an important fix since without it the 
check completely mangles the code. Should it be put in the 17.x release branch 
too?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156616/new/

https://reviews.llvm.org/D156616

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156616: [clang-tidy] Fix c_str() removal and cast addition when re-ordering arguments

2023-08-28 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

In D156616#4621945 , @PiotrZSL wrote:

> In D156616#4621914 , @mikecrowe 
> wrote:
>
>> @PiotrZSL, I think that this is quite an important fix since without it the 
>> check completely mangles the code. Should it be put in the 17.x release 
>> branch too?
>
> If issue happens only when StrictMode is set to True, then I wouldn't worry 
> too much, and then this could wait for Clang 18 that is just half year away.

The removal of `c_str()` happens even without StrictMode set to True.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156616/new/

https://reviews.llvm.org/D156616

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156616: [clang-tidy] Fix c_str() removal and cast addition when re-ordering arguments

2023-08-28 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

> Additionally user could always take "main" version, and use it just to apply 
> fixes from this check.

OK. Can this land on main then?

Thanks.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156616/new/

https://reviews.llvm.org/D156616

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156616: [clang-tidy] Fix c_str() removal and cast addition when re-ordering arguments

2023-08-29 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

Thanks for the review and landing this.

Mike.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156616/new/

https://reviews.llvm.org/D156616

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D154287: [clang-tidy] Add modernize-use-std-format check

2023-08-29 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 55.
mikecrowe added a comment.

Rebase and fix minor doc conflicts.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154287/new/

https://reviews.llvm.org/D154287

Files:
  clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
  clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
  clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp
  clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.h
  clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-format.rst
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-fmt.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp
@@ -0,0 +1,97 @@
+// RUN: %check_clang_tidy \
+// RUN:   -std=c++20 %s modernize-use-std-format %t -- \
+// RUN:   -config="{CheckOptions: [{key: StrictMode, value: true}]}" \
+// RUN:   -- -isystem %clang_tidy_headers
+// RUN: %check_clang_tidy \
+// RUN:   -std=c++20 %s modernize-use-std-format %t -- \
+// RUN:   -config="{CheckOptions: [{key: StrictMode, value: false}]}" \
+// RUN:   -- -isystem %clang_tidy_headers
+#include 
+// CHECK-FIXES: #include 
+
+namespace absl
+{
+// Use const char * for the format since the real type is hard to mock up.
+template 
+std::string StrFormat(const char *format, const Args&... args);
+} // namespace absl
+
+template 
+struct iterator {
+  T *operator->();
+  T &operator*();
+};
+
+std::string StrFormat_simple() {
+  return absl::StrFormat("Hello");
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("Hello");
+}
+
+std::string StrFormat_complex(const char *name, double value) {
+  return absl::StrFormat("'%s'='%f'", name, value);
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("'{}'='{:f}'", name, value);
+}
+
+std::string StrFormat_integer_conversions() {
+  return absl::StrFormat("int:%d int:%d char:%c char:%c", 65, 'A', 66, 'B');
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("int:{} int:{:d} char:{:c} char:{}", 65, 'A', 66, 'B');
+}
+
+// FormatConverter is capable of removing newlines from the end of the format
+// string. Ensure that isn't incorrectly happening for std::format.
+std::string StrFormat_no_newline_removal() {
+  return absl::StrFormat("a line\n");
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("a line\n");
+}
+
+// FormatConverter is capable of removing newlines from the end of the format
+// string. Ensure that isn't incorrectly happening for std::format.
+std::string StrFormat_cstr_removal(const std::string &s1, const std::string *s2) {
+  return absl::StrFormat("%s %s %s %s", s1.c_str(), s1.data(), s2->c_str(), s2->data());
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("{} {} {} {}", s1, s1, *s2, *s2);
+}
+
+std::string StrFormat_strict_conversion() {
+  const unsigned char uc = 'A';
+  return absl::StrFormat("Integer %hhd from unsigned char\n", uc);
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("Integer {} from unsigned char\n", uc);
+}
+
+std::string StrFormat_field_width_and_precision() {
+  auto s1 = absl::StrFormat("width only:%*d width and precision:%*.*f precision only:%.*f", 3, 42, 4, 2, 3.14159265358979323846, 5, 2.718);
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: std::format("width only:{:{}} width and precision:{:{}.{}f} precision only:{:.{}f}", 42, 3, 3.14159265358979323846, 4, 2, 2.718, 5);
+
+  auto s2 = absl::StrFormat("width and precision positional:%1$*2$.*3$f after", 3.14159265358979323846, 4, 2);
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: std::format("width and precision positional:{0:{1}.{2}f} after", 3.1415926535897932384

[PATCH] D154287: [clang-tidy] Add modernize-use-std-format check

2023-08-29 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 554486.
mikecrowe edited the summary of this revision.
mikecrowe added a comment.

Fix ReleaseNotes order and remove unnecessary .html from list.rst


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154287/new/

https://reviews.llvm.org/D154287

Files:
  clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
  clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
  clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp
  clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.h
  clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp
  clang-tools-extra/clang-tidy/utils/FormatStringConverter.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-format.rst
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-fmt.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp
@@ -0,0 +1,97 @@
+// RUN: %check_clang_tidy \
+// RUN:   -std=c++20 %s modernize-use-std-format %t -- \
+// RUN:   -config="{CheckOptions: [{key: StrictMode, value: true}]}" \
+// RUN:   -- -isystem %clang_tidy_headers
+// RUN: %check_clang_tidy \
+// RUN:   -std=c++20 %s modernize-use-std-format %t -- \
+// RUN:   -config="{CheckOptions: [{key: StrictMode, value: false}]}" \
+// RUN:   -- -isystem %clang_tidy_headers
+#include 
+// CHECK-FIXES: #include 
+
+namespace absl
+{
+// Use const char * for the format since the real type is hard to mock up.
+template 
+std::string StrFormat(const char *format, const Args&... args);
+} // namespace absl
+
+template 
+struct iterator {
+  T *operator->();
+  T &operator*();
+};
+
+std::string StrFormat_simple() {
+  return absl::StrFormat("Hello");
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("Hello");
+}
+
+std::string StrFormat_complex(const char *name, double value) {
+  return absl::StrFormat("'%s'='%f'", name, value);
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("'{}'='{:f}'", name, value);
+}
+
+std::string StrFormat_integer_conversions() {
+  return absl::StrFormat("int:%d int:%d char:%c char:%c", 65, 'A', 66, 'B');
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("int:{} int:{:d} char:{:c} char:{}", 65, 'A', 66, 'B');
+}
+
+// FormatConverter is capable of removing newlines from the end of the format
+// string. Ensure that isn't incorrectly happening for std::format.
+std::string StrFormat_no_newline_removal() {
+  return absl::StrFormat("a line\n");
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("a line\n");
+}
+
+// FormatConverter is capable of removing newlines from the end of the format
+// string. Ensure that isn't incorrectly happening for std::format.
+std::string StrFormat_cstr_removal(const std::string &s1, const std::string *s2) {
+  return absl::StrFormat("%s %s %s %s", s1.c_str(), s1.data(), s2->c_str(), s2->data());
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("{} {} {} {}", s1, s1, *s2, *s2);
+}
+
+std::string StrFormat_strict_conversion() {
+  const unsigned char uc = 'A';
+  return absl::StrFormat("Integer %hhd from unsigned char\n", uc);
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: return std::format("Integer {} from unsigned char\n", uc);
+}
+
+std::string StrFormat_field_width_and_precision() {
+  auto s1 = absl::StrFormat("width only:%*d width and precision:%*.*f precision only:%.*f", 3, 42, 4, 2, 3.14159265358979323846, 5, 2.718);
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: std::format("width only:{:{}} width and precision:{:{}.{}f} precision only:{:.{}f}", 42, 3, 3.14159265358979323846, 4, 2, 2.718, 5);
+
+  auto s2 = absl::StrFormat("width and precision positional:%1$*2$.*3$f after", 3.14159265358979323846, 4, 2);
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
+  // CHECK-FIXES: std::form

[PATCH] D144216: [clang-tidy] Extract string header from redundant-string-cstr checker

2023-03-04 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 502385.
mikecrowe edited the summary of this revision.
mikecrowe added a comment.

This new version uses size_t and size_type rather than the annoyingly-named 
"size" type that the old implementation in redundant-string-cstr.cpp used and 
is the basis for using the new  header in four further checks to be 
submitted as separate changes.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144216/new/

https://reviews.llvm.org/D144216

Files:
  clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
  
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
@@ -1,71 +1,5 @@
-// RUN: %check_clang_tidy %s readability-redundant-string-cstr %t
-
-typedef unsigned __INT16_TYPE__ char16;
-typedef unsigned __INT32_TYPE__ char32;
-typedef __SIZE_TYPE__ size;
-
-namespace std {
-template 
-class allocator {};
-template 
-class char_traits {};
-template 
-struct basic_string {
-  typedef basic_string _Type;
-  basic_string();
-  basic_string(const C *p, const A &a = A());
-
-  ~basic_string();
-
-  const C *c_str() const;
-  const C *data() const;
-
-  _Type& append(const C *s);
-  _Type& append(const C *s, size n);
-  _Type& assign(const C *s);
-  _Type& assign(const C *s, size n);
-
-  int compare(const _Type&) const;
-  int compare(const C* s) const;
-  int compare(size pos, size len, const _Type&) const;
-  int compare(size pos, size len, const C* s) const;
-
-  size find(const _Type& str, size pos = 0) const;
-  size find(const C* s, size pos = 0) const;
-  size find(const C* s, size pos, size n) const;
-
-  _Type& insert(size pos, const _Type& str);
-  _Type& insert(size pos, const C* s);
-  _Type& insert(size pos, const C* s, size n);
-
-  _Type& operator+=(const _Type& str);
-  _Type& operator+=(const C* s);
-  _Type& operator=(const _Type& str);
-  _Type& operator=(const C* s);
-};
-
-typedef basic_string, std::allocator> string;
-typedef basic_string, std::allocator> wstring;
-typedef basic_string, std::allocator> u16string;
-typedef basic_string, std::allocator> u32string;
-
-template 
-struct basic_string_view {
-  basic_string_view(const C* s);
-};
-typedef basic_string_view> string_view;
-typedef basic_string_view> wstring_view;
-typedef basic_string_view> u16string_view;
-typedef basic_string_view> u32string_view;
-}
-
-std::string operator+(const std::string&, const std::string&);
-std::string operator+(const std::string&, const char*);
-std::string operator+(const char*, const std::string&);
-
-bool operator==(const std::string&, const std::string&);
-bool operator==(const std::string&, const char*);
-bool operator==(const char*, const std::string&);
+// RUN: %check_clang_tidy %s readability-redundant-string-cstr %t -- -- -isystem %clang_tidy_headers
+#include 
 
 namespace llvm {
 struct StringRef {
Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
@@ -0,0 +1,74 @@
+#ifndef _STRING_
+#define _STRING_
+
+// For size_t
+#include 
+
+typedef unsigned __INT16_TYPE__ char16;
+typedef unsigned __INT32_TYPE__ char32;
+
+namespace std {
+template 
+class allocator {};
+template 
+class char_traits {};
+template 
+struct basic_string {
+  typedef size_t size_type;
+  typedef basic_string _Type;
+  basic_string();
+  basic_string(const C *p, const A &a = A());
+
+  ~basic_string();
+
+  const C *c_str() const;
+  const C *data() const;
+
+  _Type& append(const C *s);
+  _Type& append(const C *s, size_type n);
+  _Type& assign(const C *s);
+  _Type& assign(const C *s, size_type n);
+
+  int compare(const _Type&) const;
+  int compare(const C* s) const;
+  int compare(size_type pos, size_type len, const _Type&) const;
+  int compare(size_type pos, size_type len, const C* s) const;
+
+  size_type find(const _Type& str, size_type pos = 0) const;
+  size_type find(const C* s, size_type pos = 0) const;
+  size_type find(const C* s, size_type pos, size_type n) const;
+
+  _Type& insert(size_type pos, const _Type& str);
+  _Type& insert(size_type pos, const C* s);
+  _Type& insert(size_type pos, const C* s, size_type n);
+
+  _Type& operator+=(const _Type& str);
+  _Type& operator+=(const C* s);
+  _Type& operator=(const _Type& str);
+  _Type& operator=(const C* s);
+};
+
+typedef basic_string, std::allocator> string;
+typedef basic_string, std::allocator> wstring;
+typedef basic_string, std::allocator> u16string;
+typedef basic_string, std::allocator> u32string;
+
+template 
+struct basic_string_view {
+  basic_string_view(const C* s);
+};
+typedef b

[PATCH] D145310: [clang-tidy] Make readability-container-data-pointer use header

2023-03-04 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
Herald added a subscriber: xazax.hun.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

This requires operator[] to be added to the std::basic_string
implementation.


https://reviews.llvm.org/D145310

Files:
  clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
  
clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
@@ -1,4 +1,5 @@
-// RUN: %check_clang_tidy %s readability-container-data-pointer %t -- -- 
-fno-delayed-template-parsing
+// RUN: %check_clang_tidy %s readability-container-data-pointer %t -- -- 
-isystem %clang_tidy_headers -fno-delayed-template-parsing
+#include 
 
 typedef __SIZE_TYPE__ size_t;
 
@@ -17,22 +18,6 @@
   const T &operator[](size_type) const;
 };
 
-template 
-struct basic_string {
-  using size_type = size_t;
-
-  basic_string();
-
-  T *data();
-  const T *data() const;
-
-  T &operator[](size_t);
-  const T &operator[](size_type) const;
-};
-
-typedef basic_string string;
-typedef basic_string wstring;
-
 template 
 struct is_integral;
 
Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
===
--- clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
+++ clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
@@ -42,6 +42,9 @@
   _Type& insert(size_type pos, const C* s);
   _Type& insert(size_type pos, const C* s, size_type n);
 
+  _Type& operator[](size_type);
+  const _Type& operator[](size_type) const;
+
   _Type& operator+=(const _Type& str);
   _Type& operator+=(const C* s);
   _Type& operator=(const _Type& str);


Index: clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
@@ -1,4 +1,5 @@
-// RUN: %check_clang_tidy %s readability-container-data-pointer %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy %s readability-container-data-pointer %t -- -- -isystem %clang_tidy_headers -fno-delayed-template-parsing
+#include 
 
 typedef __SIZE_TYPE__ size_t;
 
@@ -17,22 +18,6 @@
   const T &operator[](size_type) const;
 };
 
-template 
-struct basic_string {
-  using size_type = size_t;
-
-  basic_string();
-
-  T *data();
-  const T *data() const;
-
-  T &operator[](size_t);
-  const T &operator[](size_type) const;
-};
-
-typedef basic_string string;
-typedef basic_string wstring;
-
 template 
 struct is_integral;
 
Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
===
--- clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
+++ clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
@@ -42,6 +42,9 @@
   _Type& insert(size_type pos, const C* s);
   _Type& insert(size_type pos, const C* s, size_type n);
 
+  _Type& operator[](size_type);
+  const _Type& operator[](size_type) const;
+
   _Type& operator+=(const _Type& str);
   _Type& operator+=(const C* s);
   _Type& operator=(const _Type& str);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145311: Make abseil-redundant-strcat-calls checker use header

2023-03-04 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
mikecrowe added a reviewer: carlosgalvezp.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

It's unclear where the "string" in no namespace comes from in this
check. The inheritance from __gnu_cxx implies that it's supposed to be
from libstdc++ but having string outside namespace std hasn't been a
thing in libstdc++ for over twenty years!

The comment says: "Here we mimic the hierarchy of ::string. We need to
do so because we are matching on the fully qualified name of the
methods." However, this doesn't appear to be true since just using the
implementation in Inputs/Headers/string, which lacks any inheritance,
doesn't cause any of the tests to fail.

I don't use Abseil, and have no idea whether this change is appropriate,
but the check does still pass provided all uses of string are changed to
std::string!

Depends on D145310 


https://reviews.llvm.org/D145311

Files:
  clang-tools-extra/test/clang-tidy/checkers/abseil/redundant-strcat-calls.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/abseil/redundant-strcat-calls.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/abseil/redundant-strcat-calls.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/abseil/redundant-strcat-calls.cpp
@@ -1,92 +1,8 @@
-// RUN: %check_clang_tidy %s abseil-redundant-strcat-calls %t
+// RUN: %check_clang_tidy %s abseil-redundant-strcat-calls %t -- -- -isystem %clang_tidy_headers
+#include 
 
 int strlen(const char *);
 
-// Here we mimic the hierarchy of ::string.
-// We need to do so because we are matching on the fully qualified name of the
-// methods.
-struct __sso_string_base {};
-namespace __gnu_cxx {
-template 
-class __versa_string {
- public:
-  const char *c_str() const;
-  const char *data() const;
-  int size() const;
-  int capacity() const;
-  int length() const;
-  bool empty() const;
-  char &operator[](int);
-  void clear();
-  void resize(int);
-  int compare(const __versa_string &) const;
-};
-}  // namespace __gnu_cxx
-
-namespace std {
-template 
-class char_traits {};
-template 
-class allocator {};
-}  // namespace std
-
-template ,
-  typename C = std::allocator>
-class basic_string : public __gnu_cxx::__versa_string {
- public:
-  basic_string();
-  basic_string(const basic_string &);
-  basic_string(const char *, C = C());
-  basic_string(const char *, int, C = C());
-  basic_string(const basic_string &, int, int, C = C());
-  ~basic_string();
-
-  basic_string &operator+=(const basic_string &);
-};
-
-template 
-basic_string operator+(const basic_string &,
-const basic_string &);
-template 
-basic_string operator+(const basic_string &, const char *);
-
-typedef basic_string string;
-
-bool operator==(const string &, const string &);
-bool operator==(const string &, const char *);
-bool operator==(const char *, const string &);
-
-bool operator!=(const string &, const string &);
-bool operator<(const string &, const string &);
-bool operator>(const string &, const string &);
-bool operator<=(const string &, const string &);
-bool operator>=(const string &, const string &);
-
-namespace std {
-template ,
-  typename _Alloc = allocator<_CharT>>
-class basic_string;
-
-template 
-class basic_string {
- public:
-  basic_string();
-  basic_string(const basic_string &);
-  basic_string(const char *, const _Alloc & = _Alloc());
-  basic_string(const char *, int, const _Alloc & = _Alloc());
-  basic_string(const basic_string &, int, int, const _Alloc & = _Alloc());
-  ~basic_string();
-
-  basic_string &operator+=(const basic_string &);
-
-  unsigned size() const;
-  unsigned length() const;
-  bool empty() const;
-};
-
-typedef basic_string string;
-}  // namespace std
-
 namespace absl {
 
 class string_view {
@@ -95,12 +11,12 @@
 
   string_view();
   string_view(const char *);
-  string_view(const string &);
+  string_view(const std::string &);
   string_view(const char *, int);
   string_view(string_view, int);
 
   template 
-  explicit operator ::basic_string() const;
+  explicit operator std::basic_string() const;
 
   const char *data() const;
   int size() const;
@@ -113,7 +29,7 @@
   AlphaNum(int i);
   AlphaNum(double f);
   AlphaNum(const char *c_str);
-  AlphaNum(const string &str);
+  AlphaNum(const std::string &str);
   AlphaNum(const string_view &pc);
 
  private:
@@ -121,28 +37,28 @@
   AlphaNum &operator=(const AlphaNum &);
 };
 
-string StrCat();
-string StrCat(const AlphaNum &A);
-string StrCat(const AlphaNum &A, const AlphaNum &B);
-string StrCat(const AlphaNum &A, const AlphaNum &B, const AlphaNum &C);
-string StrCat(const AlphaNum &A, const AlphaNum &B, const AlphaNum &C,
-  const AlphaNum &D);
+std::string StrCat();
+std::string StrCat(const AlphaNum &A);
+std::string StrCat(const

[PATCH] D145312: [clang-tidy] Make readability-string-compare check use header

2023-03-04 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
mikecrowe added a reviewer: carlosgalvezp.
Herald added a subscriber: xazax.hun.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

Improve the generic  header by adding another constructor,
std::basic_string::empty and operator!= overload set so that it can be
used to replace the custom implementation in the
readability-string-compare check.


https://reviews.llvm.org/D145312

Files:
  clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
  clang-tools-extra/test/clang-tidy/checkers/readability/string-compare.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/readability/string-compare.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/string-compare.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/string-compare.cpp
@@ -1,25 +1,5 @@
-// RUN: %check_clang_tidy %s readability-string-compare %t
-
-namespace std {
-template 
-class allocator {};
-template 
-class char_traits {};
-template , typename A = 
std::allocator>
-class basic_string {
-public:
-  basic_string();
-  basic_string(const C *, unsigned int size);
-  int compare(const basic_string &str) const;
-  int compare(const C *) const;
-  int compare(int, int, const basic_string &str) const;
-  bool empty();
-};
-bool operator==(const basic_string &lhs, const basic_string &rhs);
-bool operator!=(const basic_string &lhs, const basic_string &rhs);
-bool operator==(const basic_string &lhs, const char *&rhs);
-typedef basic_string string;
-}
+// RUN: %check_clang_tidy %s readability-string-compare %t -- -- -isystem 
%clang_tidy_headers
+#include 
 
 void func(bool b);
 
Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
===
--- clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
+++ clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
@@ -18,12 +18,15 @@
   typedef basic_string _Type;
   basic_string();
   basic_string(const C *p, const A &a = A());
+  basic_string(const C *p, size_type count);
 
   ~basic_string();
 
   const C *c_str() const;
   const C *data() const;
 
+  bool empty() const;
+
   _Type& append(const C *s);
   _Type& append(const C *s, size_type n);
   _Type& assign(const C *s);
@@ -72,6 +75,10 @@
 bool operator==(const std::string&, const std::string&);
 bool operator==(const std::string&, const char*);
 bool operator==(const char*, const std::string&);
+
+bool operator!=(const std::string&, const std::string&);
+bool operator!=(const std::string&, const char*);
+bool operator!=(const char*, const std::string&);
 }
 
 #endif // _STRING_


Index: clang-tools-extra/test/clang-tidy/checkers/readability/string-compare.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/string-compare.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/string-compare.cpp
@@ -1,25 +1,5 @@
-// RUN: %check_clang_tidy %s readability-string-compare %t
-
-namespace std {
-template 
-class allocator {};
-template 
-class char_traits {};
-template , typename A = std::allocator>
-class basic_string {
-public:
-  basic_string();
-  basic_string(const C *, unsigned int size);
-  int compare(const basic_string &str) const;
-  int compare(const C *) const;
-  int compare(int, int, const basic_string &str) const;
-  bool empty();
-};
-bool operator==(const basic_string &lhs, const basic_string &rhs);
-bool operator!=(const basic_string &lhs, const basic_string &rhs);
-bool operator==(const basic_string &lhs, const char *&rhs);
-typedef basic_string string;
-}
+// RUN: %check_clang_tidy %s readability-string-compare %t -- -- -isystem %clang_tidy_headers
+#include 
 
 void func(bool b);
 
Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
===
--- clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
+++ clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
@@ -18,12 +18,15 @@
   typedef basic_string _Type;
   basic_string();
   basic_string(const C *p, const A &a = A());
+  basic_string(const C *p, size_type count);
 
   ~basic_string();
 
   const C *c_str() const;
   const C *data() const;
 
+  bool empty() const;
+
   _Type& append(const C *s);
   _Type& append(const C *s, size_type n);
   _Type& assign(const C *s);
@@ -72,6 +75,10 @@
 bool operator==(const std::string&, const std::string&);
 bool operator==(const std::string&, const char*);
 bool operator==(const char*, const std::string&);
+
+bool operator!=(const std::string&, const std::string&);
+bool operator!=(const std::string&, const char*);
+bool operator!=(const char*, const std::string&);
 }
 
 #endif // _STRING_
___

[PATCH] D145313: [clang-tidy] Make readability-container-size-empty check using header

2023-03-04 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
mikecrowe added a reviewer: carlosgalvezp.
Herald added a subscriber: xazax.hun.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

Improve the generic  header by adding the size() method so that
it can be used to replace the custom implementation in the
readability-container-size-empty check.

This requires fixing an incorrect comparison of a std::wstring with a
char string literal.

Unfortunately, removing the custom basic_string implementation means
fixing the line numbers for many of the checks.

Depends on D145312 


https://reviews.llvm.org/D145313

Files:
  clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
  
clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp
@@ -1,6 +1,7 @@
 // RUN: %check_clang_tidy %s readability-container-size-empty %t -- \
 // RUN: -config="{CheckOptions: [{key: readability-container-size-empty.ExcludedComparisonTypes , value: '::std::array;::IgnoredDummyType'}]}" \
-// RUN: -- -fno-delayed-template-parsing
+// RUN: -- -fno-delayed-template-parsing -isystem %clang_tidy_headers
+#include 
 
 namespace std {
 template  struct vector {
@@ -11,20 +12,6 @@
   bool empty() const;
 };
 
-template  struct basic_string {
-  basic_string();
-  bool operator==(const basic_string& other) const;
-  bool operator!=(const basic_string& other) const;
-  bool operator==(const char *) const;
-  bool operator!=(const char *) const;
-  basic_string operator+(const basic_string& other) const;
-  unsigned long size() const;
-  bool empty() const;
-};
-
-typedef basic_string string;
-typedef basic_string wstring;
-
 inline namespace __v2 {
 template  struct set {
   set();
@@ -125,12 +112,12 @@
 ;
   // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty]
   // CHECK-FIXES: {{^  }}if (intSet.empty()){{$}}
-  // CHECK-MESSAGES: :34:8: note: method 'set'::empty() defined here
+  // CHECK-MESSAGES: :21:8: note: method 'set'::empty() defined here
   if (intSet == std::set())
 ;
   // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness
   // CHECK-FIXES: {{^  }}if (intSet.empty()){{$}}
-  // CHECK-MESSAGES: :34:8: note: method 'set'::empty() defined here
+  // CHECK-MESSAGES: :21:8: note: method 'set'::empty() defined here
   if (s_func() == "")
 ;
   // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
@@ -155,7 +142,7 @@
 ;
   // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
   // CHECK-FIXES: {{^  }}if (wstr.empty()){{$}}
-  if (wstr == "")
+  if (wstr == L"")
 ;
   // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
   // CHECK-FIXES: {{^  }}if (wstr.empty()){{$}}
@@ -452,7 +439,7 @@
 public:
   ConstructWithBoolField(const std::vector &C) : B(C.size()) {}
 // CHECK-MESSAGES: :[[@LINE-1]]:57: warning: the 'empty' method should be used
-// CHECK-MESSAGES: :11:8: note: method 'vector'::empty() defined here
+// CHECK-MESSAGES: :12:8: note: method 'vector'::empty() defined here
 // CHECK-FIXES: {{^  }}ConstructWithBoolField(const std::vector &C) : B(!C.empty()) {}
 };
 
@@ -460,21 +447,21 @@
   std::vector C;
   bool B = C.size();
 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: the 'empty' method should be used
-// CHECK-MESSAGES: :11:8: note: method 'vector'::empty() defined here
+// CHECK-MESSAGES: :12:8: note: method 'vector'::empty() defined here
 // CHECK-FIXES: {{^  }}bool B = !C.empty();
 };
 
 int func(const std::vector &C) {
   return C.size() ? 0 : 1;
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be used
-// CHECK-MESSAGES: :11:8: note: method 'vector'::empty() defined here
+// CHECK-MESSAGES: :12:8: note: method 'vector'::empty() defined here
 // CHECK-FIXES: {{^  }}return !C.empty() ? 0 : 1;
 }
 
 constexpr Lazy L;
 static_assert(!L.size(), "");
 // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: the 'empty' method should be used
-// CHECK-MESSAGES: :103:18: note: method 'Lazy'::empty() defined here
+// CHECK-MESSAGES: :90:18: note: method 'Lazy'::empty() defined here
 // CHECK-FIXES: {{^}}static_assert(L.empty(), "");
 
 struct StructWithLazyNoexcept {
@@ -489,7 +476,7 @@
   if (v.size())
 ;
   // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty]
-  // CHECK-MESSAGES: :11:8: note: method 'vector'::emp

[PATCH] D144216: [clang-tidy] Extract string header from redundant-string-cstr checker

2023-03-04 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

The changes that extend the  header further and use it in a few more 
checks are:

- https://reviews.llvm.org/D145310
- https://reviews.llvm.org/D145311
- https://reviews.llvm.org/D145312
- https://reviews.llvm.org/D145313

and of course my original change:

- https://reviews.llvm.org/D143342


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144216/new/

https://reviews.llvm.org/D144216

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D144216: [clang-tidy] Extract string header from redundant-string-cstr checker

2023-03-05 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

> Sounds good, should we land this?

If you're happy to do so, then so am I.

> If you don't have commit rights, please let us know Github name and email for 
> attribution.

These are my first code contributions to LLVM, so I don't really know the 
process. I don't believe that I have commit rights. My GitHub username is 
"mikecrowe" and my email address is "m...@mcrowe.com".

Thanks!

Mike.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144216/new/

https://reviews.llvm.org/D144216

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D144216: [clang-tidy] Extract string header from redundant-string-cstr checker

2023-03-05 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

> The purpose of this header is to not include any standard header, and yet 
> this is done in line 5 so it kinda defeats the purpose.

I believe that this `` header is including 
`clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string.h` rather 
than the system `string.h` header. (That's why I'm including `string.h` to get 
`size_t` rather than the more obvious `stdlib.h`.) If we're going to have sets 
of "standard-but-not-standard" headers for these checks then it feels like it 
ought to be safe to use them.

I will double check that this is true once my current build is complete.

Mike.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144216/new/

https://reviews.llvm.org/D144216

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D144216: [clang-tidy] Extract string header from redundant-string-cstr checker

2023-03-05 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

> I will double check that this is true once my current build is complete.

Yes, it's true. I stuck a `#error` in 
`clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string.h` and I saw 
the expected error from a file including ``.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144216/new/

https://reviews.llvm.org/D144216

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D144216: [clang-tidy] Extract string header from redundant-string-cstr checker

2023-03-05 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

In D144216#4169772 , @carlosgalvezp 
wrote:

> In D144216#4169764 , @mikecrowe 
> wrote:
>
>>> I will double check that this is true once my current build is complete.
>>
>> Yes, it's true. I stuck a `#error` in 
>> `clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string.h` and I 
>> saw the expected error from a file including ``.
>
> Awesome, thanks for checking, I wasn't aware we already had `string.h`. Then 
> if we do have headers named the same as the standard headers, would it make 
> sense to name this header `cstring` instead of `string`?

I think you mean rename `string.h` to `cstring`. (`string` clearly has to be 
just `string` if it's the standard C++ `string` header.)

A bit of searching in the existing checks shows that `string.h` is included by 
C checks (`bugprone/signal-handler*.c`) and also by checks that deliberately 
want `string.h` so they can suggest switching to `cstring` 
(`modernize/deprecated-headers*`) so it looks like it's necessary to keep 
`string.h`. If you wish, a `cstring` wrapper that just includes `string.h` 
could be created, but it really ought to put everything in `namespace std` too. 
(If so, I think this would probably be better done as a separate change.)


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144216/new/

https://reviews.llvm.org/D144216

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145313: [clang-tidy] Make readability-container-size-empty check using header

2023-03-05 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

In D145313#4169790 , @carlosgalvezp 
wrote:

> Could you upload the patch with full context? I believe you need to do 
> something like `git show HEAD -U99` as per the guidelines 
> . Otherwise `arc diff` should do the 
> job automatically. Reason I ask is that I cannot see the new line numbers 
> referred to by the `note` comments - Phab says "Context not available".

Of course. It had been sufficiently long since I last uploaded a new diff that 
I forgot that part of the instructions and just used `git format-patch` for 
this batch. I shall try to learn how to use `arc diff` because the copying and 
pasting of diffs was getting rather tedious and I knew I was bound to make a 
mistake with it eventually.

Thanks!


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145313/new/

https://reviews.llvm.org/D145313

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145719: [clang-tidy] Make readability-container-data-pointer use header

2023-03-09 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
Herald added subscribers: PiotrZSL, xazax.hun.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

This requires operator[] to be added to the std::basic_string
implementation.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D145719

Files:
  clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
  
clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
@@ -1,4 +1,5 @@
-// RUN: %check_clang_tidy %s readability-container-data-pointer %t -- -- 
-fno-delayed-template-parsing
+// RUN: %check_clang_tidy %s readability-container-data-pointer %t -- -- 
-isystem %clang_tidy_headers -fno-delayed-template-parsing
+#include 
 
 typedef __SIZE_TYPE__ size_t;
 
@@ -17,22 +18,6 @@
   const T &operator[](size_type) const;
 };
 
-template 
-struct basic_string {
-  using size_type = size_t;
-
-  basic_string();
-
-  T *data();
-  const T *data() const;
-
-  T &operator[](size_t);
-  const T &operator[](size_type) const;
-};
-
-typedef basic_string string;
-typedef basic_string wstring;
-
 template 
 struct is_integral;
 
Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
===
--- clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
+++ clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
@@ -42,6 +42,9 @@
   _Type& insert(size_type pos, const C* s);
   _Type& insert(size_type pos, const C* s, size_type n);
 
+  _Type& operator[](size_type);
+  const _Type& operator[](size_type) const;
+
   _Type& operator+=(const _Type& str);
   _Type& operator+=(const C* s);
   _Type& operator=(const _Type& str);


Index: clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
@@ -1,4 +1,5 @@
-// RUN: %check_clang_tidy %s readability-container-data-pointer %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy %s readability-container-data-pointer %t -- -- -isystem %clang_tidy_headers -fno-delayed-template-parsing
+#include 
 
 typedef __SIZE_TYPE__ size_t;
 
@@ -17,22 +18,6 @@
   const T &operator[](size_type) const;
 };
 
-template 
-struct basic_string {
-  using size_type = size_t;
-
-  basic_string();
-
-  T *data();
-  const T *data() const;
-
-  T &operator[](size_t);
-  const T &operator[](size_type) const;
-};
-
-typedef basic_string string;
-typedef basic_string wstring;
-
 template 
 struct is_integral;
 
Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
===
--- clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
+++ clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
@@ -42,6 +42,9 @@
   _Type& insert(size_type pos, const C* s);
   _Type& insert(size_type pos, const C* s, size_type n);
 
+  _Type& operator[](size_type);
+  const _Type& operator[](size_type) const;
+
   _Type& operator+=(const _Type& str);
   _Type& operator+=(const C* s);
   _Type& operator=(const _Type& str);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145719: [clang-tidy] Make readability-container-data-pointer use header

2023-03-09 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe abandoned this revision.
mikecrowe added a comment.

Whoops. I accidentally uploaded https://reviews.llvm.org/D145719 as a new 
change. :(


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145719/new/

https://reviews.llvm.org/D145719

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145310: [clang-tidy] Make readability-container-data-pointer use header

2023-03-09 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 503882.
mikecrowe added a comment.
Herald added a subscriber: PiotrZSL.

Rebase on top of fb7ef637a84652dbd3d973a1ba7db9470181b5aa 
 (which is 
a
descendent of ae25e2f19decb94198301f0726ee613f945cc405 
 aka 
D144216 , on
which this change relies.)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145310/new/

https://reviews.llvm.org/D145310

Files:
  clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
  
clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
@@ -1,4 +1,5 @@
-// RUN: %check_clang_tidy %s readability-container-data-pointer %t -- -- 
-fno-delayed-template-parsing
+// RUN: %check_clang_tidy %s readability-container-data-pointer %t -- -- 
-isystem %clang_tidy_headers -fno-delayed-template-parsing
+#include 
 
 typedef __SIZE_TYPE__ size_t;
 
@@ -17,22 +18,6 @@
   const T &operator[](size_type) const;
 };
 
-template 
-struct basic_string {
-  using size_type = size_t;
-
-  basic_string();
-
-  T *data();
-  const T *data() const;
-
-  T &operator[](size_t);
-  const T &operator[](size_type) const;
-};
-
-typedef basic_string string;
-typedef basic_string wstring;
-
 template 
 struct is_integral;
 
Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
===
--- clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
+++ clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
@@ -42,6 +42,9 @@
   _Type& insert(size_type pos, const C* s);
   _Type& insert(size_type pos, const C* s, size_type n);
 
+  _Type& operator[](size_type);
+  const _Type& operator[](size_type) const;
+
   _Type& operator+=(const _Type& str);
   _Type& operator+=(const C* s);
   _Type& operator=(const _Type& str);


Index: clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/container-data-pointer.cpp
@@ -1,4 +1,5 @@
-// RUN: %check_clang_tidy %s readability-container-data-pointer %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy %s readability-container-data-pointer %t -- -- -isystem %clang_tidy_headers -fno-delayed-template-parsing
+#include 
 
 typedef __SIZE_TYPE__ size_t;
 
@@ -17,22 +18,6 @@
   const T &operator[](size_type) const;
 };
 
-template 
-struct basic_string {
-  using size_type = size_t;
-
-  basic_string();
-
-  T *data();
-  const T *data() const;
-
-  T &operator[](size_t);
-  const T &operator[](size_type) const;
-};
-
-typedef basic_string string;
-typedef basic_string wstring;
-
 template 
 struct is_integral;
 
Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
===
--- clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
+++ clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
@@ -42,6 +42,9 @@
   _Type& insert(size_type pos, const C* s);
   _Type& insert(size_type pos, const C* s, size_type n);
 
+  _Type& operator[](size_type);
+  const _Type& operator[](size_type) const;
+
   _Type& operator+=(const _Type& str);
   _Type& operator+=(const C* s);
   _Type& operator=(const _Type& str);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145311: [clang-tidy] Make abseil-redundant-strcat-calls checker use header

2023-03-09 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 503884.
mikecrowe added a comment.
Herald added a subscriber: PiotrZSL.

Re-upload using arc.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145311/new/

https://reviews.llvm.org/D145311

Files:
  clang-tools-extra/test/clang-tidy/checkers/abseil/redundant-strcat-calls.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/abseil/redundant-strcat-calls.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/abseil/redundant-strcat-calls.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/abseil/redundant-strcat-calls.cpp
@@ -1,92 +1,8 @@
-// RUN: %check_clang_tidy %s abseil-redundant-strcat-calls %t
+// RUN: %check_clang_tidy %s abseil-redundant-strcat-calls %t -- -- -isystem %clang_tidy_headers
+#include 
 
 int strlen(const char *);
 
-// Here we mimic the hierarchy of ::string.
-// We need to do so because we are matching on the fully qualified name of the
-// methods.
-struct __sso_string_base {};
-namespace __gnu_cxx {
-template 
-class __versa_string {
- public:
-  const char *c_str() const;
-  const char *data() const;
-  int size() const;
-  int capacity() const;
-  int length() const;
-  bool empty() const;
-  char &operator[](int);
-  void clear();
-  void resize(int);
-  int compare(const __versa_string &) const;
-};
-}  // namespace __gnu_cxx
-
-namespace std {
-template 
-class char_traits {};
-template 
-class allocator {};
-}  // namespace std
-
-template ,
-  typename C = std::allocator>
-class basic_string : public __gnu_cxx::__versa_string {
- public:
-  basic_string();
-  basic_string(const basic_string &);
-  basic_string(const char *, C = C());
-  basic_string(const char *, int, C = C());
-  basic_string(const basic_string &, int, int, C = C());
-  ~basic_string();
-
-  basic_string &operator+=(const basic_string &);
-};
-
-template 
-basic_string operator+(const basic_string &,
-const basic_string &);
-template 
-basic_string operator+(const basic_string &, const char *);
-
-typedef basic_string string;
-
-bool operator==(const string &, const string &);
-bool operator==(const string &, const char *);
-bool operator==(const char *, const string &);
-
-bool operator!=(const string &, const string &);
-bool operator<(const string &, const string &);
-bool operator>(const string &, const string &);
-bool operator<=(const string &, const string &);
-bool operator>=(const string &, const string &);
-
-namespace std {
-template ,
-  typename _Alloc = allocator<_CharT>>
-class basic_string;
-
-template 
-class basic_string {
- public:
-  basic_string();
-  basic_string(const basic_string &);
-  basic_string(const char *, const _Alloc & = _Alloc());
-  basic_string(const char *, int, const _Alloc & = _Alloc());
-  basic_string(const basic_string &, int, int, const _Alloc & = _Alloc());
-  ~basic_string();
-
-  basic_string &operator+=(const basic_string &);
-
-  unsigned size() const;
-  unsigned length() const;
-  bool empty() const;
-};
-
-typedef basic_string string;
-}  // namespace std
-
 namespace absl {
 
 class string_view {
@@ -95,12 +11,12 @@
 
   string_view();
   string_view(const char *);
-  string_view(const string &);
+  string_view(const std::string &);
   string_view(const char *, int);
   string_view(string_view, int);
 
   template 
-  explicit operator ::basic_string() const;
+  explicit operator std::basic_string() const;
 
   const char *data() const;
   int size() const;
@@ -113,7 +29,7 @@
   AlphaNum(int i);
   AlphaNum(double f);
   AlphaNum(const char *c_str);
-  AlphaNum(const string &str);
+  AlphaNum(const std::string &str);
   AlphaNum(const string_view &pc);
 
  private:
@@ -121,28 +37,28 @@
   AlphaNum &operator=(const AlphaNum &);
 };
 
-string StrCat();
-string StrCat(const AlphaNum &A);
-string StrCat(const AlphaNum &A, const AlphaNum &B);
-string StrCat(const AlphaNum &A, const AlphaNum &B, const AlphaNum &C);
-string StrCat(const AlphaNum &A, const AlphaNum &B, const AlphaNum &C,
-  const AlphaNum &D);
+std::string StrCat();
+std::string StrCat(const AlphaNum &A);
+std::string StrCat(const AlphaNum &A, const AlphaNum &B);
+std::string StrCat(const AlphaNum &A, const AlphaNum &B, const AlphaNum &C);
+std::string StrCat(const AlphaNum &A, const AlphaNum &B, const AlphaNum &C,
+   const AlphaNum &D);
 
 // Support 5 or more arguments
 template 
-string StrCat(const AlphaNum &A, const AlphaNum &B, const AlphaNum &C,
+std::string StrCat(const AlphaNum &A, const AlphaNum &B, const AlphaNum &C,
   const AlphaNum &D, const AlphaNum &E, const AV &... args);
 
-void StrAppend(string *Dest, const AlphaNum &A);
-void StrAppend(string *Dest, const AlphaNum &A, const AlphaNum &B);
-void StrAppend(string *Dest, const AlphaNum &A, const AlphaNum &B,
-   const AlphaNum &C);
-void StrAppend(string *Dest, const AlphaNum &A, const

[PATCH] D145724: [clang-tidy] Provide default template arguments in

2023-03-09 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
mikecrowe added a reviewer: carlosgalvezp.
Herald added subscribers: PiotrZSL, xazax.hun.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

Simplify the use of the basic_string and basic_string_view types by
providing default template arguments.

Depends on D145311 


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D145724

Files:
  clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string


Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
===
--- clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
+++ clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
@@ -12,7 +12,7 @@
 class allocator {};
 template 
 class char_traits {};
-template 
+template , typename A = allocator>
 struct basic_string {
   typedef size_t size_type;
   typedef basic_string _Type;
@@ -54,19 +54,19 @@
   _Type& operator=(const C* s);
 };
 
-typedef basic_string, std::allocator> 
string;
-typedef basic_string, 
std::allocator> wstring;
-typedef basic_string, std::allocator> 
u16string;
-typedef basic_string, std::allocator> 
u32string;
+typedef basic_string string;
+typedef basic_string wstring;
+typedef basic_string u16string;
+typedef basic_string u32string;
 
-template 
+template >
 struct basic_string_view {
   basic_string_view(const C* s);
 };
-typedef basic_string_view> string_view;
-typedef basic_string_view> wstring_view;
-typedef basic_string_view> u16string_view;
-typedef basic_string_view> u32string_view;
+typedef basic_string_view string_view;
+typedef basic_string_view wstring_view;
+typedef basic_string_view u16string_view;
+typedef basic_string_view u32string_view;
 
 std::string operator+(const std::string&, const std::string&);
 std::string operator+(const std::string&, const char*);


Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
===
--- clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
+++ clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
@@ -12,7 +12,7 @@
 class allocator {};
 template 
 class char_traits {};
-template 
+template , typename A = allocator>
 struct basic_string {
   typedef size_t size_type;
   typedef basic_string _Type;
@@ -54,19 +54,19 @@
   _Type& operator=(const C* s);
 };
 
-typedef basic_string, std::allocator> string;
-typedef basic_string, std::allocator> wstring;
-typedef basic_string, std::allocator> u16string;
-typedef basic_string, std::allocator> u32string;
+typedef basic_string string;
+typedef basic_string wstring;
+typedef basic_string u16string;
+typedef basic_string u32string;
 
-template 
+template >
 struct basic_string_view {
   basic_string_view(const C* s);
 };
-typedef basic_string_view> string_view;
-typedef basic_string_view> wstring_view;
-typedef basic_string_view> u16string_view;
-typedef basic_string_view> u32string_view;
+typedef basic_string_view string_view;
+typedef basic_string_view wstring_view;
+typedef basic_string_view u16string_view;
+typedef basic_string_view u32string_view;
 
 std::string operator+(const std::string&, const std::string&);
 std::string operator+(const std::string&, const char*);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145312: [clang-tidy] Make readability-string-compare check use header

2023-03-09 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe marked an inline comment as done.
mikecrowe added inline comments.
Herald added a subscriber: PiotrZSL.



Comment at: 
clang-tools-extra/test/clang-tidy/checkers/readability/string-compare.cpp:4-8
-template 
-class allocator {};
-template 
-class char_traits {};
-template , typename A = 
std::allocator>

carlosgalvezp wrote:
> Would it make sense to add these to the new header?
Done in https://reviews.llvm.org/D145724 .


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145312/new/

https://reviews.llvm.org/D145312

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145313: [clang-tidy] Make readability-container-size-empty check using header

2023-03-09 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 503896.
mikecrowe added a comment.
Herald added a subscriber: PiotrZSL.

Upload using arc diff so more context is available.

Now a descendent of D145724 .


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145313/new/

https://reviews.llvm.org/D145313

Files:
  clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
  
clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp
@@ -1,6 +1,7 @@
 // RUN: %check_clang_tidy %s readability-container-size-empty %t -- \
 // RUN: -config="{CheckOptions: [{key: readability-container-size-empty.ExcludedComparisonTypes , value: '::std::array;::IgnoredDummyType'}]}" \
-// RUN: -- -fno-delayed-template-parsing
+// RUN: -- -fno-delayed-template-parsing -isystem %clang_tidy_headers
+#include 
 
 namespace std {
 template  struct vector {
@@ -11,20 +12,6 @@
   bool empty() const;
 };
 
-template  struct basic_string {
-  basic_string();
-  bool operator==(const basic_string& other) const;
-  bool operator!=(const basic_string& other) const;
-  bool operator==(const char *) const;
-  bool operator!=(const char *) const;
-  basic_string operator+(const basic_string& other) const;
-  unsigned long size() const;
-  bool empty() const;
-};
-
-typedef basic_string string;
-typedef basic_string wstring;
-
 inline namespace __v2 {
 template  struct set {
   set();
@@ -125,12 +112,12 @@
 ;
   // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty]
   // CHECK-FIXES: {{^  }}if (intSet.empty()){{$}}
-  // CHECK-MESSAGES: :34:8: note: method 'set'::empty() defined here
+  // CHECK-MESSAGES: :21:8: note: method 'set'::empty() defined here
   if (intSet == std::set())
 ;
   // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness
   // CHECK-FIXES: {{^  }}if (intSet.empty()){{$}}
-  // CHECK-MESSAGES: :34:8: note: method 'set'::empty() defined here
+  // CHECK-MESSAGES: :21:8: note: method 'set'::empty() defined here
   if (s_func() == "")
 ;
   // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
@@ -155,7 +142,7 @@
 ;
   // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
   // CHECK-FIXES: {{^  }}if (wstr.empty()){{$}}
-  if (wstr == "")
+  if (wstr == L"")
 ;
   // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
   // CHECK-FIXES: {{^  }}if (wstr.empty()){{$}}
@@ -452,7 +439,7 @@
 public:
   ConstructWithBoolField(const std::vector &C) : B(C.size()) {}
 // CHECK-MESSAGES: :[[@LINE-1]]:57: warning: the 'empty' method should be used
-// CHECK-MESSAGES: :11:8: note: method 'vector'::empty() defined here
+// CHECK-MESSAGES: :12:8: note: method 'vector'::empty() defined here
 // CHECK-FIXES: {{^  }}ConstructWithBoolField(const std::vector &C) : B(!C.empty()) {}
 };
 
@@ -460,21 +447,21 @@
   std::vector C;
   bool B = C.size();
 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: the 'empty' method should be used
-// CHECK-MESSAGES: :11:8: note: method 'vector'::empty() defined here
+// CHECK-MESSAGES: :12:8: note: method 'vector'::empty() defined here
 // CHECK-FIXES: {{^  }}bool B = !C.empty();
 };
 
 int func(const std::vector &C) {
   return C.size() ? 0 : 1;
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be used
-// CHECK-MESSAGES: :11:8: note: method 'vector'::empty() defined here
+// CHECK-MESSAGES: :12:8: note: method 'vector'::empty() defined here
 // CHECK-FIXES: {{^  }}return !C.empty() ? 0 : 1;
 }
 
 constexpr Lazy L;
 static_assert(!L.size(), "");
 // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: the 'empty' method should be used
-// CHECK-MESSAGES: :103:18: note: method 'Lazy'::empty() defined here
+// CHECK-MESSAGES: :90:18: note: method 'Lazy'::empty() defined here
 // CHECK-FIXES: {{^}}static_assert(L.empty(), "");
 
 struct StructWithLazyNoexcept {
@@ -489,7 +476,7 @@
   if (v.size())
 ;
   // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty]
-  // CHECK-MESSAGES: :11:8: note: method 'vector'::empty() defined here
+  // CHECK-MESSAGES: :12:8: note: method 'vector'::empty() defined here
   // CHECK-FIXES: {{^  }}if (!v.empty()){{$}}
   if (v == std::vector())
 ;
@@ -498,24 +485,24 @@
   // CHECK-FIXES-NEXT: ;
   CHECKSIZE(v);
   // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: the 'empty' method should be used
-  // CHECK-MESSAGES: :11:8: note: method 've

[PATCH] D145313: [clang-tidy] Make readability-container-size-empty check using header

2023-03-09 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

In D145313#4182637 , @mikecrowe wrote:

> Now a descendent of D145724 .

Oh. The commit message update didn't make it through. :( Never mind, this 
doesn't really depend on D145724  since that 
change modified a different part of ``.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145313/new/

https://reviews.llvm.org/D145313

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145730: [clang-tidy] readability-redundant-string-cstr for smart pointer #576705

2023-03-09 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
mikecrowe added a reviewer: njames93.
Herald added subscribers: PiotrZSL, carlosgalvezp, xazax.hun.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

The readability-redundant-string-cstr check incorrectly replaces calls
to c_str() that involve an overloaded operator->.

Running `clang-tidy --checks="-*,readability-redundant-string-cstr"` on:

#include 
 #include 

void it(std::vector::const_iterator i)
 {

  std::string tmp;
  tmp = i->c_str();

}

yields:

/home/mac/git/llvm-project/build/../bug.cpp:7:9: warning: redundant call to 
'c_str' [readability-redundant-string-cstr]

  tmp = i->c_str();
^~
*i->

which means that the code is "fixed" to incorrectly say:

  tmp = *i->;

rather than the expected:

  tmp = *i;

This appears to be due to the overloaded `operator->` meaning that
RedundantStringCStrCheck.cpp#L53 ends up with Text containing "i->"
rather than just the expected "i".

Add test case for this and fix it in a somewhat nasty manner in the
absence of something better.

Fixes: https://github.com/llvm/llvm-project/issues/56705


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D145730

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
@@ -1,6 +1,11 @@
 // RUN: %check_clang_tidy %s readability-redundant-string-cstr %t -- -- 
-isystem %clang_tidy_headers
 #include 
 
+template 
+struct iterator {
+  T *operator->();
+};
+
 namespace llvm {
 struct StringRef {
   StringRef(const char *p);
@@ -202,6 +207,15 @@
   m1p2(s.c_str());  
 }
 
+// Test for iterator
+void it(iterator i)
+{
+  std::string tmp;
+  tmp = i->c_str();
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' 
[readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}tmp = *i;{{$}}
+}
+
 namespace PR45286 {
 struct Foo {
   void func(const std::string &) {}
Index: clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
@@ -52,6 +52,10 @@
 
   if (Text.empty())
 return std::string();
+
+  // https://github.com/llvm/llvm-project/issues/56705
+  Text.consume_back("->");
+
   // Add leading '*'.
   if (needParensAfterUnaryOperator(ExprNode)) {
 return (llvm::Twine("*(") + Text + ")").str();


Index: clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
@@ -1,6 +1,11 @@
 // RUN: %check_clang_tidy %s readability-redundant-string-cstr %t -- -- -isystem %clang_tidy_headers
 #include 
 
+template 
+struct iterator {
+  T *operator->();
+};
+
 namespace llvm {
 struct StringRef {
   StringRef(const char *p);
@@ -202,6 +207,15 @@
   m1p2(s.c_str());  
 }
 
+// Test for iterator
+void it(iterator i)
+{
+  std::string tmp;
+  tmp = i->c_str();
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}tmp = *i;{{$}}
+}
+
 namespace PR45286 {
 struct Foo {
   void func(const std::string &) {}
Index: clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
@@ -52,6 +52,10 @@
 
   if (Text.empty())
 return std::string();
+
+  // https://github.com/llvm/llvm-project/issues/56705
+  Text.consume_back("->");
+
   // Add leading '*'.
   if (needParensAfterUnaryOperator(ExprNode)) {
 return (llvm::Twine("*(") + Text + ")").str();
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145730: [clang-tidy] readability-redundant-string-cstr for smart pointer #576705

2023-03-10 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

In D145730#4182949 , @PiotrZSL wrote:

> Also consider reducing commit message, instead just copying issue description.
> Simple description about issue would be sufficient.

TBH, I wasn't expecting this change to be accepted. I was merely hoping that it 
would cause someone to give me a hint as to how to fix it properly. That's why 
I included so much information in the commit message. I will shorten the commit 
message.

> No functional issues, so LGTM.

Thanks for the review.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145730/new/

https://reviews.llvm.org/D145730

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145730: [clang-tidy] readability-redundant-string-cstr for smart pointer #576705

2023-03-10 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 504108.
mikecrowe marked an inline comment as done.
mikecrowe added a comment.

Fix comment in code as suggested by PiotrZSL. Improve lit check tests.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145730/new/

https://reviews.llvm.org/D145730

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
@@ -1,6 +1,12 @@
 // RUN: %check_clang_tidy %s readability-redundant-string-cstr %t -- -- 
-isystem %clang_tidy_headers
 #include 
 
+template 
+struct iterator {
+  T *operator->();
+  T &operator*();
+};
+
 namespace llvm {
 struct StringRef {
   StringRef(const char *p);
@@ -202,6 +208,31 @@
   m1p2(s.c_str());  
 }
 
+// Test for overloaded operator->
+void it(iterator i)
+{
+  std::string tmp;
+  tmp = i->c_str();
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' 
[readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}tmp = *i;{{$}}
+
+  // An unlikely situation and the outcome is not ideal, but at least the fix 
doesn't generate broken code.
+  tmp = i.operator->()->c_str();
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' 
[readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}tmp = *i.operator->();{{$}}
+
+  // The fix contains an unnecessary set of parentheses, but these have no 
effect.
+  iterator *pi = &i;
+  tmp = (*pi)->c_str();
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' 
[readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}tmp = *(*pi);{{$}}
+
+  // An unlikely situation, but at least the fix doesn't generate broken code.
+  tmp = pi->operator->()->c_str();
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' 
[readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}tmp = *pi->operator->();{{$}}
+}
+
 namespace PR45286 {
 struct Foo {
   void func(const std::string &) {}
Index: clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
@@ -52,6 +52,10 @@
 
   if (Text.empty())
 return std::string();
+
+  // Remove remaining '->' from overloaded operator call
+  Text.consume_back("->");
+
   // Add leading '*'.
   if (needParensAfterUnaryOperator(ExprNode)) {
 return (llvm::Twine("*(") + Text + ")").str();


Index: clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
@@ -1,6 +1,12 @@
 // RUN: %check_clang_tidy %s readability-redundant-string-cstr %t -- -- -isystem %clang_tidy_headers
 #include 
 
+template 
+struct iterator {
+  T *operator->();
+  T &operator*();
+};
+
 namespace llvm {
 struct StringRef {
   StringRef(const char *p);
@@ -202,6 +208,31 @@
   m1p2(s.c_str());  
 }
 
+// Test for overloaded operator->
+void it(iterator i)
+{
+  std::string tmp;
+  tmp = i->c_str();
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}tmp = *i;{{$}}
+
+  // An unlikely situation and the outcome is not ideal, but at least the fix doesn't generate broken code.
+  tmp = i.operator->()->c_str();
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}tmp = *i.operator->();{{$}}
+
+  // The fix contains an unnecessary set of parentheses, but these have no effect.
+  iterator *pi = &i;
+  tmp = (*pi)->c_str();
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}tmp = *(*pi);{{$}}
+
+  // An unlikely situation, but at least the fix doesn't generate broken code.
+  tmp = pi->operator->()->c_str();
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}tmp = *pi->operator->();{{$}}
+}
+
 namespace PR45286 {
 struct Foo {
   void func(const std::string &) {}
Index: clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantStringCS

[PATCH] D145730: [PATCH] [clang-tidy] Fix readability-redundant-string-cstr for smart pointer #576705

2023-03-10 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

Thanks for the speedy re-review. I don't have commit permission, so please can 
you land this if you are happy to do so?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145730/new/

https://reviews.llvm.org/D145730

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145730: [clang-tidy] Fix readability-redundant-string-cstr for smart pointer #576705

2023-03-10 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

Thanks, and sorry about the erroneous `[PATCH]` in the summary. :(


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145730/new/

https://reviews.llvm.org/D145730

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145311: [clang-tidy] Make abseil-redundant-strcat-calls checker use header

2023-03-11 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

In D145311#4184159 , @PiotrZSL wrote:

> It's fine, absl::StrCat returns std::string.
> So those changes are correct.

Thanks. Would you like me to remove the unnecessary noise from the commit 
message then, or will you do that as part of landing it?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145311/new/

https://reviews.llvm.org/D145311

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-03-11 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp:189
+  getLangOpts().CPlusPlus2b
+  ? hasAnyName("::std::print", "::std::format")
+  : hasName("::std::format"))),

PiotrZSL wrote:
> Please introduce configuration option to specify custom functions.
> For example if some project (like mine) is wrapping fmt::format with some 
> variadic template function, then such function could be specified.
> Same goes to things like some loggers.
> 
> Check utils/OptionsUtils.h for configuration, and  utils/Matchers.h 
> (matchesAnyListedName)
> Please introduce configuration option to specify custom functions.
> For example if some project (like mine) is wrapping fmt::format with some 
> variadic template function, then such function could be specified.

That's exactly where this change originated (as part of [[ 
https://github.com/mikecrowe/clang-tidy-fmt | my clang-tidy fmt fork ]], which 
I hope to submit for review soon once I've made it configurable too and 
improved the test cases.)

> Same goes to things like some loggers.
> 
> Check utils/OptionsUtils.h for configuration, and  utils/Matchers.h 
> (matchesAnyListedName)

Thanks for the pointer. I shall study those files for how to support this.

Do you think that the change can land like in its current state first? Or would 
you prefer that the configuration option is added at the same time?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D143342/new/

https://reviews.llvm.org/D143342

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-03-11 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

In D143342#4186809 , @PiotrZSL wrote:

> Code is fine, probably If would would write this, then I would bother to 
> split into C++20 and C++2B simply because `std::print` wouldn't compile if it 
> wouldn't be available. So I would just use hasAnyName.
> But code looks fine, configuration could be added later...

Thanks. I originally wrote it like that, but @njames93 requested that I checked 
the version, so I did. :) It doesn't do any harm and might avoid confusion.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D143342/new/

https://reviews.llvm.org/D143342

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-03-11 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp:189
+  getLangOpts().CPlusPlus2b
+  ? hasAnyName("::std::print", "::std::format")
+  : hasName("::std::format"))),

mikecrowe wrote:
> PiotrZSL wrote:
> > Please introduce configuration option to specify custom functions.
> > For example if some project (like mine) is wrapping fmt::format with some 
> > variadic template function, then such function could be specified.
> > Same goes to things like some loggers.
> > 
> > Check utils/OptionsUtils.h for configuration, and  utils/Matchers.h 
> > (matchesAnyListedName)
> > Please introduce configuration option to specify custom functions.
> > For example if some project (like mine) is wrapping fmt::format with some 
> > variadic template function, then such function could be specified.
> 
> That's exactly where this change originated (as part of [[ 
> https://github.com/mikecrowe/clang-tidy-fmt | my clang-tidy fmt fork ]], 
> which I hope to submit for review soon once I've made it configurable too and 
> improved the test cases.)
> 
> > Same goes to things like some loggers.
> > 
> > Check utils/OptionsUtils.h for configuration, and  utils/Matchers.h 
> > (matchesAnyListedName)
> 
> Thanks for the pointer. I shall study those files for how to support this.
> 
> Do you think that the change can land like in its current state first? Or 
> would you prefer that the configuration option is added at the same time?
> Please introduce configuration option to specify custom functions.
> For example if some project (like mine) is wrapping fmt::format with some 
> variadic template function, then such function could be specified.

I could add some sort of `readability-redundant-string-cstr.PrintFunction` 
option or `readability-redundant-string-cstr.FormatFunction` option, but 
reducing this to its fundamental behaviour would be "a function that takes 
`const char *` arguments that is also willing to take `std::string` arguments". 
I'm struggling to find a sensible name for such an option. Maybe 
`readability-redundant-string-cstr.StdStringAcceptingFunction=::fmt::format`? 
Or just `readability-redundant-string-cstr.FunctionCall=::fmt::format`?

> Same goes to things like some loggers.

Loggers may be classes, so there would need to be an option that specifies a 
class name (or even a base class name) and a method name (which may be an 
operator.) See [[ 
https://github.com/mikecrowe/clang-tidy-fmt/blob/7ace8a3ff41e9679104fe558835b0ef3cb33d969/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp#L196
 | this hard-coded example ]] (If it's not obvious, there's a description in 
the [[ 
https://github.com/mikecrowe/clang-tidy-fmt/blob/7ace8a3ff41e9679104fe558835b0ef3cb33d969/README.md?plain=1#L103
 | README ]]. In such cases the options could be 
`readability-redundant-string-cstr.Class=::BaseTrace` and 
`readability-redundant-string-cstr.Method=Log` or 
`readability-redundant-string-cstr.Operator=()`, but then it would be hard to 
tie together the right classes and methods. That could be avoided with 
something like 
`readability-redundant-string-cstr.MemberFunctionCall=::BaseTrace::operator(),::NullTrace::operator()`
 and some parsing I suppose.

Regardless, I'll try and get the simple case working and await suggestions for 
appropriate option names.

Thanks again for the suggestions.



CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D143342/new/

https://reviews.llvm.org/D143342

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-03-12 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp:189
+  getLangOpts().CPlusPlus2b
+  ? hasAnyName("::std::print", "::std::format")
+  : hasName("::std::format"))),

PiotrZSL wrote:
> mikecrowe wrote:
> > mikecrowe wrote:
> > > PiotrZSL wrote:
> > > > Please introduce configuration option to specify custom functions.
> > > > For example if some project (like mine) is wrapping fmt::format with 
> > > > some variadic template function, then such function could be specified.
> > > > Same goes to things like some loggers.
> > > > 
> > > > Check utils/OptionsUtils.h for configuration, and  utils/Matchers.h 
> > > > (matchesAnyListedName)
> > > > Please introduce configuration option to specify custom functions.
> > > > For example if some project (like mine) is wrapping fmt::format with 
> > > > some variadic template function, then such function could be specified.
> > > 
> > > That's exactly where this change originated (as part of [[ 
> > > https://github.com/mikecrowe/clang-tidy-fmt | my clang-tidy fmt fork ]], 
> > > which I hope to submit for review soon once I've made it configurable too 
> > > and improved the test cases.)
> > > 
> > > > Same goes to things like some loggers.
> > > > 
> > > > Check utils/OptionsUtils.h for configuration, and  utils/Matchers.h 
> > > > (matchesAnyListedName)
> > > 
> > > Thanks for the pointer. I shall study those files for how to support this.
> > > 
> > > Do you think that the change can land like in its current state first? Or 
> > > would you prefer that the configuration option is added at the same time?
> > > Please introduce configuration option to specify custom functions.
> > > For example if some project (like mine) is wrapping fmt::format with some 
> > > variadic template function, then such function could be specified.
> > 
> > I could add some sort of `readability-redundant-string-cstr.PrintFunction` 
> > option or `readability-redundant-string-cstr.FormatFunction` option, but 
> > reducing this to its fundamental behaviour would be "a function that takes 
> > `const char *` arguments that is also willing to take `std::string` 
> > arguments". I'm struggling to find a sensible name for such an option. 
> > Maybe 
> > `readability-redundant-string-cstr.StdStringAcceptingFunction=::fmt::format`?
> >  Or just `readability-redundant-string-cstr.FunctionCall=::fmt::format`?
> > 
> > > Same goes to things like some loggers.
> > 
> > Loggers may be classes, so there would need to be an option that specifies 
> > a class name (or even a base class name) and a method name (which may be an 
> > operator.) See [[ 
> > https://github.com/mikecrowe/clang-tidy-fmt/blob/7ace8a3ff41e9679104fe558835b0ef3cb33d969/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp#L196
> >  | this hard-coded example ]] (If it's not obvious, there's a description 
> > in the [[ 
> > https://github.com/mikecrowe/clang-tidy-fmt/blob/7ace8a3ff41e9679104fe558835b0ef3cb33d969/README.md?plain=1#L103
> >  | README ]]. In such cases the options could be 
> > `readability-redundant-string-cstr.Class=::BaseTrace` and 
> > `readability-redundant-string-cstr.Method=Log` or 
> > `readability-redundant-string-cstr.Operator=()`, but then it would be hard 
> > to tie together the right classes and methods. That could be avoided with 
> > something like 
> > `readability-redundant-string-cstr.MemberFunctionCall=::BaseTrace::operator(),::NullTrace::operator()`
> >  and some parsing I suppose.
> > 
> > Regardless, I'll try and get the simple case working and await suggestions 
> > for appropriate option names.
> > 
> > Thanks again for the suggestions.
> > 
> I asked AI, and it suggested 
> readability-redundant-string-cstr.FormattingFunctionsList.
> Also, I thing that matchesAnyListedName should support things like 
> '::NullTrace::operator()', so one option should be sufficient.
> 
> FormattingFunctionsList:
> A semicolon-separated list of (fully qualified) function/method/operator 
> names, with the requirement that 
> any parameter capable of accepting a 'const char*' input should also be able 
> to accept 'std::string' or 
> 'std::string_view' inputs, or proper overload candidates that can do so 
> should exist.
Far be it from me to question the wisdom of the AI :) , but my point was that 
the check works for any function that accepts `const char *` parameters that 
could equally well be `std::string` parameters. It's not limitted to formatting 
functions. Despite this, I suspect that if the majority use case is formatting 
functions then maybe it's more helpful to use a name connected with that for 
discoverability.

In my prototype (which is proving easier to implement than I expected so far), 
I've used `readability-redundant-string-cstr.StringParameterFunctions`, which I 
can't say I'm entirely 

[PATCH] D145885: [clang-tidy] Support readability-redundant-string-cstr.StringParameterFunctions option

2023-03-12 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
mikecrowe added reviewers: PiotrZSL, carlosgalvezp.
Herald added a subscriber: xazax.hun.
Herald added a reviewer: njames93.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

Many libraries and code bases have functions that work like std::format
and std::print and it would be useful for the
readability-redundant-string-cstr check to work with these functions to
remove unnecessary calls to c_str() among their arguments.

The StringParameterFunctions option contains a semicolon-separated list
of function names for which any arguments which are the result of
calling std::string::c_str() or std::string::data() should be changed to
pass the object directly.

For example, when using the {fmt}[1] library, this option can be used to
change arguments to fmt::format and fmt::print.

Depends on D143342 


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D145885

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
  clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/readability/redundant-string-cstr.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-function.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-function.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-function.cpp
@@ -0,0 +1,124 @@
+// RUN: %check_clang_tidy %s readability-redundant-string-cstr %t -- \
+// RUN:   -config="{CheckOptions: \
+// RUN: [{key: readability-redundant-string-cstr.StringParameterFunctions, \
+// RUN:   value: '::fmt::format; ::fmt::print; ::BaseLogger::operator(); ::BaseLogger::Log'}] \
+// RUN: }" \
+// RUN:   -- -isystem %clang_tidy_headers
+#include 
+
+namespace fmt {
+  inline namespace v8 {
+template
+void print(const char *, Args &&...);
+template
+std::string format(const char *, Args &&...);
+  }
+}
+
+namespace notfmt {
+  inline namespace v8 {
+template
+void print(const char *, Args &&...);
+template
+std::string format(const char *, Args &&...);
+  }
+}
+
+void fmt_print(const std::string &s1, const std::string &s2, const std::string &s3) {
+  fmt::print("One:{}\n", s1.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}fmt::print("One:{}\n", s1);
+
+  fmt::print("One:{} Two:{} Three:{}\n", s1.c_str(), s2, s3.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-2]]:58: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}fmt::print("One:{} Two:{} Three:{}\n", s1, s2, s3);
+}
+
+// There's no c_str() call here, so it shouldn't be touched
+void fmt_print_no_cstr(const std::string &s1, const std::string &s2) {
+fmt::print("One: {}, Two: {}\n", s1, s2);
+}
+
+// This isn't fmt::print, so it shouldn't be fixed.
+void not_fmt_print(const std::string &s1) {
+notfmt::print("One: {}\n", s1.c_str());
+}
+
+void fmt_format(const std::string &s1, const std::string &s2, const std::string &s3) {
+  auto r1 = fmt::format("One:{}\n", s1.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}auto r1 = fmt::format("One:{}\n", s1);
+
+  auto r2 = fmt::format("One:{} Two:{} Three:{}\n", s1.c_str(), s2, s3.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:53: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-2]]:69: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}auto r2 = fmt::format("One:{} Two:{} Three:{}\n", s1, s2, s3);
+}
+
+// There's are c_str() calls here, so it shouldn't be touched
+void fmt_format_no_cstr(const std::string &s1, const std::string &s2) {
+fmt::format("One: {}, Two: {}\n", s1, s2);
+}
+
+// This is not fmt::format, so it shouldn't be fixed
+std::string not_fmt_format(const std::string &s1) {
+return notfmt::format("One: {}\n", s1.c_str());
+}
+
+class BaseLogger {
+public:
+  template 
+  void operator()(const char *fmt, Args &&...args) {
+  }
+
+  template 
+  void Log(const char *fmt, Args &&...args) {
+  }
+};
+
+class DerivedLogger : public BaseLogger {};
+class DoubleDerivedLogger : public DerivedLogger {};
+typedef DerivedLogger TypedefDerivedLogger;
+
+void logger1(const std::string &s1, const std::string &s2, const std::string &s3) {
+  BaseLogger LOGGER;
+
+  LOGGER("%s\n", s1.c_str(), s2, s3.c_str());
+  // 

[PATCH] D145885: [clang-tidy] Support readability-redundant-string-cstr.StringParameterFunctions option

2023-03-12 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

I can squash this with https://reviews.llvm.org/D143342 if required.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145885/new/

https://reviews.llvm.org/D145885

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-03-12 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp:189
+  getLangOpts().CPlusPlus2b
+  ? hasAnyName("::std::print", "::std::format")
+  : hasName("::std::format"))),

PiotrZSL wrote:
> mikecrowe wrote:
> > PiotrZSL wrote:
> > > mikecrowe wrote:
> > > > mikecrowe wrote:
> > > > > PiotrZSL wrote:
> > > > > > Please introduce configuration option to specify custom functions.
> > > > > > For example if some project (like mine) is wrapping fmt::format 
> > > > > > with some variadic template function, then such function could be 
> > > > > > specified.
> > > > > > Same goes to things like some loggers.
> > > > > > 
> > > > > > Check utils/OptionsUtils.h for configuration, and  utils/Matchers.h 
> > > > > > (matchesAnyListedName)
> > > > > > Please introduce configuration option to specify custom functions.
> > > > > > For example if some project (like mine) is wrapping fmt::format 
> > > > > > with some variadic template function, then such function could be 
> > > > > > specified.
> > > > > 
> > > > > That's exactly where this change originated (as part of [[ 
> > > > > https://github.com/mikecrowe/clang-tidy-fmt | my clang-tidy fmt fork 
> > > > > ]], which I hope to submit for review soon once I've made it 
> > > > > configurable too and improved the test cases.)
> > > > > 
> > > > > > Same goes to things like some loggers.
> > > > > > 
> > > > > > Check utils/OptionsUtils.h for configuration, and  utils/Matchers.h 
> > > > > > (matchesAnyListedName)
> > > > > 
> > > > > Thanks for the pointer. I shall study those files for how to support 
> > > > > this.
> > > > > 
> > > > > Do you think that the change can land like in its current state 
> > > > > first? Or would you prefer that the configuration option is added at 
> > > > > the same time?
> > > > > Please introduce configuration option to specify custom functions.
> > > > > For example if some project (like mine) is wrapping fmt::format with 
> > > > > some variadic template function, then such function could be 
> > > > > specified.
> > > > 
> > > > I could add some sort of 
> > > > `readability-redundant-string-cstr.PrintFunction` option or 
> > > > `readability-redundant-string-cstr.FormatFunction` option, but reducing 
> > > > this to its fundamental behaviour would be "a function that takes 
> > > > `const char *` arguments that is also willing to take `std::string` 
> > > > arguments". I'm struggling to find a sensible name for such an option. 
> > > > Maybe 
> > > > `readability-redundant-string-cstr.StdStringAcceptingFunction=::fmt::format`?
> > > >  Or just `readability-redundant-string-cstr.FunctionCall=::fmt::format`?
> > > > 
> > > > > Same goes to things like some loggers.
> > > > 
> > > > Loggers may be classes, so there would need to be an option that 
> > > > specifies a class name (or even a base class name) and a method name 
> > > > (which may be an operator.) See [[ 
> > > > https://github.com/mikecrowe/clang-tidy-fmt/blob/7ace8a3ff41e9679104fe558835b0ef3cb33d969/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp#L196
> > > >  | this hard-coded example ]] (If it's not obvious, there's a 
> > > > description in the [[ 
> > > > https://github.com/mikecrowe/clang-tidy-fmt/blob/7ace8a3ff41e9679104fe558835b0ef3cb33d969/README.md?plain=1#L103
> > > >  | README ]]. In such cases the options could be 
> > > > `readability-redundant-string-cstr.Class=::BaseTrace` and 
> > > > `readability-redundant-string-cstr.Method=Log` or 
> > > > `readability-redundant-string-cstr.Operator=()`, but then it would be 
> > > > hard to tie together the right classes and methods. That could be 
> > > > avoided with something like 
> > > > `readability-redundant-string-cstr.MemberFunctionCall=::BaseTrace::operator(),::NullTrace::operator()`
> > > >  and some parsing I suppose.
> > > > 
> > > > Regardless, I'll try and get the simple case working and await 
> > > > suggestions for appropriate option names.
> > > > 
> > > > Thanks again for the suggestions.
> > > > 
> > > I asked AI, and it suggested 
> > > readability-redundant-string-cstr.FormattingFunctionsList.
> > > Also, I thing that matchesAnyListedName should support things like 
> > > '::NullTrace::operator()', so one option should be sufficient.
> > > 
> > > FormattingFunctionsList:
> > > A semicolon-separated list of (fully qualified) function/method/operator 
> > > names, with the requirement that 
> > > any parameter capable of accepting a 'const char*' input should also be 
> > > able to accept 'std::string' or 
> > > 'std::string_view' inputs, or proper overload candidates that can do so 
> > > should exist.
> > Far be it from me to question the wisdom of the AI :) , but my point was 
> > that the check works for any function that accepts `const char *` 
> > parameters that could equally well

[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-03-12 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

In D143342#4187641 , @PiotrZSL wrote:

> Correct commit message and this could land.

I've read through all the comments and the commit message itself and I can't 
spot what's wrong with the commit message, except perhaps for its verbosity. 
What would you like me to correct?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D143342/new/

https://reviews.llvm.org/D143342

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-03-12 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

Thank you for your patience.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D143342/new/

https://reviews.llvm.org/D143342

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-03-12 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 504474.
mikecrowe edited the summary of this revision.
mikecrowe added a comment.

Rebase. No conflicts.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D143342/new/

https://reviews.llvm.org/D143342

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
  
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-format.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-format.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-format.cpp
@@ -0,0 +1,214 @@
+// RUN: %check_clang_tidy -check-suffix=STDFORMAT -std=c++20 %s readability-redundant-string-cstr %t -- --  -isystem %clang_tidy_headers -DTEST_STDFORMAT
+// RUN: %check_clang_tidy -check-suffixes=STDFORMAT,STDPRINT -std=c++2b %s readability-redundant-string-cstr %t -- --  -isystem %clang_tidy_headers -DTEST_STDFORMAT -DTEST_STDPRINT
+#include 
+
+namespace std {
+  template
+struct type_identity { using type = T; };
+  template
+using type_identity_t = typename type_identity::type;
+
+  template 
+  struct basic_format_string {
+consteval basic_format_string(const CharT *format) : str(format) {}
+basic_string_view> str;
+  };
+
+  template
+using format_string = basic_format_string...>;
+
+  template
+using wformat_string = basic_format_string...>;
+
+#if defined(TEST_STDFORMAT)
+  template
+  std::string format(format_string, Args &&...);
+  template
+  std::string format(wformat_string, Args &&...);
+#endif // TEST_STDFORMAT
+
+#if defined(TEST_STDPRINT)
+  template
+  void print(format_string, Args &&...);
+  template
+  void print(wformat_string, Args &&...);
+#endif // TEST_STDPRINT
+}
+
+namespace notstd {
+#if defined(TEST_STDFORMAT)
+  template
+  std::string format(const char *, Args &&...);
+  template
+  std::string format(const wchar_t *, Args &&...);
+#endif // TEST_STDFORMAT
+#if defined(TEST_STDPRINT)
+  template
+  void print(const char *, Args &&...);
+  template
+  void print(const wchar_t *, Args &&...);
+#endif // TEST_STDPRINT
+}
+
+std::string return_temporary();
+std::wstring return_wtemporary();
+
+#if defined(TEST_STDFORMAT)
+void std_format(const std::string &s1, const std::string &s2, const std::string &s3) {
+  auto r1 = std::format("One:{}\n", s1.c_str());
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:37: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES-STDFORMAT: {{^  }}auto r1 = std::format("One:{}\n", s1);
+
+  auto r2 = std::format("One:{} Two:{} Three:{} Four:{}\n", s1.c_str(), s2, s3.c_str(), return_temporary().c_str());
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:61: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-2]]:77: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-3]]:89: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES-STDFORMAT: {{^  }}auto r2 = std::format("One:{} Two:{} Three:{} Four:{}\n", s1, s2, s3, return_temporary());
+
+  using namespace std;
+  auto r3 = format("Four:{}\n", s1.c_str());
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:33: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES-STDFORMAT: {{^  }}auto r3 = format("Four:{}\n", s1);
+}
+
+void std_format_wide(const std::wstring &s1, const std::wstring &s2, const std::wstring &s3) {
+  auto r1 = std::format(L"One:{}\n", s1.c_str());
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:38: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES-STDFORMAT: {{^  }}auto r1 = std::format(L"One:{}\n", s1);
+
+  auto r2 = std::format(L"One:{} Two:{} Three:{} Four:{}\n", s1.c_str(), s2, s3.c_str(), return_wtemporary().c_str());
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:62: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-2]]:78: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-3]]:90: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES-STDFORMAT: {{^  }}auto r2 = std::format(L"One:{} Two:{} Three:{} Four:{}\n", s1, s2, s3, return_wtemporary());
+
+  using namespace std;
+  auto r3 = format(L"Four:{}\n", s1.c_str());
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:34: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES-STDFORMAT: {{^  }}auto r3 = format(L"Four:{}\n", s1);
+}
+
+// There's are c_str() calls here, so it shouldn't be touched.
+std::string std_format_no_cstr(const std::stri

[PATCH] D145885: [clang-tidy] Support readability-redundant-string-cstr.StringParameterFunctions option

2023-03-12 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 504475.
mikecrowe added a comment.

Rebase.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145885/new/

https://reviews.llvm.org/D145885

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
  clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/readability/redundant-string-cstr.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-function.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-function.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-function.cpp
@@ -0,0 +1,124 @@
+// RUN: %check_clang_tidy %s readability-redundant-string-cstr %t -- \
+// RUN:   -config="{CheckOptions: \
+// RUN: [{key: readability-redundant-string-cstr.StringParameterFunctions, \
+// RUN:   value: '::fmt::format; ::fmt::print; ::BaseLogger::operator(); ::BaseLogger::Log'}] \
+// RUN: }" \
+// RUN:   -- -isystem %clang_tidy_headers
+#include 
+
+namespace fmt {
+  inline namespace v8 {
+template
+void print(const char *, Args &&...);
+template
+std::string format(const char *, Args &&...);
+  }
+}
+
+namespace notfmt {
+  inline namespace v8 {
+template
+void print(const char *, Args &&...);
+template
+std::string format(const char *, Args &&...);
+  }
+}
+
+void fmt_print(const std::string &s1, const std::string &s2, const std::string &s3) {
+  fmt::print("One:{}\n", s1.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}fmt::print("One:{}\n", s1);
+
+  fmt::print("One:{} Two:{} Three:{}\n", s1.c_str(), s2, s3.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-2]]:58: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}fmt::print("One:{} Two:{} Three:{}\n", s1, s2, s3);
+}
+
+// There's no c_str() call here, so it shouldn't be touched
+void fmt_print_no_cstr(const std::string &s1, const std::string &s2) {
+fmt::print("One: {}, Two: {}\n", s1, s2);
+}
+
+// This isn't fmt::print, so it shouldn't be fixed.
+void not_fmt_print(const std::string &s1) {
+notfmt::print("One: {}\n", s1.c_str());
+}
+
+void fmt_format(const std::string &s1, const std::string &s2, const std::string &s3) {
+  auto r1 = fmt::format("One:{}\n", s1.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}auto r1 = fmt::format("One:{}\n", s1);
+
+  auto r2 = fmt::format("One:{} Two:{} Three:{}\n", s1.c_str(), s2, s3.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:53: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-2]]:69: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}auto r2 = fmt::format("One:{} Two:{} Three:{}\n", s1, s2, s3);
+}
+
+// There's are c_str() calls here, so it shouldn't be touched
+void fmt_format_no_cstr(const std::string &s1, const std::string &s2) {
+fmt::format("One: {}, Two: {}\n", s1, s2);
+}
+
+// This is not fmt::format, so it shouldn't be fixed
+std::string not_fmt_format(const std::string &s1) {
+return notfmt::format("One: {}\n", s1.c_str());
+}
+
+class BaseLogger {
+public:
+  template 
+  void operator()(const char *fmt, Args &&...args) {
+  }
+
+  template 
+  void Log(const char *fmt, Args &&...args) {
+  }
+};
+
+class DerivedLogger : public BaseLogger {};
+class DoubleDerivedLogger : public DerivedLogger {};
+typedef DerivedLogger TypedefDerivedLogger;
+
+void logger1(const std::string &s1, const std::string &s2, const std::string &s3) {
+  BaseLogger LOGGER;
+
+  LOGGER("%s\n", s1.c_str(), s2, s3.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-2]]:34: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}LOGGER("%s\n", s1, s2, s3);
+
+  DerivedLogger LOGGER2;
+  LOGGER2("%d %s\n", 42, s1.c_str(), s2.c_str(), s3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-2]]:38: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}LOGGER2("%d %s\n", 42, s1, s2, s3);
+
+  DoubleDerivedLogger LOGGERD;
+  LOGGERD("%d %s\n", 42, s1.c_str(), s2, s3.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: redundant call to 'c_str' [readability-redundant-string-cst

[PATCH] D145885: [clang-tidy] Support readability-redundant-string-cstr.StringParameterFunctions option

2023-03-12 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

In D145885#4187679 , @PiotrZSL wrote:

> My only complain is documentation, changes in code and tests are correct.
> Build failed mainly due to conflicts in previous change.
> It should get green once prev patch will land, and this will be re-based.

Thanks for the comments. I will address them. I've rebased this change on top 
of the rebase of the previous one. Maybe that will help. Git didn't report any 
conflicts when I rebased.

> I strongly suggest using arc (less issues with patches).

I have been using arc. I couldn't find a way to make it submit updates to more 
than one change at a time. I've done these two with `git checkout HEAD~1 ; arc 
diff ; git checkout mybranch; arc diff`. Is there a better way?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145885/new/

https://reviews.llvm.org/D145885

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145885: [clang-tidy] Support readability-redundant-string-cstr.StringParameterFunctions option

2023-03-13 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 504517.
mikecrowe marked 2 inline comments as done.
mikecrowe added a comment.

Documentation updates suggested by @PiotrZSL. Rebase.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145885/new/

https://reviews.llvm.org/D145885

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
  clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/readability/redundant-string-cstr.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-function.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-function.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-function.cpp
@@ -0,0 +1,148 @@
+// RUN: %check_clang_tidy %s readability-redundant-string-cstr %t -- \
+// RUN:   -config="{CheckOptions: \
+// RUN: [{key: readability-redundant-string-cstr.StringParameterFunctions, \
+// RUN:   value: '::fmt::format; ::fmt::print; ::BaseLogger::operator(); ::BaseLogger::Log'}] \
+// RUN: }" \
+// RUN:   -- -isystem %clang_tidy_headers
+#include 
+
+namespace fmt {
+  inline namespace v8 {
+template
+void print(const char *, Args &&...);
+template
+std::string format(const char *, Args &&...);
+  }
+}
+
+namespace notfmt {
+  inline namespace v8 {
+template
+void print(const char *, Args &&...);
+template
+std::string format(const char *, Args &&...);
+  }
+}
+
+void fmt_print(const std::string &s1, const std::string &s2, const std::string &s3) {
+  fmt::print("One:{}\n", s1.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}fmt::print("One:{}\n", s1);
+
+  fmt::print("One:{} Two:{} Three:{}\n", s1.c_str(), s2, s3.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-2]]:58: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}fmt::print("One:{} Two:{} Three:{}\n", s1, s2, s3);
+}
+
+// There's no c_str() call here, so it shouldn't be touched
+void fmt_print_no_cstr(const std::string &s1, const std::string &s2) {
+fmt::print("One: {}, Two: {}\n", s1, s2);
+}
+
+// This isn't fmt::print, so it shouldn't be fixed.
+void not_fmt_print(const std::string &s1) {
+notfmt::print("One: {}\n", s1.c_str());
+}
+
+void fmt_format(const std::string &s1, const std::string &s2, const std::string &s3) {
+  auto r1 = fmt::format("One:{}\n", s1.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}auto r1 = fmt::format("One:{}\n", s1);
+
+  auto r2 = fmt::format("One:{} Two:{} Three:{}\n", s1.c_str(), s2, s3.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:53: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-2]]:69: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}auto r2 = fmt::format("One:{} Two:{} Three:{}\n", s1, s2, s3);
+}
+
+// There's are c_str() calls here, so it shouldn't be touched
+void fmt_format_no_cstr(const std::string &s1, const std::string &s2) {
+fmt::format("One: {}, Two: {}\n", s1, s2);
+}
+
+// This is not fmt::format, so it shouldn't be fixed
+std::string not_fmt_format(const std::string &s1) {
+return notfmt::format("One: {}\n", s1.c_str());
+}
+
+class BaseLogger {
+public:
+  template 
+  void operator()(const char *fmt, Args &&...args) {
+  }
+
+  template 
+  void Log(const char *fmt, Args &&...args) {
+  }
+};
+
+class DerivedLogger : public BaseLogger {};
+class DoubleDerivedLogger : public DerivedLogger {};
+typedef DerivedLogger TypedefDerivedLogger;
+
+void logger1(const std::string &s1, const std::string &s2, const std::string &s3) {
+  BaseLogger LOGGER;
+
+  LOGGER("%s\n", s1.c_str(), s2, s3.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-2]]:34: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}LOGGER("%s\n", s1, s2, s3);
+
+  DerivedLogger LOGGER2;
+  LOGGER2("%d %s\n", 42, s1.c_str(), s2.c_str(), s3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-2]]:38: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}LOGGER2("%d %s\n", 42, s1, s2, s3);
+
+  DoubleDerivedLogger LOGGERD;
+  LOGGERD("%d %s\n", 42, s1.c_str(), s2, s3.c_str());
+  // CHECK-MESSA

[PATCH] D145885: [clang-tidy] Support readability-redundant-string-cstr.StringParameterFunctions option

2023-03-13 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 504537.
mikecrowe edited the summary of this revision.
mikecrowe added a comment.

Quote types and functions correctly in redundant-string-cstr.rst.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145885/new/

https://reviews.llvm.org/D145885

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
  clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/readability/redundant-string-cstr.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-function.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-function.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-function.cpp
@@ -0,0 +1,148 @@
+// RUN: %check_clang_tidy %s readability-redundant-string-cstr %t -- \
+// RUN:   -config="{CheckOptions: \
+// RUN: [{key: readability-redundant-string-cstr.StringParameterFunctions, \
+// RUN:   value: '::fmt::format; ::fmt::print; ::BaseLogger::operator(); ::BaseLogger::Log'}] \
+// RUN: }" \
+// RUN:   -- -isystem %clang_tidy_headers
+#include 
+
+namespace fmt {
+  inline namespace v8 {
+template
+void print(const char *, Args &&...);
+template
+std::string format(const char *, Args &&...);
+  }
+}
+
+namespace notfmt {
+  inline namespace v8 {
+template
+void print(const char *, Args &&...);
+template
+std::string format(const char *, Args &&...);
+  }
+}
+
+void fmt_print(const std::string &s1, const std::string &s2, const std::string &s3) {
+  fmt::print("One:{}\n", s1.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}fmt::print("One:{}\n", s1);
+
+  fmt::print("One:{} Two:{} Three:{}\n", s1.c_str(), s2, s3.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-2]]:58: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}fmt::print("One:{} Two:{} Three:{}\n", s1, s2, s3);
+}
+
+// There's no c_str() call here, so it shouldn't be touched
+void fmt_print_no_cstr(const std::string &s1, const std::string &s2) {
+fmt::print("One: {}, Two: {}\n", s1, s2);
+}
+
+// This isn't fmt::print, so it shouldn't be fixed.
+void not_fmt_print(const std::string &s1) {
+notfmt::print("One: {}\n", s1.c_str());
+}
+
+void fmt_format(const std::string &s1, const std::string &s2, const std::string &s3) {
+  auto r1 = fmt::format("One:{}\n", s1.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}auto r1 = fmt::format("One:{}\n", s1);
+
+  auto r2 = fmt::format("One:{} Two:{} Three:{}\n", s1.c_str(), s2, s3.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:53: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-2]]:69: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}auto r2 = fmt::format("One:{} Two:{} Three:{}\n", s1, s2, s3);
+}
+
+// There's are c_str() calls here, so it shouldn't be touched
+void fmt_format_no_cstr(const std::string &s1, const std::string &s2) {
+fmt::format("One: {}, Two: {}\n", s1, s2);
+}
+
+// This is not fmt::format, so it shouldn't be fixed
+std::string not_fmt_format(const std::string &s1) {
+return notfmt::format("One: {}\n", s1.c_str());
+}
+
+class BaseLogger {
+public:
+  template 
+  void operator()(const char *fmt, Args &&...args) {
+  }
+
+  template 
+  void Log(const char *fmt, Args &&...args) {
+  }
+};
+
+class DerivedLogger : public BaseLogger {};
+class DoubleDerivedLogger : public DerivedLogger {};
+typedef DerivedLogger TypedefDerivedLogger;
+
+void logger1(const std::string &s1, const std::string &s2, const std::string &s3) {
+  BaseLogger LOGGER;
+
+  LOGGER("%s\n", s1.c_str(), s2, s3.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-2]]:34: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}LOGGER("%s\n", s1, s2, s3);
+
+  DerivedLogger LOGGER2;
+  LOGGER2("%d %s\n", 42, s1.c_str(), s2.c_str(), s3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-2]]:38: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}LOGGER2("%d %s\n", 42, s1, s2, s3);
+
+  DoubleDerivedLogger LOGGERD;
+  LOGGERD("%d %s\n", 42, s1.c_str(), s2, s3.c_str());
+ 

[PATCH] D149280: [clang-tidy] Add modernize-printf-to-std-print check

2023-06-18 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe marked 6 inline comments as done.
mikecrowe added a comment.

Thanks for the comprehensive review.




Comment at: clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp:43-44
+
+  if (!MaybeHeaderToInclude && (ReplacementPrintFunction == "std::print" ||
+ReplacementPrintlnFunction == "std::println"))
+MaybeHeaderToInclude = "";

PiotrZSL wrote:
> this code is already duplicated, move it to some separate private function, 
> like isCpp23PrintConfigured or something...
You're correct that `ReplacementPrintFunction == "std::print" || 
ReplacementPrintlnFunction == "std::println"` is duplicated in 
`isLanguageVersionSupported`, but in that code we're considering which C++ 
version the functions require and in this code we're considering which header 
the functions require. These are not the same question. It just so happens that 
these checks are against the same function names now, but they need not be. If 
another function is added to `` in C++26 and this code ends up being 
able to convert to it then the checks would need to diverge.

Nevertheless, I will do as you request if you still think it's worthwhile.




Comment at: clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp:56
+  Finder->addMatcher(
+  traverse(TK_IgnoreUnlessSpelledInSource,
+   callExpr(callee(functionDecl(matchers::matchesAnyListedName(

PiotrZSL wrote:
> Those TK_IgnoreUnlessSpelledInSource should be moved into 
> getCheckTraversalKind()
Ah, that was added since I wrote the original version of this check. I'll 
address this.



Comment at: clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.h:40
+  StringRef ReplacementPrintlnFunction;
+  utils::IncludeInserter IncludeInserter;
+  std::optional MaybeHeaderToInclude;

PiotrZSL wrote:
> I heard that using clang::tooling::HeaderIncludes is more recommended.
> And this is just some house-made stuff
I'm afraid that I don't really understand this comment. The use of 
`IncludeInserter` is far more common in the existing checks than 
`HeaderIncludes` and from looking at `IncludeCleaner.cpp` the use of the latter 
is rather more complex. New features were being added to `IncludeInserter` 
within the last six months. I'm unsure what "house-made" means in the context 
of the `IncludeInserter` code that I didn't write.

Do you have anything more concrete than hearsay? If there is a plan to 
deprecate `IncludeInserter` then it feels like something closer to its 
convenient interface would need to be implemented in terms of `HeaderIncludes` 
for checks to use rather than them duplicating the code in `IncludeCleaner.cpp`.

If you can explain what you'd like me to do, and ideally provide pointers to 
similar things being done elsewhere then perhaps I can address this comment.



Comment at: clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp:185
+  assert(FormatExpr);
+  PrintfFormatString = FormatExpr->getString();
+

PiotrZSL wrote:
> This may crash for wchar, maybe better limit StringLiteral to Ordinary and 
> UTF8 or only Ordinary 
It doesn't look like there's any support for u8 literals in `printf` or 
`std::print` (yet), so I think just Ordinary is sufficient.



Comment at: clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp:202
+/// Called for each format specifier by ParsePrintfString.
+bool FormatStringConverter::HandlePrintfSpecifier(
+const analyze_printf::PrintfSpecifier &FS, const char *StartSpecifier,

PiotrZSL wrote:
> this function should be split into smaller one.
I agree. I'm surprised it hasn't come up in review earlier. I tried to do so 
prior to pushing the very first version of this for review and gave up since 
the parts ended up referring to so many local variables making the code even 
harder to understand than it is now. I will have another attempt.



Comment at: clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp:230
+return conversionNotPossible("'%m' is not supported in format string");
+  } else {
+StandardFormatString.push_back('{');

PiotrZSL wrote:
> general: no need for else after return
In general, you're correct that I've used else after return in other places and 
I will fix them. However, in this case the else is required since the very 
first `if` block above doesn't have a return. (Hopefully this complexity will 
go away if I succeed in splitting this function up.)



Comment at: clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp:384-397
+const auto StringDecl = type(hasUnqualifiedDesugaredType(recordType(
+hasDeclaration(cxxRecordDecl(hasName("::std::basic_string"));
+const auto StringExpr = expr(anyOf(
+hasType(StringDecl), hasType(qualType(pointsTo(StringDecl);
+
+const a

[PATCH] D149280: [clang-tidy] Add modernize-printf-to-std-print check

2023-06-18 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added inline comments.



Comment at: clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp:202
+/// Called for each format specifier by ParsePrintfString.
+bool FormatStringConverter::HandlePrintfSpecifier(
+const analyze_printf::PrintfSpecifier &FS, const char *StartSpecifier,

mikecrowe wrote:
> PiotrZSL wrote:
> > this function should be split into smaller one.
> I agree. I'm surprised it hasn't come up in review earlier. I tried to do so 
> prior to pushing the very first version of this for review and gave up since 
> the parts ended up referring to so many local variables making the code even 
> harder to understand than it is now. I will have another attempt.
It turns out that things are working out much better in my second attempt at 
splitting this function. I shall address the other new review comments before 
sending another revision for review though.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D149280/new/

https://reviews.llvm.org/D149280

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D149280: [clang-tidy] Add modernize-printf-to-std-print check

2023-06-24 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe marked 7 inline comments as done.
mikecrowe added a comment.

I'm still working on the remaining items.




Comment at: clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp:230
+return conversionNotPossible("'%m' is not supported in format string");
+  } else {
+StandardFormatString.push_back('{');

mikecrowe wrote:
> PiotrZSL wrote:
> > general: no need for else after return
> In general, you're correct that I've used else after return in other places 
> and I will fix them. However, in this case the else is required since the 
> very first `if` block above doesn't have a return. (Hopefully this complexity 
> will go away if I succeed in splitting this function up.)
I've now reworked this function extensively, so there's no longer an else here.



Comment at: 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst:117
+
+.. option:: PrintFunction
+

PiotrZSL wrote:
> mikecrowe wrote:
> > Is `PrintFunction` (and the soon-to-arrive `PrintlnFunction`) distinct 
> > enough from `PrintfLikeFunctions` and `FprintfLikeFunctions`? Should I use 
> > `ReplacementPrintFunction` instead?
> Use `Replacement`. It will be way better.
I assume that you mean `ReplacementPrintFunction`. (I see `ReplacementString` 
used in other checks, so I think that just `Replacement` might be a bit vague.)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D149280/new/

https://reviews.llvm.org/D149280

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D149280: [clang-tidy] Add modernize-printf-to-std-print check

2023-06-24 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe marked 4 inline comments as done.
mikecrowe added inline comments.



Comment at: clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp:384-397
+const auto StringDecl = type(hasUnqualifiedDesugaredType(recordType(
+hasDeclaration(cxxRecordDecl(hasName("::std::basic_string"));
+const auto StringExpr = expr(anyOf(
+hasType(StringDecl), hasType(qualType(pointsTo(StringDecl);
+
+const auto StringCStrCallExpr =
+cxxMemberCallExpr(on(StringExpr.bind("arg")),

PiotrZSL wrote:
> mikecrowe wrote:
> > PiotrZSL wrote:
> > > constant construction of those marchers may be costly.. can be cache them 
> > > somehow in this object ?
> > Good idea. Do you have any pointers to code that does this? I couldn't find 
> > any.
> > 
> > The types involved all seem to be in the `internal::` namespace and 
> > presumably subject to change. Ideally, I'd put:
> > ```
> > std::optional StringCStrCallExprMatcher;
> > ```
> > in the class and then populate it here the first time lazily. Unfortunately 
> > I have no idea what type to use for `SomeSortOfMatcherType`.
> `clang::ast_matchers::StatementMatcher`, this is defined 
> as `using clang::ast_matchers::StatementMatcher = typedef 
> internal::Matcher`.
> I would create it in class constructor as private member.
Thanks for the pointer. It turns out that I need just 
`clang::ast_matchers::StatementMatcher`.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D149280/new/

https://reviews.llvm.org/D149280

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D149280: [clang-tidy] Add modernize-printf-to-std-print check

2023-06-24 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

@Eugene.Zelenko,
I will make the documentation changes you've suggested, but I can't say I 
really understand which document elements require single backticks and which 
require dual backticks. https://llvm.org/docs/SphinxQuickstartTemplate.html 
seems to imply that single backticks are only used for links and double 
backticks are used for monospace, but it's not completely clear. Most of the 
existing documentation seems to be consistent with what you've suggested though.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D149280/new/

https://reviews.llvm.org/D149280

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D149280: [clang-tidy] Add modernize-printf-to-std-print check

2023-06-24 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe marked 2 inline comments as done.
mikecrowe added a comment.

Thanks for the further reviews.




Comment at: clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp:37
+
+  if (PrintfLikeFunctions.empty() && FprintfLikeFunctions.empty()) {
+PrintfLikeFunctions.push_back("::printf");

PiotrZSL wrote:
> those 2 looks in-depended. Cannot they be put as default value into Option 
> config ?
My expectation was that if you didn't want to replace `printf` (and instead 
wanted to replace some other `printf`-like function) then you'd also not want 
to replace `fprintf` and vice-versa. In my head the two options do go together. 
If setting one didn't also remove the default for the other you'd end up having 
to specify `PrintfLikeFunctions=my_printf, FPrintfLikeFunctions=` just to 
replace a single function.



Comment at: clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp:79
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(
+  matchers::matchesAnyListedName(FprintfLikeFunctions))

PiotrZSL wrote:
> this could match also methods, maybe something `unless(cxxMethodDecl())` ?
I would like to be able to match methods. The code I wrote this check to run on 
has classes that have methods that used to call `std::fprintf`, and currently 
call `fmt::fprintf`. I wish to convert those methods to use `fmt::print` and 
use this check to fix all their callers. Eventually I hope to be able to move 
to `std::print`.

However, the check doesn't currently seem to work for methods since the 
arguments are off-by-one and the replacement is incorrect too. I'll add the 
`unless(cxxMethodDecl)` checks for now and support can be added later.



Comment at: clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp:82
+  .bind("func_decl")),
+   hasArgument(1, stringLiteral()))
+  .bind("fprintf"),

PiotrZSL wrote:
> consider moving this stringLiteral to be first, consider adding something 
> like `unless(argumentCountIs(0)), unless(argumentCountIs(1))`` at begining or 
> create matcher that verify first that argument count is >= 2, so we could 
> exlude most of callExpr at begining, even before we match functions
I would have hoped that `hasArgument` would fail quite fast if the argument 
index passed is greater than the number of arguments. I will add 
`argumentCountAtLeast` and use it regardless though.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D149280/new/

https://reviews.llvm.org/D149280

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D153716: [ASTMatchers] Add argumentCountAtLeast narrowing matcher

2023-06-25 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added inline comments.



Comment at: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp:1671
+  notMatches("void x(int, int = 1) { x(0); }",
+ traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs)));
+  EXPECT_TRUE(

I'm not sure if this is the best way to trigger testing of the ignoring default 
argument path in the implementation of `argumentCountAtLeast`, but it does seem 
to work. I added explicit `TK_AsIs` to the tests above to make it clear that 
they are not testing that path.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153716/new/

https://reviews.llvm.org/D153716

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D153716: [ASTMatchers] Add argumentCountAtLeast narrowing matcher

2023-06-25 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
mikecrowe added a reviewer: PiotrZSL.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
mikecrowe added inline comments.



Comment at: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp:1671
+  notMatches("void x(int, int = 1) { x(0); }",
+ traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs)));
+  EXPECT_TRUE(

I'm not sure if this is the best way to trigger testing of the ignoring default 
argument path in the implementation of `argumentCountAtLeast`, but it does seem 
to work. I added explicit `TK_AsIs` to the tests above to make it clear that 
they are not testing that path.


This will be used by the modernize-use-std-print clang-tidy check and
related checks later.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D153716

Files:
  clang/docs/LibASTMatchersReference.html
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -1640,6 +1640,95 @@
  cxxConversionDecl(isExplicit(;
 }
 
+TEST_P(ASTMatchersTest, ArgumentCountAtLeast_CallExpr) {
+  StatementMatcher Call2PlusArgs = callExpr(argumentCountAtLeast(2));
+
+  EXPECT_TRUE(notMatches("void x(void) { x(); }", Call2PlusArgs));
+  EXPECT_TRUE(notMatches("void x(int) { x(0); }", Call2PlusArgs));
+  EXPECT_TRUE(matches("void x(int, int) { x(0, 0); }", Call2PlusArgs));
+  EXPECT_TRUE(matches("void x(int, int, int) { x(0, 0, 0); }", Call2PlusArgs));
+
+  if (!GetParam().isCXX()) {
+return;
+  }
+
+  EXPECT_TRUE(
+  notMatches("void x(int = 1) { x(); }", traverse(TK_AsIs, Call2PlusArgs)));
+  EXPECT_TRUE(matches("void x(int, int = 1) { x(0); }",
+  traverse(TK_AsIs, Call2PlusArgs)));
+  EXPECT_TRUE(matches("void x(int, int = 1, int = 1) { x(0); }",
+  traverse(TK_AsIs, Call2PlusArgs)));
+  EXPECT_TRUE(matches("void x(int, int, int = 1) { x(0, 0); }",
+  traverse(TK_AsIs, Call2PlusArgs)));
+  EXPECT_TRUE(matches("void x(int, int, int, int = 1) { x(0, 0, 0); }",
+  traverse(TK_AsIs, Call2PlusArgs)));
+
+  EXPECT_TRUE(
+  notMatches("void x(int = 1) { x(); }",
+ traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs)));
+  EXPECT_TRUE(
+  notMatches("void x(int, int = 1) { x(0); }",
+ traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs)));
+  EXPECT_TRUE(
+  notMatches("void x(int, int = 1, int = 1) { x(0); }",
+ traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs)));
+  EXPECT_TRUE(matches("void x(int, int, int = 1) { x(0, 0); }",
+  traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs)));
+  EXPECT_TRUE(matches("void x(int, int, int, int = 1) { x(0, 0, 0); }",
+  traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs)));
+}
+
+TEST_P(ASTMatchersTest, ArgumentCountAtLeast_CallExpr_CXX) {
+  if (!GetParam().isCXX()) {
+return;
+  }
+
+  StatementMatcher Call2PlusArgs = callExpr(argumentCountAtLeast(2));
+  EXPECT_TRUE(notMatches("class X { void x() { x(); } };", Call2PlusArgs));
+  EXPECT_TRUE(notMatches("class X { void x(int) { x(0); } };", Call2PlusArgs));
+  EXPECT_TRUE(
+  matches("class X { void x(int, int) { x(0, 0); } };", Call2PlusArgs));
+  EXPECT_TRUE(matches("class X { void x(int, int, int) { x(0, 0, 0); } };",
+  Call2PlusArgs));
+
+  EXPECT_TRUE(notMatches("class X { void x(int = 1) { x(0); } };",
+ traverse(TK_AsIs, Call2PlusArgs)));
+  EXPECT_TRUE(matches("class X { void x(int, int = 1) { x(0); } };",
+  traverse(TK_AsIs, Call2PlusArgs)));
+  EXPECT_TRUE(matches("class X { void x(int, int = 1, int = 1) { x(0); } };",
+  traverse(TK_AsIs, Call2PlusArgs)));
+  EXPECT_TRUE(matches("class X { void x(int, int, int = 1) { x(0, 0); } };",
+  traverse(TK_AsIs, Call2PlusArgs)));
+  EXPECT_TRUE(
+  matches("class X { void x(int, int, int, int = 1) { x(0, 0, 0); } };",
+  traverse(TK_AsIs, Call2PlusArgs)));
+
+  EXPECT_TRUE(
+  notMatches("class X { void x(int = 1) { x(0); } };",
+ traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs)));
+  EXPECT_TRUE(
+  notMatches("class X { void x(int, int = 1) { x(0); } };",
+ traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs)));
+  EXPECT_TRUE(
+  notMatches("class X { void x(int, int = 1, int = 1) { x(0); } };",
+ traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs)));
+  EXPECT_TRUE(matches("cl

[PATCH] D149280: [clang-tidy] Add modernize-printf-to-std-print check

2023-06-25 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added inline comments.



Comment at: clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp:64
+  if (MaybeHeaderToInclude)
+Options.store(Opts, "PrintHeader", *MaybeHeaderToInclude);
+}

This is going to write the default value set in the constructor if 
`ReplacementPrintFunction` is `std::print` or `ReplacementPrintlnFunction` is 
`std::println` even if `PrintHeader` was not specified in the configuration. I 
don't know how much of a problem this is.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D149280/new/

https://reviews.llvm.org/D149280

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D149280: [clang-tidy] Add modernize-printf-to-std-print check

2023-06-25 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

In D149280#4447363 , @thakis wrote:

> This breaks tests on windows: http://45.33.8.238/win/80283/step_8.txt
>
> Please take a look and revert for now if it takes a while to fix.

Thanks for letting me know, I thought I could get away with including 
 from a test since it is a compiler header rather than a libc 
header.

I've added a potential fix, but I don't have a Windows machine (or many other 
targets) to test it on. Is there a way to get this change to run through the 
buildbots without landing it?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D149280/new/

https://reviews.llvm.org/D149280

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D149280: [clang-tidy] Add modernize-printf-to-std-print check

2023-06-25 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe marked an inline comment as done.
mikecrowe added inline comments.



Comment at: 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp:9-15
+#include 
+#include 
+#include 
+// CHECK-FIXES: #include 
+#include 
+#include 
+#include 

PiotrZSL wrote:
> Those includes need to be removed. We cannot use system includes, some dummy 
> one can be used only.
I believe that `` is the only one that isn't present in 
`test/clang-tidy/checkers/Inputs/Headers/`. Hopefully adding it will have been 
sufficient.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D149280/new/

https://reviews.llvm.org/D149280

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D149280: [clang-tidy] Add modernize-printf-to-std-print check

2023-06-26 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe marked an inline comment as done.
mikecrowe added a comment.

In D149280#4448158 , @PiotrZSL wrote:

> Test is failing:
> https://lab.llvm.org/buildbot/#/builders/230/builds/14939/steps/6/logs/FAIL__Clang_Tools__use-std-print_cpp
> https://lab.llvm.org/buildbot/#/builders/245/builds/10266

It  looks like the `char` test is failing on targets where unadorned `char` is 
`unsigned`. I have access to two such machines, so I ought to be able to 
reproduce this myself (either on the up-to-date slow one, or the fast one that 
lacks a sufficiently-new cmake.)

@thakis, http://45.33.8.238/win/80313/summary.html makes it looks like Windows 
may be happy now, but I may be misinterpreting the results.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D149280/new/

https://reviews.llvm.org/D149280

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D149280: [clang-tidy] Add modernize-printf-to-std-print check

2023-06-26 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added inline comments.



Comment at: 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp:169
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 
'printf' [modernize-use-std-print]
+  // CHECK-FIXES: std::println("Integer {:d} from char", c);
+

This should have a cast to `signed char` if `StrictMode=true`. That cast is 
currently there by accident on targets where `char` is unsigned, but not on 
targets where `char` is signed. This is a real problem, but luckily one that's 
easy to fix.



Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D149280/new/

https://reviews.llvm.org/D149280

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D149280: [clang-tidy] Add modernize-printf-to-std-print check

2023-06-26 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

Despite the fact that I've worked on what became this check for about two 
years, now that it's landed I've suddenly spotted a significant flaw: `printf` 
returns the number of characters printed, whereas `std::print` doesn't return 
anything. None of my test cases made use of the return value. I think this 
means that I need to only match on calls that don't make use of the return 
value. I shall try to do that.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D149280/new/

https://reviews.llvm.org/D149280

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D153860: [clang-tidy] Fix modernize-use-std-print check when return value used

2023-06-27 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
mikecrowe added a reviewer: PiotrZSL.
Herald added subscribers: carlosgalvezp, xazax.hun.
Herald added a reviewer: njames93.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

The initial implementation of the modernize-use-std-print check was
capable of converting calls to printf (etc.) which used the return value
to calls to std::print which has no return value, thus breaking the
code.

Use code inspired by the implementation of bugprone-unused-return-value
check to ignore cases where the return value is used. Add appropriate
lit test cases and documentation.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D153860

Files:
  clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp
  clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-absl.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
@@ -44,6 +44,233 @@
   // CHECK-FIXES: std::println("Hello");
 }
 
+// std::print returns nothing, so any callers that use the return
+// value cannot be automatically translated.
+int printf_uses_return_value(int choice) {
+  const int i = printf("Return value assigned to variable %d\n", 42);
+
+  if (choice == 0)
+printf("if body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("if body {}", i);
+  else if (choice == 1)
+printf("else if body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("else if body {}", i);
+  else
+printf("else body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("else body {}", i);
+
+  if (printf("Return value used as boolean in if statement"))
+if (printf("Return value used in expression if statement") == 44)
+  if (const int j = printf("Return value used in assignment in if statement"))
+if (const int k = printf("Return value used with initializer in if statement"); k == 44)
+  ;
+
+  int d = 0;
+  while (printf("%d", d) < 2)
+++d;
+
+  while (true)
+printf("while body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("while body {}", i);
+
+  do
+printf("do body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("do body {}", i);
+  while (true);
+
+  for (;;)
+printf("for body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("for body {}", i);
+
+  for (printf("for init statement %d\n", i);;)
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("for init statement {}", i);
+;;
+
+  for (int j = printf("for init statement %d\n", i);;)
+;;
+
+  for (; printf("for condition %d\n", i);)
+;;
+
+  for (;; printf("for expression %d\n", i))
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("for expression {}", i)
+;;
+
+  for (auto C : "foo")
+printf("ranged-for body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("ranged-for body {}", i);
+
+  switch (1) {
+  case 1:
+printf("switch case body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("switch case body {}", i);
+break;
+  default:
+printf("switch default body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("switch default body {}", i);
+break;
+  }
+
+  try {
+printf("try body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("try body {}", i);
+  } catch (i

[PATCH] D153860: [clang-tidy] Fix modernize-use-std-print check when return value used

2023-06-27 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe marked an inline comment as done.
mikecrowe added inline comments.



Comment at: clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp:73-95
+static clang::ast_matchers::StatementMatcher
+unusedReturnValue(clang::ast_matchers::StatementMatcher MatchedCallExpr) {
+  auto UnusedInCompoundStmt =
+  compoundStmt(forEach(MatchedCallExpr),
+   // The checker can't currently differentiate between the
+   // return statement and other statements inside GNU 
statement
+   // expressions, so disable the checker inside them to avoid

PiotrZSL wrote:
> NOTE: Personally I do not thing that this is right way. Instead of using 
> "inclusion" matcher, better would be to use elimination.
> like:
> ```callExpr(unless(hasParent(anyOf(varDecl(), callExpr(), ifStmt(), ...```.
> 
> But if it's working fine, then it could be for now, so lets leave it. Simply 
> with this it may not find all cases.
I'm happy to try doing it a different way. I just took this code from the 
`bugprone-unused-return-value` check. I had a go at using:
```C++
Finder->addMatcher(
  callExpr(unless(hasParent(anyOf(varDecl(), callExpr(), ifStmt(), 
whileStmt(), doStmt(), forStmt(), cxxForRangeStmt(), switchCase(, 
argumentCountAtLeast(1),
```
but there's no overload of `hasParent` that will accept the return type of 
`anyOf`:
```
/home/mac/git/llvm-project/clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp:100:23:
 error: no matching function for call to object of type 'const 
internal::ArgumentAdaptingMatcherFunc, 
internal::TypeList>'
  callExpr(unless(hasParent(anyOf(varDecl(), callExpr(), ifStmt(), 
whileStmt(), doStmt(), forStmt(), cxxForRangeStmt(), switchCase(, 
argumentCountAtLeast(1),
  ^
/home/mac/git/llvm-project/clang/include/clang/ASTMatchers/ASTMatchersInternal.h:1491:3:
 note: candidate template ignored: could not match 'Matcher' against 
'VariadicOperatorMatcher'
  operator()(const Matcher &InnerMatcher) const {
  ^
/home/mac/git/llvm-project/clang/include/clang/ASTMatchers/ASTMatchersInternal.h:1498:3:
 note: candidate template ignored: could not match 'MapAnyOfHelper' against 
'VariadicOperatorMatcher'
  operator()(const MapAnyOfHelper &InnerMatcher) const {
```
(Reducing the set of matchers inside the `anyOf` didn't help.)



Comment at: 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-absl.cpp:63
+  // CHECK-MESSAGES-NOT: [[@LINE-1]]:10: warning: use 'std::println' instead 
of 'PrintF' [modernize-use-std-print]
+  // CHECK-FIXES-NOT: std::println("return value {}", i);
+}

PiotrZSL wrote:
> NOTE: I don't think that those FIXES-NOT are needed.
OK. I'll leave only the ones that are for deficiencies that might one day be 
fixed.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153860/new/

https://reviews.llvm.org/D153860

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D153860: [clang-tidy] Fix modernize-use-std-print check when return value used

2023-06-27 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe marked an inline comment as done.
mikecrowe added a comment.

In D153860#4453572 , @dyung wrote:

> @mikecrowe Your change is causing a test failure on the PS4 linux and PS5 
> Windows build bots. Can you take a look and fix or revert if you need time to 
> investigate?
>
> https://lab.llvm.org/buildbot/#/builders/139/builds/43856
> https://lab.llvm.org/buildbot/#/builders/216/builds/23017

The failure is due to:

  use-std-print.cpp.tmp.cpp:125:3: error: cannot use 'try' with exceptions 
disabled [clang-diagnostic-error]

I wasn't expecting that!

It looks like I failed to notice that the `bugprone-unused-return-value` check 
explicitly added `-fexceptions` to the `clang-tidy` command line to avoid this 
problem. I can add that to hopefully fix the problem, and I had some other 
changes that I hadn't pushed for review before this landed the first time too.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153860/new/

https://reviews.llvm.org/D153860

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D153860: [clang-tidy] Fix modernize-use-std-print check when return value used

2023-06-27 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 535106.
mikecrowe added a comment.

Fix test failures on PS4 and PS5 and improve tests

- Ensure that exceptions are available so the test can use try/catch
- Remove unwanted -NOT checks
- Add more return value tests


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153860/new/

https://reviews.llvm.org/D153860

Files:
  clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp
  clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-absl.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp
  clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp
@@ -1,11 +1,11 @@
 // RUN: %check_clang_tidy -check-suffixes=,STRICT \
 // RUN:   -std=c++23 %s modernize-use-std-print %t -- \
 // RUN:   -config="{CheckOptions: [{key: StrictMode, value: true}]}" \
-// RUN:   -- -isystem %clang_tidy_headers
+// RUN:   -- -isystem %clang_tidy_headers -fexceptions
 // RUN: %check_clang_tidy -check-suffixes=,NOTSTRICT \
 // RUN:   -std=c++23 %s modernize-use-std-print %t -- \
 // RUN:   -config="{CheckOptions: [{key: StrictMode, value: false}]}" \
-// RUN:   -- -isystem %clang_tidy_headers
+// RUN:   -- -isystem %clang_tidy_headers -fexceptions
 #include 
 #include 
 #include 
@@ -44,6 +44,239 @@
   // CHECK-FIXES: std::println("Hello");
 }
 
+// std::print returns nothing, so any callers that use the return
+// value cannot be automatically translated.
+int printf_uses_return_value(int choice) {
+  const int i = printf("Return value assigned to variable %d\n", 42);
+
+  extern void accepts_int(int);
+  accepts_int(printf("Return value passed to function %d\n", 42));
+
+  if (choice == 0)
+printf("if body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("if body {}", i);
+  else if (choice == 1)
+printf("else if body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("else if body {}", i);
+  else
+printf("else body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("else body {}", i);
+
+  if (printf("Return value used as boolean in if statement"))
+if (printf("Return value used in expression if statement") == 44)
+  if (const int j = printf("Return value used in assignment in if statement"))
+if (const int k = printf("Return value used with initializer in if statement"); k == 44)
+  ;
+
+  int d = 0;
+  while (printf("%d", d) < 2)
+++d;
+
+  while (true)
+printf("while body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("while body {}", i);
+
+  do
+printf("do body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("do body {}", i);
+  while (true);
+
+  for (;;)
+printf("for body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("for body {}", i);
+
+  for (printf("for init statement %d\n", i);;)
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("for init statement {}", i);
+;;
+
+  for (int j = printf("for init statement %d\n", i);;)
+;;
+
+  for (; printf("for condition %d\n", i);)
+;;
+
+  for (;; printf("for expression %d\n", i))
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("for expression {}", i)
+;;
+
+  for (auto C : "foo")
+printf("ranged-for body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("ranged-for body {}", i);
+
+  switch (1) {
+  case 1:
+printf("switch case body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
+// CHECK-FIXES: std::println("switch case body {}", i);
+break;
+  default:
+printf("switch default body %d\n", i);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'pr

[PATCH] D153860: [clang-tidy] Fix modernize-use-std-print check when return value used

2023-06-29 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe requested review of this revision.
mikecrowe added a comment.

I believe that the problems that caused this to be reverted have been fixed.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153860/new/

https://reviews.llvm.org/D153860

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D154151: [clang-tidy] Improve documentation for modernize-use-std-print check

2023-06-29 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
mikecrowe added a reviewer: PiotrZSL.
Herald added subscribers: carlosgalvezp, xazax.hun.
Herald added a reviewer: njames93.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

Remove incorrect use of double colons so that the code blocks are
rendered correctly to HTML.

Wrap the name of another check in single backticks. Wrap the name of a
macro in double backticks.

Explain that with the default settings the check is only enabled with
C++23 or later standards.

Correct std::string_data() to std::string::data().


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D154151

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


Index: clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst
+++ clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst
@@ -9,21 +9,25 @@
 The replaced and replacement functions can be customised by configuration
 options. Each argument that is the result of a call to 
``std::string::c_str()`` and
 ``std::string::data()`` will have that now-unnecessary call removed in a
-similar manner to the readability-redundant-string-cstr check.
+similar manner to the `readability-redundant-string-cstr` check.
 
-In other words, it turns lines like::
+In other words, it turns lines like:
 
 .. code-block:: c++
 
   fprintf(stderr, "The %s is %3d\n", description.c_str(), value);
 
-into::
+into:
 
 .. code-block:: c++
 
   std::println(stderr, "The {} is {:3}", description, value);
 
-It doesn't do a bad job, but it's not perfect. In particular:
+If the `ReplacementPrintFunction` or `ReplacementPrintlnFunction` options
+are left, or assigned to their default values then this check is only
+enabled with `-std=c++23` or later.
+
+The check doesn't do a bad job, but it's not perfect. In particular:
 
 - It assumes that the format string is correct for the arguments. If you
   get any warnings when compiling with `-Wformat` then misbehaviour is
@@ -35,7 +39,7 @@
   handled. Although it's possible for the check to automatically put the
   escapes back, they may not be exactly as they were written (e.g.
   ``"\x0a"`` will become ``"\n"`` and ``"ab" "cd"`` will become
-  ``"abcd"``.) This is helpful since it means that the PRIx macros from
+  ``"abcd"``.) This is helpful since it means that the ``PRIx`` macros from
    are removed correctly.
 
 - It supports field widths, precision, positional arguments, leading zeros,
@@ -78,7 +82,7 @@
   signedness will be wrapped in an approprate ``static_cast`` if `StrictMode`
   is enabled.
 - any arguments that end in a call to ``std::string::c_str()`` or
-  ``std::string_data()`` will have that call removed.
+  ``std::string::data()`` will have that call removed.
 
 Options
 ---
@@ -99,7 +103,7 @@
 unsigned int u = 0x;
 printf("%d %u\n", i, u);
 
-  would be converted to::
+  would be converted to:
 
   .. code-block:: c++
 


Index: clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst
+++ clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst
@@ -9,21 +9,25 @@
 The replaced and replacement functions can be customised by configuration
 options. Each argument that is the result of a call to ``std::string::c_str()`` and
 ``std::string::data()`` will have that now-unnecessary call removed in a
-similar manner to the readability-redundant-string-cstr check.
+similar manner to the `readability-redundant-string-cstr` check.
 
-In other words, it turns lines like::
+In other words, it turns lines like:
 
 .. code-block:: c++
 
   fprintf(stderr, "The %s is %3d\n", description.c_str(), value);
 
-into::
+into:
 
 .. code-block:: c++
 
   std::println(stderr, "The {} is {:3}", description, value);
 
-It doesn't do a bad job, but it's not perfect. In particular:
+If the `ReplacementPrintFunction` or `ReplacementPrintlnFunction` options
+are left, or assigned to their default values then this check is only
+enabled with `-std=c++23` or later.
+
+The check doesn't do a bad job, but it's not perfect. In particular:
 
 - It assumes that the format string is correct for the arguments. If you
   get any warnings when compiling with `-Wformat` then misbehaviour is
@@ -35,7 +39,7 @@
   handled. Although it's possible for the check to automatically put the
   escapes back, they may not be exactly as they were written (e.g.
   ``"\x0a"`` will become ``"\n"`` and ``"ab" "cd"`` will become
-  ``"abcd"``.) This is helpful since it means that the PRIx macros from
+  ``"abcd"``.) This is helpful since it means that the ``PRIx`` macros from
    are remo

[PATCH] D149280: [clang-tidy] Add modernize-printf-to-std-print check

2023-05-20 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added inline comments.



Comment at: 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst:79
+
+.. option:: StrictMode
+

It turns out that absl::PrintF and absl::FPrintF work like std::format, 
fmt::printf, etc. and use the signedness of the argument rather than the 
signedness indicated in the format string to determine how to format the 
number. In other words:
`unsigned int ui = 0x; absl::PrintF("%d\n", ui);` yields `4294967295` 
(see https://godbolt.org/z/dYcbehxP9 ), so the casts that StrictMode adds would 
change the behaviour of the converted code.

I can think of several ways around this:

1. Update the documentation to explain this, recommending not to use StrictMode 
when converting Abseil functions.

2. Remove built-in support for Abseil functions from this check. Anyone wishing 
to convert them can do so via the customisation features, and can choose not to 
use StrictMode. (This could be documented here.)

3. Teach the code to recognise whether the arguments is being passed as a 
C-style variable argument list or as fully-typed arguments to a templated 
function and make StrictMode only add the casts for the former. (I've not 
investigated how feasible this is.)

4. Treat the known Abseil functions in this check differently by name and 
disable the casting behaviour. This means that conversion from fmt::printf via 
the customisation mechanism wouldn't automatically get that behaviour.

As someone who doesn't use Abseil I'm inclined towards option 2, with the 
possibility of implementing option 3 in a separate commit later. I'm not 
particularly keen on the other two options.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D149280/new/

https://reviews.llvm.org/D149280

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D150602: [clang-tidy] Move formatDereference to FixitHintUtils

2023-05-23 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe marked an inline comment as done.
mikecrowe added a comment.

Thanks for the review. New version with the `static` added coming shortly.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D150602/new/

https://reviews.llvm.org/D150602

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D150602: [clang-tidy] Move formatDereference to FixitHintUtils

2023-05-23 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 524815.
mikecrowe added a comment.

Make needParensAfterUnaryOperator static


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D150602/new/

https://reviews.llvm.org/D150602

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
  clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp
  clang-tools-extra/clang-tidy/utils/FixItHintUtils.h

Index: clang-tools-extra/clang-tidy/utils/FixItHintUtils.h
===
--- clang-tools-extra/clang-tidy/utils/FixItHintUtils.h
+++ clang-tools-extra/clang-tidy/utils/FixItHintUtils.h
@@ -44,6 +44,9 @@
   DeclSpec::TQ Qualifier,
   QualifierTarget CT = QualifierTarget::Pointee,
   QualifierPolicy CP = QualifierPolicy::Left);
+
+// \brief Format a pointer to an expression
+std::string formatDereference(const Expr &ExprNode, const ASTContext &Context);
 } // namespace clang::tidy::utils::fixit
 
 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_FIXITHINTUTILS_H
Index: clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp
===
--- clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp
+++ clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp
@@ -9,7 +9,9 @@
 #include "FixItHintUtils.h"
 #include "LexerUtils.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ExprCXX.h"
 #include "clang/AST/Type.h"
+#include "clang/Tooling/FixIt.h"
 #include 
 
 namespace clang::tidy::utils::fixit {
@@ -221,4 +223,46 @@
 
   return std::nullopt;
 }
+
+// Return true if expr needs to be put in parens when it is an argument of a
+// prefix unary operator, e.g. when it is a binary or ternary operator
+// syntactically.
+static bool needParensAfterUnaryOperator(const Expr &ExprNode) {
+  if (isa(&ExprNode) ||
+  isa(&ExprNode)) {
+return true;
+  }
+  if (const auto *Op = dyn_cast(&ExprNode)) {
+return Op->getNumArgs() == 2 && Op->getOperator() != OO_PlusPlus &&
+   Op->getOperator() != OO_MinusMinus && Op->getOperator() != OO_Call &&
+   Op->getOperator() != OO_Subscript;
+  }
+  return false;
+}
+
+// Format a pointer to an expression: prefix with '*' but simplify
+// when it already begins with '&'.  Return empty string on failure.
+std::string formatDereference(const Expr &ExprNode, const ASTContext &Context) {
+  if (const auto *Op = dyn_cast(&ExprNode)) {
+if (Op->getOpcode() == UO_AddrOf) {
+  // Strip leading '&'.
+  return std::string(
+  tooling::fixit::getText(*Op->getSubExpr()->IgnoreParens(), Context));
+}
+  }
+  StringRef Text = tooling::fixit::getText(ExprNode, Context);
+
+  if (Text.empty())
+return std::string();
+
+  // Remove remaining '->' from overloaded operator call
+  Text.consume_back("->");
+
+  // Add leading '*'.
+  if (needParensAfterUnaryOperator(ExprNode)) {
+return (llvm::Twine("*(") + Text + ")").str();
+  }
+  return (llvm::Twine("*") + Text).str();
+}
+
 } // namespace clang::tidy::utils::fixit
Index: clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
@@ -11,6 +11,7 @@
 //===--===//
 
 #include "RedundantStringCStrCheck.h"
+#include "../utils/FixItHintUtils.h"
 #include "../utils/Matchers.h"
 #include "../utils/OptionsUtils.h"
 #include "clang/Lex/Lexer.h"
@@ -22,49 +23,6 @@
 
 namespace {
 
-// Return true if expr needs to be put in parens when it is an argument of a
-// prefix unary operator, e.g. when it is a binary or ternary operator
-// syntactically.
-bool needParensAfterUnaryOperator(const Expr &ExprNode) {
-  if (isa(&ExprNode) ||
-  isa(&ExprNode)) {
-return true;
-  }
-  if (const auto *Op = dyn_cast(&ExprNode)) {
-return Op->getNumArgs() == 2 && Op->getOperator() != OO_PlusPlus &&
-   Op->getOperator() != OO_MinusMinus && Op->getOperator() != OO_Call &&
-   Op->getOperator() != OO_Subscript;
-  }
-  return false;
-}
-
-// Format a pointer to an expression: prefix with '*' but simplify
-// when it already begins with '&'.  Return empty string on failure.
-std::string
-formatDereference(const ast_matchers::MatchFinder::MatchResult &Result,
-  const Expr &ExprNode) {
-  if (const auto *Op = dyn_cast(&ExprNode)) {
-if (Op->getOpcode() == UO_AddrOf) {
-  // Strip leading '&'.
-  return std::string(tooling::fixit::getText(
-  *Op->getSubExpr()->IgnoreParens(), *Result.Context));
-}
-  }
-  StringRef Text = tooling::fixit::getText(ExprNode, *Result.Context);
-
-  if (Text.empty())
-return std::string();
-
-  // Remove remaining '->' from ove

[PATCH] D149280: [clang-tidy] Add modernize-printf-to-std-print check

2023-05-31 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added inline comments.



Comment at: 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst:79
+
+.. option:: StrictMode
+

mikecrowe wrote:
> It turns out that absl::PrintF and absl::FPrintF work like std::format, 
> fmt::printf, etc. and use the signedness of the argument rather than the 
> signedness indicated in the format string to determine how to format the 
> number. In other words:
> `unsigned int ui = 0x; absl::PrintF("%d\n", ui);` yields `4294967295` 
> (see https://godbolt.org/z/dYcbehxP9 ), so the casts that StrictMode adds 
> would change the behaviour of the converted code.
> 
> I can think of several ways around this:
> 
> 1. Update the documentation to explain this, recommending not to use 
> StrictMode when converting Abseil functions.
> 
> 2. Remove built-in support for Abseil functions from this check. Anyone 
> wishing to convert them can do so via the customisation features, and can 
> choose not to use StrictMode. (This could be documented here.)
> 
> 3. Teach the code to recognise whether the arguments is being passed as a 
> C-style variable argument list or as fully-typed arguments to a templated 
> function and make StrictMode only add the casts for the former. (I've not 
> investigated how feasible this is.)
> 
> 4. Treat the known Abseil functions in this check differently by name and 
> disable the casting behaviour. This means that conversion from fmt::printf 
> via the customisation mechanism wouldn't automatically get that behaviour.
> 
> As someone who doesn't use Abseil I'm inclined towards option 2, with the 
> possibility of implementing option 3 in a separate commit later. I'm not 
> particularly keen on the other two options.
It turns out that option 3 was easier to implement than I expected, so I've 
implemented it in the latest version.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D149280/new/

https://reviews.llvm.org/D149280

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-02-10 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp:188
+  callee(functionDecl(hasName("::std::format",
+hasAnyArgument(materializeTemporaryExpr(
+has(StringCStrCallExpr),

njames93 wrote:
> The limitation about only transforming the first argument can be alleviated 
> by using the `forEachArgumentWithParam` matcher
Thanks for the hint. I did try to overcome this limitation but failed to find 
`forEachArgumentWithParam`.

I think that I've managed to make `forEachArgumentWithParam` work, but only if 
I lose the `materializeTemporaryExpr`. I hope that's not essential. I've ended 
up with:

```C++
  Finder->addMatcher(   

   
traverse(TK_AsIs,   

   
 callExpr(callee(functionDecl(hasAnyName("::std::print", 
"::std::format"))), 
  
  forEachArgumentWithParam(StringCStrCallExpr, 
parmVarDecl(,   

this);  

   
```
I suspect that there's something better than the `parmVarDecl()` second 
parameter to `forEachArgumentWithParam` though.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D143342/new/

https://reviews.llvm.org/D143342

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-02-12 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp:188
+  callee(functionDecl(hasName("::std::format",
+hasAnyArgument(materializeTemporaryExpr(
+has(StringCStrCallExpr),

njames93 wrote:
> mikecrowe wrote:
> > njames93 wrote:
> > > The limitation about only transforming the first argument can be 
> > > alleviated by using the `forEachArgumentWithParam` matcher
> > Thanks for the hint. I did try to overcome this limitation but failed to 
> > find `forEachArgumentWithParam`.
> > 
> > I think that I've managed to make `forEachArgumentWithParam` work, but only 
> > if I lose the `materializeTemporaryExpr`. I hope that's not essential. I've 
> > ended up with:
> > 
> > ```C++
> >   Finder->addMatcher(   
> > 
> >
> > traverse(TK_AsIs,   
> > 
> >
> >  callExpr(callee(functionDecl(hasAnyName("::std::print", 
> > "::std::format"))), 
> >   
> >   forEachArgumentWithParam(StringCStrCallExpr, 
> > parmVarDecl(,   
> > 
> > this);  
> > 
> >
> > ```
> > I suspect that there's something better than the `parmVarDecl()` second 
> > parameter to `forEachArgumentWithParam` though.
> `parmVarDecl` is exactly what you need here.
> 
> My understanding of the temporary expressions isn't perfect, but from what I 
> can gather, we shouldn't need temporaries when calling the `.c_str()`method 
> for all but the first argument.
> 
> This does highlight an issue with your test code though.
> `std::format` and `std::print` take a `std::format_string` as the first 
> argument, but in your tests you have it as `const char *`
> Anyway I think this means the first argument in real world code would result 
> in a `materializeTemporaryExpr`
> See [[ https://en.cppreference.com/w/cpp/utility/format/basic_format_string | 
> here ]]
I mentioned that I'd failed to use a genuine type for the first parameter in my 
commit message. However, I've now tried again, and I think that I've got 
something working that is much closer to that required by the standard.

I tried to come up with something that I could call `c_str()` on to pass as the 
first argument, but couldn't come up with anything that g++ thought was a 
constant expression. I tried:
```
consteval std::string f()   

 {  


  
return {"Hi {}"};   

 
}   

 

std::puts(std::format(f().c_str(), get().c_str());  

 
```
but g++ still claims:
```
format.cpp:22:28: error: 
‘std::string{std::__cxx11::basic_string::_Alloc_hider{((char*)(&.std::__cxx11::basic_string::.std::__cxx11::basic_string_M_local_buf))}, 5, std::__cxx11::basic_string::{char [16]{'H', 'i', ' ', '{', '}', 0, '\000', '\000', '\000', '\000', 
'\000', '\000', '\000', '\000', '\000', '\000'}}}’ is not a constant expression
   22 | std::puts(std::format(f().c_str(), get().c_str());
  |   ~^~
```
So I think that the risk of inadvertently removing `c_str()` from the first 
argument is low, given that such a call appears not to be legal anyway. Even if 
there does turn out to be a way to do so, I think that removing the `c_str()` 
call probably ought to be expected to work too.


CHANGES SINCE LAST ACTION
 

[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-02-12 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 496758.
mikecrowe added a comment.

Incorporate feedback from Nathan James:

- Simplify callExpr pattern in matcher.
- Use `forEachArgumentWithParam` so that check works on all arguments and 
remove mentions of previous limitation in commit message and documentation.
- Make lit test use closer approximation to standard first argument for 
`std::format` and `std::print` rather than `const char *`.
- Add wide-character string tests.
- Other minor improvements to tests.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D143342/new/

https://reviews.llvm.org/D143342

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s readability-redundant-string-cstr %t
+// RUN: %check_clang_tidy -std=c++20 %s readability-redundant-string-cstr %t
 
 typedef unsigned __INT16_TYPE__ char16;
 typedef unsigned __INT32_TYPE__ char32;
@@ -51,7 +51,8 @@
 
 template 
 struct basic_string_view {
-  basic_string_view(const C* s);
+  const C *str;
+  constexpr basic_string_view(const C* s) : str(s) {}
 };
 typedef basic_string_view> string_view;
 typedef basic_string_view> wstring_view;
@@ -291,3 +292,199 @@
   Foo.func2((Str.c_str()));
 }
 } // namespace PR45286
+
+namespace std {
+  template
+struct type_identity { using type = T; };
+  template
+using type_identity_t = typename type_identity::type;
+
+  template 
+  struct basic_format_string {
+consteval basic_format_string(const CharT *format) : str(format) {}
+basic_string_view> str;
+  };
+
+  template
+using format_string = basic_format_string...>;
+
+  template
+using wformat_string = basic_format_string...>;
+
+  template
+  void print(format_string, Args &&...);
+  template
+  void print(wformat_string, Args &&...);
+
+  template
+  std::string format(format_string, Args &&...);
+  template
+  std::string format(wformat_string, Args &&...);
+}
+
+namespace notstd {
+  template
+  void print(const char *, Args &&...);
+  template
+  void print(const wchar_t *, Args &&...);
+  template
+  std::string format(const char *, Args &&...);
+  template
+  std::string format(const wchar_t *, Args &&...);
+}
+
+std::string return_temporary();
+std::wstring return_wtemporary();
+
+void std_print(const std::string &s1, const std::string &s2, const std::string &s3) {
+  std::print("One:{}\n", s1.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}std::print("One:{}\n", s1);
+
+  std::print("One:{} Two:{} Three:{} Four:{}\n", s1.c_str(), s2, s3.c_str(), return_temporary().c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:50: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-2]]:66: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-3]]:78: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}std::print("One:{} Two:{} Three:{} Four:{}\n", s1, s2, s3, return_temporary());
+
+  using namespace std;
+  print("Four:{}\n", s1.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}print("Four:{}\n", s1);
+}
+
+void std_print_wide(const std::wstring &s1, const std::wstring &s2, const std::wstring &s3) {
+  std::print(L"One:{}\n", s1.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}std::print(L"One:{}\n", s1);
+
+  std::print(L"One:{} Two:{} Three:{} Four:{}\n", s1.c_str(), s2, s3.c_str(), return_wtemporary().c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:51: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-2]]:67: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES: :[[@LINE-3]]:79: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}std::print(L"One:{} Two:{} Three:{} Four:{}\n", s1, s2, s3, return_wtemporary());
+
+  using namespace std;
+  print(L"Four:{}\n", s1.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}print(L"Four:{}\n", s1);
+}
+
+// There's no c_str() call here, so it shouldn't be touched.
+void std_print_no_cstr(const std::string &s1, const std::string &s2

[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-02-15 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

Thanks for the review and further suggestions.

Mike.




Comment at: 
clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp:181-190
+
+  // Detect redundant 'c_str()' calls in parameters passed to std::print and
+  // std::format.
+  Finder->addMatcher(
+  traverse(
+  TK_AsIs,
+  callExpr(

njames93 wrote:
> Can this be wrapped in a check to make sure it only runs in c++20
> 
> Likewise `::std::print` is only c++23, so maybe:
> ```lang=c++
> getLangOpts().CPlusPlus2B ? hasAnyName("::std::print", "::std::format") : 
> hasAnyName("::std::format")
> ```
I can do that. I had (presumably incorrectly) assumed that since and use of 
`std::print` and `std::format` in any previous version would be UB then it was 
safe to apply the check regardless of the C++ version.



Comment at: 
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp:1
-// RUN: %check_clang_tidy %s readability-redundant-string-cstr %t
+// RUN: %check_clang_tidy -std=c++20 %s readability-redundant-string-cstr %t
 

njames93 wrote:
> We shouldn't be removing tests from older language standards
> Can all the changes made to the file be moved into a new file 
> `redundant-string-cstr-cpp20.cpp`
> Would likely either need to create a second file for c++23 or make use of the 
> check-suffix to run the tests for std::print
My brief reading up on check-suffix implies that it could be used to keep 
everything in `redundant-string-cstr.cpp`, but that file is getting rather 
large anyway. Having `redundant-string-cstr-cpp20.cpp` also containing C++23 
tests might be a bit confusing. Having `redundant-string-cstr-cpp23.cpp` too 
would mean moving the format_args stuff to a header (which might be beneficial 
regardless.)

Anyway, I shall have a play and see what I can make work.

Do I need to add tests to ensure that the checks don't trigger when running 
against earlier standard versions?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D143342/new/

https://reviews.llvm.org/D143342

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D144216: [clang-tidy] Extract string header from redundant-string-cstr checker

2023-02-16 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe created this revision.
mikecrowe added a reviewer: njames93.
Herald added a subscriber: xazax.hun.
Herald added a project: All.
mikecrowe requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

In preparation for using the implementation of basic_string and
basic_string_view from redundant-string-cstr.cpp in other checks, let's
extract it to a header.


https://reviews.llvm.org/D144216

Files:
  clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
  
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp
@@ -1,71 +1,5 @@
-// RUN: %check_clang_tidy %s readability-redundant-string-cstr %t
-
-typedef unsigned __INT16_TYPE__ char16;
-typedef unsigned __INT32_TYPE__ char32;
-typedef __SIZE_TYPE__ size;
-
-namespace std {
-template 
-class allocator {};
-template 
-class char_traits {};
-template 
-struct basic_string {
-  typedef basic_string _Type;
-  basic_string();
-  basic_string(const C *p, const A &a = A());
-
-  ~basic_string();
-
-  const C *c_str() const;
-  const C *data() const;
-
-  _Type& append(const C *s);
-  _Type& append(const C *s, size n);
-  _Type& assign(const C *s);
-  _Type& assign(const C *s, size n);
-
-  int compare(const _Type&) const;
-  int compare(const C* s) const;
-  int compare(size pos, size len, const _Type&) const;
-  int compare(size pos, size len, const C* s) const;
-
-  size find(const _Type& str, size pos = 0) const;
-  size find(const C* s, size pos = 0) const;
-  size find(const C* s, size pos, size n) const;
-
-  _Type& insert(size pos, const _Type& str);
-  _Type& insert(size pos, const C* s);
-  _Type& insert(size pos, const C* s, size n);
-
-  _Type& operator+=(const _Type& str);
-  _Type& operator+=(const C* s);
-  _Type& operator=(const _Type& str);
-  _Type& operator=(const C* s);
-};
-
-typedef basic_string, std::allocator> string;
-typedef basic_string, std::allocator> wstring;
-typedef basic_string, std::allocator> u16string;
-typedef basic_string, std::allocator> u32string;
-
-template 
-struct basic_string_view {
-  basic_string_view(const C* s);
-};
-typedef basic_string_view> string_view;
-typedef basic_string_view> wstring_view;
-typedef basic_string_view> u16string_view;
-typedef basic_string_view> u32string_view;
-}
-
-std::string operator+(const std::string&, const std::string&);
-std::string operator+(const std::string&, const char*);
-std::string operator+(const char*, const std::string&);
-
-bool operator==(const std::string&, const std::string&);
-bool operator==(const std::string&, const char*);
-bool operator==(const char*, const std::string&);
+// RUN: %check_clang_tidy %s readability-redundant-string-cstr %t -- -- -isystem %clang_tidy_headers
+#include 
 
 namespace llvm {
 struct StringRef {
Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
@@ -0,0 +1,71 @@
+#ifndef _STRING_
+#define _STRING_
+
+typedef unsigned __INT16_TYPE__ char16;
+typedef unsigned __INT32_TYPE__ char32;
+typedef __SIZE_TYPE__ size;
+
+namespace std {
+template 
+class allocator {};
+template 
+class char_traits {};
+template 
+struct basic_string {
+  typedef basic_string _Type;
+  basic_string();
+  basic_string(const C *p, const A &a = A());
+
+  ~basic_string();
+
+  const C *c_str() const;
+  const C *data() const;
+
+  _Type& append(const C *s);
+  _Type& append(const C *s, size n);
+  _Type& assign(const C *s);
+  _Type& assign(const C *s, size n);
+
+  int compare(const _Type&) const;
+  int compare(const C* s) const;
+  int compare(size pos, size len, const _Type&) const;
+  int compare(size pos, size len, const C* s) const;
+
+  size find(const _Type& str, size pos = 0) const;
+  size find(const C* s, size pos = 0) const;
+  size find(const C* s, size pos, size n) const;
+
+  _Type& insert(size pos, const _Type& str);
+  _Type& insert(size pos, const C* s);
+  _Type& insert(size pos, const C* s, size n);
+
+  _Type& operator+=(const _Type& str);
+  _Type& operator+=(const C* s);
+  _Type& operator=(const _Type& str);
+  _Type& operator=(const C* s);
+};
+
+typedef basic_string, std::allocator> string;
+typedef basic_string, std::allocator> wstring;
+typedef basic_string, std::allocator> u16string;
+typedef basic_string, std::allocator> u32string;
+
+template 
+struct basic_string_view {
+  basic_string_view(const C* s);
+};
+typedef basic_string_view> string_view;
+typedef basic_string_view> wstring_view;
+typedef basic_string_view> u16string_view;
+typedef basic_

[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-02-16 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe updated this revision to Diff 498136.
mikecrowe edited the summary of this revision.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D143342/new/

https://reviews.llvm.org/D143342

Files:
  clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string
  
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-format.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-format.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-format.cpp
@@ -0,0 +1,214 @@
+// RUN: %check_clang_tidy -check-suffix=STDFORMAT -std=c++20 %s readability-redundant-string-cstr %t -- --  -isystem %clang_tidy_headers -DTEST_STDFORMAT
+// RUN: %check_clang_tidy -check-suffixes=STDFORMAT,STDPRINT -std=c++2b %s readability-redundant-string-cstr %t -- --  -isystem %clang_tidy_headers -DTEST_STDFORMAT -DTEST_STDPRINT
+#include 
+
+namespace std {
+  template
+struct type_identity { using type = T; };
+  template
+using type_identity_t = typename type_identity::type;
+
+  template 
+  struct basic_format_string {
+consteval basic_format_string(const CharT *format) : str(format) {}
+basic_string_view> str;
+  };
+
+  template
+using format_string = basic_format_string...>;
+
+  template
+using wformat_string = basic_format_string...>;
+
+#if defined(TEST_STDFORMAT)
+  template
+  std::string format(format_string, Args &&...);
+  template
+  std::string format(wformat_string, Args &&...);
+#endif // TEST_STDFORMAT
+
+#if defined(TEST_STDPRINT)
+  template
+  void print(format_string, Args &&...);
+  template
+  void print(wformat_string, Args &&...);
+#endif // TEST_STDPRINT
+}
+
+namespace notstd {
+#if defined(TEST_STDFORMAT)
+  template
+  std::string format(const char *, Args &&...);
+  template
+  std::string format(const wchar_t *, Args &&...);
+#endif // TEST_STDFORMAT
+#if defined(TEST_STDPRINT)
+  template
+  void print(const char *, Args &&...);
+  template
+  void print(const wchar_t *, Args &&...);
+#endif // TEST_STDPRINT
+}
+
+std::string return_temporary();
+std::wstring return_wtemporary();
+
+#if defined(TEST_STDFORMAT)
+void std_format(const std::string &s1, const std::string &s2, const std::string &s3) {
+  auto r1 = std::format("One:{}\n", s1.c_str());
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:37: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES-STDFORMAT: {{^  }}auto r1 = std::format("One:{}\n", s1);
+
+  auto r2 = std::format("One:{} Two:{} Three:{} Four:{}\n", s1.c_str(), s2, s3.c_str(), return_temporary().c_str());
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:61: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-2]]:77: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-3]]:89: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES-STDFORMAT: {{^  }}auto r2 = std::format("One:{} Two:{} Three:{} Four:{}\n", s1, s2, s3, return_temporary());
+
+  using namespace std;
+  auto r3 = format("Four:{}\n", s1.c_str());
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:33: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES-STDFORMAT: {{^  }}auto r3 = format("Four:{}\n", s1);
+}
+
+void std_format_wide(const std::wstring &s1, const std::wstring &s2, const std::wstring &s3) {
+  auto r1 = std::format(L"One:{}\n", s1.c_str());
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:38: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES-STDFORMAT: {{^  }}auto r1 = std::format(L"One:{}\n", s1);
+
+  auto r2 = std::format(L"One:{} Two:{} Three:{} Four:{}\n", s1.c_str(), s2, s3.c_str(), return_wtemporary().c_str());
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:62: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-2]]:78: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-3]]:90: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES-STDFORMAT: {{^  }}auto r2 = std::format(L"One:{} Two:{} Three:{} Four:{}\n", s1, s2, s3, return_wtemporary());
+
+  using namespace std;
+  auto r3 = format(L"Four:{}\n", s1.c_str());
+  // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:34: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+  // CHECK-FIXES-STDFORMAT: {{^  }}auto r3 = format(L"Four:{}\n", s1);
+}
+
+// There's are c_str() calls here, so it shouldn't be touched.
+std::string std_format_no_cstr(const std::string &s1, const std::string &s2) {
+  return std::format("One: {}, Two: {}\n", s1, s2);
+}
+

[PATCH] D143342: [clang-tidy] Support std::format and std::print in readability-redundant-string-cstr

2023-02-16 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe marked 2 inline comments as done.
mikecrowe added a comment.

I ended up splitting out the std::format and std::print tests to their own file 
which meant that I didn't need to modify the existing 
`redundant-string-cstr.cpp` file in this commit. (Though of course I had to 
extract the  header in D144216  
first.) Let me know if you don't like the split.

I also slightly re-ordered the tests and removed a few incorrect comments that 
incorrectly survived the switch to using `forEachArgumentWithParam`.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D143342/new/

https://reviews.llvm.org/D143342

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D144216: [clang-tidy] Extract string header from redundant-string-cstr checker

2023-02-17 Thread Mike Crowe via Phabricator via cfe-commits
mikecrowe added a comment.

In D144216#4133671 , @Eugene.Zelenko 
wrote:

> May be you could use heard in other test in same patch?

I'm not quite sure what you mean by "heard". Searching for "heard" in the LLVM 
code and Googling "llvm heard" reveal nothing useful. Please can you explain 
what you mean?

If you're suggesting that I could use the new `` header to replace 
declarations of `basic_string` etc. in other tests then I think that would be 
possible with some careful checking to make sure it include the necessary 
functionality. I think that would easier to review separately rather than in a 
single patch though.




Comment at: 
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr.cpp:1
-// RUN: %check_clang_tidy %s readability-redundant-string-cstr %t
-
-typedef unsigned __INT16_TYPE__ char16;
-typedef unsigned __INT32_TYPE__ char32;
-typedef __SIZE_TYPE__ size;
-
-namespace std {
-template 
-class allocator {};
-template 
-class char_traits {};
-template 
-struct basic_string {
-  typedef basic_string _Type;
-  basic_string();
-  basic_string(const C *p, const A &a = A());
-
-  ~basic_string();
-
-  const C *c_str() const;
-  const C *data() const;
-
-  _Type& append(const C *s);
-  _Type& append(const C *s, size n);
-  _Type& assign(const C *s);
-  _Type& assign(const C *s, size n);
-
-  int compare(const _Type&) const;
-  int compare(const C* s) const;
-  int compare(size pos, size len, const _Type&) const;
-  int compare(size pos, size len, const C* s) const;
-
-  size find(const _Type& str, size pos = 0) const;
-  size find(const C* s, size pos = 0) const;
-  size find(const C* s, size pos, size n) const;
-
-  _Type& insert(size pos, const _Type& str);
-  _Type& insert(size pos, const C* s);
-  _Type& insert(size pos, const C* s, size n);
-
-  _Type& operator+=(const _Type& str);
-  _Type& operator+=(const C* s);
-  _Type& operator=(const _Type& str);
-  _Type& operator=(const C* s);
-};
-
-typedef basic_string, std::allocator> 
string;
-typedef basic_string, 
std::allocator> wstring;
-typedef basic_string, std::allocator> 
u16string;
-typedef basic_string, std::allocator> 
u32string;
-
-template 
-struct basic_string_view {
-  basic_string_view(const C* s);
-};
-typedef basic_string_view> string_view;
-typedef basic_string_view> wstring_view;
-typedef basic_string_view> u16string_view;
-typedef basic_string_view> u32string_view;
-}
-
-std::string operator+(const std::string&, const std::string&);
-std::string operator+(const std::string&, const char*);
-std::string operator+(const char*, const std::string&);
-
-bool operator==(const std::string&, const std::string&);
-bool operator==(const std::string&, const char*);
-bool operator==(const char*, const std::string&);
+// RUN: %check_clang_tidy %s readability-redundant-string-cstr %t -- -- 
-isystem %clang_tidy_headers
+#include 

carlosgalvezp wrote:
> Where does this come from? Other tests use the actual path to the folder.
I copied it from other checks:
```
clang-tools-extra/test/clang-tidy/checkers/bugprone/signal-handler-minimal.c:// 
RUN: -- -isystem %clang_tidy_headers
clang-tools-extra/test/clang-tidy/checkers/bugprone/signal-handler-posix.c:// 
RUN: -- -isystem %clang_tidy_headers
clang-tools-extra/test/clang-tidy/checkers/bugprone/signal-handler.c:// RUN: 
%check_clang_tidy %s bugprone-signal-handler %t -- -- -isystem 
%clang_tidy_headers
clang-tools-extra/test/clang-tidy/checkers/bugprone/signal-handler.cpp:// RUN: 
%check_clang_tidy -std=c++14 %s bugprone-signal-handler %t -- -- -isystem 
%clang_tidy_headers -isystem %S/Inputs/signal-handler -target 
x86_64-unknown-unknown
clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-include.cpp:// 
RUN: %check_clang_tidy %s bugprone-suspicious-include %t -- -- -isystem 
%clang_tidy_headers -fmodules
clang-tools-extra/test/clang-tidy/checkers/google/objc-function-naming.m:// 
RUN: %check_clang_tidy %s google-objc-function-naming %t -- -- -isystem 
%clang_tidy_headers
clang-tools-extra/test/clang-tidy/checkers/llvm/include-order.cpp:// RUN: 
%check_clang_tidy %s llvm-include-order %t -- -- -isystem %clang_tidy_headers
clang-tools-extra/test/clang-tidy/checkers/modernize/pass-by-value-macro-header.cpp://
 RUN: %check_clang_tidy %s modernize-pass-by-value %t -- -- -isystem 
%clang_tidy_headers
clang-tools-extra/test/clang-tidy/checkers/performance/move-constructor-init.cpp://
 RUN: -- -isystem %clang_tidy_headers
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-format.cpp://
 RUN: %check_clang_tidy -check-suffix=STDFORMAT -std=c++20 %s 
readability-redundant-string-cstr %t -- --  -isystem %clang_tidy_headers 
-DTEST_STDFORMAT
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-format.cpp://
 RUN: %check_clang_tidy -check-suffixes=STDFORMAT,STDPRINT -std=c++2b %s 
readability-redundant-string-cstr %t -- --  -isystem %clang_tidy_heade

  1   2   >