ziqingluo-90 created this revision.
ziqingluo-90 added reviewers: jkorous, NoQ, malavikasamak, t-rasmud.
Herald added a subscriber: jdoerfert.
Herald added a project: All.
ziqingluo-90 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

For fix-its that insert `[[clang::unsafe_buffer_usage]]` attributes,  they will 
lookup existing macros defined for `[[clang::unsafe_buffer_usage]]` and use the 
(last defined such) macro directly.  Fix-its will use raw 
`[[clang::unsafe_buffer_usage]]` if no such macro is defined.

For example,

  // Suppose `foo` uses `p` in an unsafe way...
  
  void foo(int *p); // A fix-it will insert "[[clang::unsafe_buffer_usage]] " 
right before the declaration as there is no macro for the attribute defined here
  
  #define MACRO [[clang::unsafe_buffer_usage]]
  
  void foo(int *p); // A fix-it will insert "MACRO " right before the 
declaration

The implementation mimics how a similar machine for the  `[[fallthrough]]` 
attribute was implemented. (Mentioned here 
https://reviews.llvm.org/D143048#inline-1435398 )


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D150338

Files:
  clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
  clang/lib/Analysis/UnsafeBufferUsage.cpp
  clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-attributes-spelling.cpp
  
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-include-header/warn-unsafe-buffer-usage-fixits-header-exists.cpp
  
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-include-header/warn-unsafe-buffer-usage-fixits-parm-in-header.cpp
  clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span-overload.cpp
  
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span-qualified-names.cpp
  clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span.cpp
  clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp

Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp
@@ -8,7 +8,7 @@
   // FIXME: the fix-it above is incorrect
   int tmp = x[5]; // expected-note{{used in buffer access here}}
 }
-// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\nvoid const_ptr(int * const x) {return const_ptr(std::span<int>(x, <# size #>));}\n"
+// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void const_ptr(int * const x) {return const_ptr(std::span<int>(x, <# size #>));}\n"
 // FIXME: the fix-it above is incorrect
 
 void const_ptr_to_const(const int * const x) {// expected-warning{{'x' is an unsafe pointer used for buffer access}} expected-note{{change type of 'x' to 'std::span' to preserve bounds information}}
@@ -16,7 +16,7 @@
   // FIXME: the fix-it above is incorrect
   int tmp = x[5]; // expected-note{{used in buffer access here}}
 }
-// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\nvoid const_ptr_to_const(const int * const x) {return const_ptr_to_const(std::span<const int>(x, <# size #>));}\n"
+// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void const_ptr_to_const(const int * const x) {return const_ptr_to_const(std::span<const int>(x, <# size #>));}\n"
 // FIXME: the fix-it above is incorrect
 
 // We do not fix parameters participating unsafe operations for the
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span.cpp
@@ -11,13 +11,13 @@
 void f();
 
 void simple(int *p);
-// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\n"
+// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} "
 // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-2]]:20-[[@LINE-2]]:20}:";\nvoid simple(std::span<int> p)"
 
 #else
 
 void simple(int *);
-// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\n"
+// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} "
 // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-2]]:19-[[@LINE-2]]:19}:";\nvoid simple(std::span<int>)"
 
 void simple(int *p) {
@@ -25,7 +25,7 @@
   int tmp;
   tmp = p[5];
 }
-// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\nvoid simple(int *p) {return simple(std::span<int>(p, <# size #>));}\n"
+// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void simple(int *p) {return simple(std::span<int>(p, <# size #>));}\n"
 
 
 void twoParms(int *p, int * q) {
@@ -34,21 +34,21 @@
   int tmp;
   tmp = p[5] + q[5];
 }
-// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\nvoid twoParms(int *p, int * q) {return twoParms(std::span<int>(p, <# size #>), q);}\n"
-// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-2]]:2-[[@LINE-2]]:2}:"\n#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\nvoid twoParms(int *p, int * q) {return twoParms(p, std::span<int>(q, <# size #>));}\n"
+// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void twoParms(int *p, int * q) {return twoParms(std::span<int>(p, <# size #>), q);}\n"
+// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-2]]:2-[[@LINE-2]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void twoParms(int *p, int * q) {return twoParms(p, std::span<int>(q, <# size #>));}\n"
 
 void decayedArrayParm(int arr[]) {
   // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:23-[[@LINE-1]]:32}:"std::span<int> arr"
   int tmp;
   tmp = arr[5];
 }
-// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\nvoid decayedArrayParm(int arr[]) {return decayedArrayParm(std::span<int>(arr, <# size #>));}\n"
+// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void decayedArrayParm(int arr[]) {return decayedArrayParm(std::span<int>(arr, <# size #>));}\n"
 
 
 void ptrToConst(const int * x) {
   // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:30}:"std::span<const int> x"
   int tmp = x[5];
 }
-// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\nvoid ptrToConst(const int * x) {return ptrToConst(std::span<const int>(x, <# size #>));}\n"
+// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void ptrToConst(const int * x) {return ptrToConst(std::span<const int>(x, <# size #>));}\n"
 
 #endif
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span-qualified-names.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span-qualified-names.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span-qualified-names.cpp
@@ -2,15 +2,15 @@
 
 namespace NS1 {
   void foo(int *);
-  // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\n"
+  // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} "
   // CHECK-DAG: fix-it:"{{.*}}:{[[@LINE-2]]:18-[[@LINE-2]]:18}:";\nvoid foo(std::span<int>)"
   namespace NS2 {
     void foo(int *);
-    // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:5-[[@LINE-1]]:5}:"#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\n"
+    // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:5-[[@LINE-1]]:5}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} "
     // CHECK-DAG: fix-it:"{{.*}}:{[[@LINE-2]]:20-[[@LINE-2]]:20}:";\nvoid foo(std::span<int>)"
     namespace NS3 {
       void foo(int *);
-      // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:7-[[@LINE-1]]:7}:"#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\n"
+      // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:7-[[@LINE-1]]:7}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} "
       // CHECK-DAG: fix-it:"{{.*}}:{[[@LINE-2]]:22-[[@LINE-2]]:22}:";\nvoid foo(std::span<int>)"
     }
   }
@@ -23,21 +23,21 @@
   int tmp;
   tmp = p[5];
 }
-// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\nvoid NS1::foo(int *p) {return NS1::foo(std::span<int>(p, <# size #>));}\n"
+// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void NS1::foo(int *p) {return NS1::foo(std::span<int>(p, <# size #>));}\n"
 
 void NS1::NS2::foo(int *p) {
   // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:20-[[@LINE-1]]:26}:"std::span<int> p"
   int tmp;
   tmp = p[5];
 }
-// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\nvoid NS1::NS2::foo(int *p) {return NS1::NS2::foo(std::span<int>(p, <# size #>));}\n"
+// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void NS1::NS2::foo(int *p) {return NS1::NS2::foo(std::span<int>(p, <# size #>));}\n"
 
 void NS1::NS2::NS3::foo(int *p) {
   // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:25-[[@LINE-1]]:31}:"std::span<int> p"
   int tmp;
   tmp = p[5];
 }
-// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\nvoid NS1::NS2::NS3::foo(int *p) {return NS1::NS2::NS3::foo(std::span<int>(p, <# size #>));}\n"
+// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void NS1::NS2::NS3::foo(int *p) {return NS1::NS2::NS3::foo(std::span<int>(p, <# size #>));}\n"
 
 
 void f(NS1::MyType * x) {
@@ -45,4 +45,4 @@
   NS1::MyType tmp;
   tmp = x[5];
 }
-// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\nvoid f(NS1::MyType * x) {return f(std::span<NS1::MyType>(x, <# size #>));}\n"
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void f(NS1::MyType * x) {return f(std::span<NS1::MyType>(x, <# size #>));}\n"
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span-overload.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span-overload.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span-overload.cpp
@@ -46,11 +46,11 @@
     int tmp;
     tmp = p[5];
   }
-  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\nvoid foo(int *p) {return foo(std::span<int>(p, <# size #>));}\n"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void foo(int *p) {return foo(std::span<int>(p, <# size #>));}\n"
 
   // Similarly, `NS::bar` is distinct from `bar`:
   void bar(int *p);
-  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:3}:"#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\n"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:3}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} "
   // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:19-[[@LINE-2]]:19}:";\nvoid bar(std::span<int> p)"
 } // end of namespace NS
 
@@ -60,7 +60,7 @@
   int tmp;
   tmp = p[5];
 }
-// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\nvoid NS::bar(int *p) {return NS::bar(std::span<int>(p, <# size #>));}\n"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void NS::bar(int *p) {return NS::bar(std::span<int>(p, <# size #>));}\n"
 
 namespace NESTED {
   void alpha(int);
@@ -74,7 +74,7 @@
       int tmp;
       tmp = p[5];
     }
-    // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:6-[[@LINE-1]]:6}:"\n#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\nvoid alpha(int *p) {return alpha(std::span<int>(p, <# size #>));}\n"
+    // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:6-[[@LINE-1]]:6}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void alpha(int *p) {return alpha(std::span<int>(p, <# size #>));}\n"
   }
 }
 
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-include-header/warn-unsafe-buffer-usage-fixits-parm-in-header.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-include-header/warn-unsafe-buffer-usage-fixits-parm-in-header.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-include-header/warn-unsafe-buffer-usage-fixits-parm-in-header.cpp
@@ -7,7 +7,7 @@
 
 #include "warn-unsafe-buffer-usage-fixits-parm-in-header.h"
 // CHECK-DAG: fix-it:"{{.*}}warn-unsafe-buffer-usage-fixits-parm-in-header.h":{1:1-1:1}:"#include <span>\n"
-// CHECK-DAG: fix-it:"{{.*}}warn-unsafe-buffer-usage-fixits-parm-in-header.h":{3:1-3:1}:"#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\n"
+// CHECK-DAG: fix-it:"{{.*}}warn-unsafe-buffer-usage-fixits-parm-in-header.h":{3:1-3:1}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} "
 // CHECK-DAG: fix-it:"{{.*}}warn-unsafe-buffer-usage-fixits-parm-in-header.h":{3:25-3:25}:";\nvoid unsafe_code(std::span<int> p)"
 // CHECK-DAG: fix-it:"{{.*}}:{[[@LINE-3]]:1-[[@LINE-3]]:1}:"#include <span>\n"
 
@@ -16,4 +16,4 @@
   int tmp;
   tmp = p[5];
 }
-// CHECK-DAG: fix-it:"{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\nvoid unsafe_code(int *p) {return unsafe_code(std::span<int>(p, <# size #>));}\n"
+// CHECK-DAG: fix-it:"{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void unsafe_code(int *p) {return unsafe_code(std::span<int>(p, <# size #>));}\n"
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-include-header/warn-unsafe-buffer-usage-fixits-header-exists.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-include-header/warn-unsafe-buffer-usage-fixits-header-exists.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-include-header/warn-unsafe-buffer-usage-fixits-header-exists.cpp
@@ -10,4 +10,4 @@
   int tmp;
   tmp = p[5];
 }
-// CHECK: fix-it:"{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n#if __has_cpp_attribute(clang::unsafe_buffer_usage)\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n#endif\nvoid unsafe_code(int *p) {return unsafe_code(std::span<int>(p, <# size #>));}\n"
+// CHECK: fix-it:"{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void unsafe_code(int *p) {return unsafe_code(std::span<int>(p, <# size #>));}\n"
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-attributes-spelling.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-attributes-spelling.cpp
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fdiagnostics-parseable-fixits -DCMD_UNSAFE_ATTR=[[clang::unsafe_buffer_usage]] %s 2>&1 | FileCheck %s
+
+
+// no need to check fix-its for definition in this test ...
+void foo(int *p) { 
+  int tmp = p[5];
+}
+
+// Will use the macro defined from the command line:
+void foo(int *);
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"CMD_UNSAFE_ATTR "
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:";\nvoid foo(std::span<int>)"
+
+
+#undef CMD_UNSAFE_ATTR
+void foo(int *);
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} "
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:";\nvoid foo(std::span<int>)"
+
+
+#define UNSAFE_ATTR [[clang::unsafe_buffer_usage]]
+
+void foo(int *);
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"UNSAFE_ATTR "
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:";\nvoid foo(std::span<int>)"
+
+#undef UNSAFE_ATTR
+
+#if __has_cpp_attribute(clang::unsafe_buffer_usage)
+#define UNSAFE_ATTR [[clang::unsafe_buffer_usage]]
+#endif
+
+void foo(int *);
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"UNSAFE_ATTR "
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:";\nvoid foo(std::span<int>)"
+
+#undef UNSAFE_ATTR
+
+#if __has_cpp_attribute(clang::unsafe_buffer_usage)
+// we don't know how to use this macro
+#define UNSAFE_ATTR(x) [[clang::unsafe_buffer_usage]]
+#endif
+
+void foo(int *);
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} "
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:";\nvoid foo(std::span<int>)"
+
+#undef UNSAFE_ATTR
+
+#define UNSAFE_ATTR_1 [[clang::unsafe_buffer_usage]]
+#define UNSAFE_ATTR_2 [[clang::unsafe_buffer_usage]]
+#define UNSAFE_ATTR_3 [[clang::unsafe_buffer_usage]]
+
+// Should use the last defined macro (i.e., UNSAFE_ATTR_3) for
+// `[[clang::unsafe_buffer_usage]]`
+void foo(int *p); 
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"UNSAFE_ATTR_3 "
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:17-[[@LINE-2]]:17}:";\nvoid foo(std::span<int> p)"
+
+
+#define WRONG_ATTR_1 [clang::unsafe_buffer_usage]]
+#define WRONG_ATTR_2 [[clang::unsafe_buffer_usage]
+#define WRONG_ATTR_3 [[clang::unsafe_buffer_usag]]
+
+// The last defined macro for
+// `[[clang::unsafe_buffer_usage]]` is still UNSAFE_ATTR_3
+void foo(int *p); 
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"UNSAFE_ATTR_3 "
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:17-[[@LINE-2]]:17}:";\nvoid foo(std::span<int> p)"
Index: clang/lib/Analysis/UnsafeBufferUsage.cpp
===================================================================
--- clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1117,6 +1117,14 @@
   return EOL;
 }
 
+// Returns the text indicating that the user needs to provide input there:
+std::string getUserFillPlaceHolder(StringRef HintTextToUser = "placeholder") {
+  std::string s = std::string("<# ");
+  s += HintTextToUser;
+  s += " #>";
+  return s;
+}
+
 // Return the text representation of the given `APInt Val`:
 static std::string getAPIntText(APInt Val) {
   SmallVector<char> Txt;
@@ -1507,15 +1515,28 @@
 }
 
 // Returns the text representation of clang::unsafe_buffer_usage attribute.
-// (FIXME:) The text could vary depending on whether macros over the attribute
-// are defined.
-static std::string getUnsafeBufferUsageAttributeText() {
-  std::stringstream SS;
-
-  SS << "#if __has_cpp_attribute(clang::unsafe_buffer_usage)"
-     << getEndOfLine().data() << "[[clang::unsafe_buffer_usage]]"
-     << getEndOfLine().data() << "#endif" << getEndOfLine().data();
-  return SS.str();
+// `WSSuffix` holds customized "white-space"s, e.g., newline or whilespace
+// characters.
+static std::string
+getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc, Sema &S,
+                                    StringRef WSSuffix = "") {
+  Preprocessor &PP = S.getPreprocessor();
+  TokenValue ClangUnsafeBufferUsageTokens[] = {
+      tok::l_square,
+      tok::l_square,
+      PP.getIdentifierInfo("clang"),
+      tok::coloncolon,
+      PP.getIdentifierInfo("unsafe_buffer_usage"),
+      tok::r_square,
+      tok::r_square};
+
+  StringRef MacroName;
+
+  // The returned macro (it returns) is guaranteed not to be function-like:
+  MacroName = PP.getLastMacroWithSpelling(Loc, ClangUnsafeBufferUsageTokens);
+  if (MacroName.empty())
+    MacroName = "[[clang::unsafe_buffer_usage]]";
+  return MacroName.str() + WSSuffix.str();
 }
 
 // Returns the name of `FD` including qualifiers if `FD` is declared with qualifiers.
@@ -1620,13 +1641,13 @@
   // A lambda that creates the text representation of a function definition with
   // the original signature:
   const auto OldOverloadDefCreator =
-      [&SM, &Handler](const FunctionDecl *FD, unsigned ParmIdx,
+      [&SM, &S](const FunctionDecl *FD, unsigned ParmIdx,
                       StringRef NewTypeText) -> std::string {
     std::stringstream SS;
 
     SS << getEndOfLine().data();
     // Appending: attr-name ret-type func-name "(" param-list ")" "{"
-    SS << getUnsafeBufferUsageAttributeText()
+    SS << getUnsafeBufferUsageAttributeTextAt(FD->getBeginLoc(), S, " ")
        << std::string(SM.getCharacterData(FD->getBeginLoc()),
                       SM.getCharacterData(FD->getBody()->getBeginLoc()))
        << "{";
@@ -1645,7 +1666,7 @@
       if (i == ParmIdx)
         // This is our spanified paramter!
         SS << NewTypeText.data() << "(" << Parm->getName().str() << ", "
-           << Handler.getUserFillPlaceHolder("size") << ")";
+           << getUserFillPlaceHolder("size") << ")";
       else
         SS << Parm->getName().str();
       if (i != NumParms - 1)
@@ -1673,7 +1694,8 @@
       // Adds the unsafe-buffer attribute (if not already there) to `FReDecl`:
       if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
         FixIts.emplace_back(FixItHint::CreateInsertion(
-            FReDecl->getBeginLoc(), getUnsafeBufferUsageAttributeText()));
+            FReDecl->getBeginLoc(),
+            getUnsafeBufferUsageAttributeTextAt(FReDecl->getBeginLoc(), S, " ")));
       }
       // Inserts a declaration with the new signature to the end of `FReDecl`:
       FixIts.emplace_back(FixItHint::CreateInsertion(
@@ -1735,7 +1757,7 @@
   (void)DS;
 
   // FIXME: handle cases where DS has multiple declarations
-  return fixVarDeclWithSpan(VD, Ctx, Handler.getUserFillPlaceHolder());
+  return fixVarDeclWithSpan(VD, Ctx, getUserFillPlaceHolder());
 }
 
 // TODO: we should be consistent to use `std::nullopt` to represent no-fix due
Index: clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
===================================================================
--- clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
+++ clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
@@ -67,15 +67,6 @@
 
   /// Returns a reference to the cache for the translation unit:
   virtual HeaderIncludesCache &headerIncludesCache() const = 0;
-
-  /// Returns the text indicating that the user needs to provide input there:
-  virtual std::string
-  getUserFillPlaceHolder(StringRef HintTextToUser = "placeholder") const {
-    std::string s = std::string("<# ");
-    s += HintTextToUser;
-    s += " #>";
-    return s;
-  }
 };
 
 // This function invokes the analysis and allows the caller to react to it
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to