ziqingluo-90 updated this revision to Diff 544111.

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

https://reviews.llvm.org/D156189

Files:
  clang/lib/Analysis/UnsafeBufferUsage.cpp
  clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-local-var-span.cpp
  clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp
  clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-deref.cpp
  clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-unevaluated-context.cpp
  clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp

Index: clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp
@@ -80,28 +80,16 @@
       );
 }
 
-void testArraySubscriptsWithAuto(int *p, int **pp) {
+void testArraySubscriptsWithAuto() {
   int a[10];
-  auto ap1 = a;   // expected-warning{{'ap1' is an unsafe pointer used for buffer access}} \
-		     expected-note{{change type of 'ap1' to 'std::span' to preserve bounds information}}
-
+  // We do not fix a declaration if the type is `auto`. Because the actual type may change later.
+  auto ap1 = a;   // expected-warning{{'ap1' is an unsafe pointer used for buffer access}}
   foo(ap1[1]);    // expected-note{{used in buffer access here}}
 
-  auto ap2 = p;   // expected-warning{{'ap2' is an unsafe pointer used for buffer access}} \
-  		     expected-note{{change type of 'ap2' to 'std::span' to preserve bounds information}}
-
+  // In case the type is `auto *`, we know it must be a pointer. We can fix it.
+  auto * ap2 = a; // expected-warning{{'ap2' is an unsafe pointer used for buffer access}} \
+                     expected-note{{change type of 'ap2' to 'std::span' to preserve bounds information}}
   foo(ap2[1]);    // expected-note{{used in buffer access here}}
-
-  auto ap3 = pp;  // expected-warning{{'ap3' is an unsafe pointer used for buffer access}} \
-		     expected-note{{change type of 'ap3' to 'std::span' to preserve bounds information}}
-
-  foo(ap3[1][1]); // expected-note{{used in buffer access here}}
-                  // expected-warning@-1{{unsafe buffer access}}
-
-  auto ap4 = *pp; // expected-warning{{'ap4' is an unsafe pointer used for buffer access}} \
-  		     expected-note{{change type of 'ap4' to 'std::span' to preserve bounds information}}
-
-  foo(ap4[1]);    // expected-note{{used in buffer access here}}
 }
 
 void testUnevaluatedContext(int * p) {// no-warning
@@ -358,8 +346,9 @@
 }
 
 void testMultiLineDeclStmt(int * p) {
-  auto
+  int
 
+  *
 
   ap1 = p;      // expected-warning{{'ap1' is an unsafe pointer used for buffer access}} \
          	   expected-note{{change type of 'ap1' to 'std::span' to preserve bounds information}}
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-unevaluated-context.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-unevaluated-context.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-unevaluated-context.cpp
@@ -15,7 +15,7 @@
 int bar(int *ptr);
 
 void uneval_context_fix_pointer_dereference() {
-  auto p = new int[10];
+  int* p = new int[10];
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
@@ -30,7 +30,7 @@
 }
 
 void uneval_context_fix_pointer_array_access() {
-  auto p = new int[10];
+  int* p = new int[10];
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
@@ -41,7 +41,7 @@
 }
 
 void uneval_context_fix_pointer_reference() {
-  auto p = new int[10];
+  int* p = new int[10];
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
@@ -63,7 +63,7 @@
 
 // FIXME: Emit fixits for each of the below use.
 void uneval_context_fix_pointer_dereference_not_handled() {
-  auto p = new int[10];
+  int* p = new int[10];
   int tmp = p[5];
 
   foo(sizeof(*p), sizeof(decltype(*p)));
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-deref.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-deref.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-deref.cpp
@@ -4,7 +4,7 @@
 
 void basic_dereference() {
   int tmp;
-  auto p = new int[10];
+  int* p = new int[10];
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
@@ -15,7 +15,7 @@
 }
 
 int return_method() {
-  auto p = new int[10];
+  int* p = new int[10];
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
@@ -29,7 +29,7 @@
 }
 
 void method_invocation() {
-  auto p = new int[10];
+  int* p = new int[10];
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
@@ -42,7 +42,7 @@
 }
 
 void binary_operation() {
-  auto p = new int[10];
+  int* p = new int[10];
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp
@@ -10,7 +10,7 @@
 }
 
 void condition_check_nullptr() {
-  auto p = new int[10];
+  int* p = new int[10];
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
@@ -21,7 +21,7 @@
 }
 
 void condition_check() {
-  auto p = new int[10];
+  int* p = new int[10];
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
@@ -53,12 +53,12 @@
 }
 
 void condition_check_two_usafe_buffers() {
-  auto p = new int[10];
+  int* p = new int[10];
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
 
-  auto q = new int[10];
+  int* q = new int[10];
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> q"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
@@ -72,7 +72,7 @@
 }
 
 void unsafe_method_invocation_single_param() {
-  auto p = new int[10];
+  int* p = new int[10];
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
@@ -84,12 +84,12 @@
 }
 
 void safe_method_invocation_single_param() {
-  auto p = new int[10];
+  int* p = new int[10];
   foo(p);
 }
 
 void unsafe_method_invocation_double_param() {
-  auto p = new int[10];
+  int* p = new int[10];
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-local-var-span.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-local-var-span.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-local-var-span.cpp
@@ -4,53 +4,64 @@
 typedef int * Int_ptr_t;
 typedef int Int_t;
 
-#define DEFINE_PTR(X) int* ptr = (X);
-
 void local_array_subscript_simple() {
   int tmp;
   int *p = new int[10];
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
   const int *q = new int[10];
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:17}:"std::span<const int> q"
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:18-[[@LINE-2]]:18}:"{"
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:29-[[@LINE-3]]:29}:", 10}"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:17}:"std::span<int const> q"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:18-[[@LINE-2]]:18}:"{"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:29-[[@LINE-3]]:29}:", 10}"
   tmp = p[5];
   tmp = q[5];
 
+  // We do not fix the following declaration. Because if the
+  // definition of `Int_ptr_t` gets changed, the fixed code becomes
+  // incorrect and may NOT be noticed.
   Int_ptr_t x = new int[10];
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:16}:"std::span<int> x"
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:17-[[@LINE-2]]:17}:"{"
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:28-[[@LINE-3]]:28}:", 10}"
-  Int_ptr_t y = new int;
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:16}:"std::span<int> y"
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:17-[[@LINE-2]]:17}:"{"
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 1}"
+  // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
   Int_t * z = new int[10];
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span<Int_t> z"
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"{"
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:26-[[@LINE-3]]:26}:", 10}"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span<Int_t> z"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"{"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:26-[[@LINE-3]]:26}:", 10}"
   Int_t * w = new Int_t[10];
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span<Int_t> w"
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"{"
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:28-[[@LINE-3]]:28}:", 10}"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span<Int_t> w"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"{"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:28-[[@LINE-3]]:28}:", 10}"
 
   tmp = x[5];
-  tmp = y[5]; // y[5] will crash after being span
   tmp = z[5];
   tmp = w[5];
 }
 
 void local_array_subscript_auto() {
   int tmp;
+  // We do not fix the following declaration. Because if the
+  // definition of `Int_ptr_t` gets changed, the fixed code becomes
+  // incorrect and may NOT be noticed.
   auto p = new int[10];
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
+  // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
   tmp = p[5];
 }
 
+void local_variable_qualifiers_specifiers() {
+  int a[10];
+  const int * p = a;
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:18}:"std::span<int const> p"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:19-[[@LINE-2]]:19}:"{"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:20-[[@LINE-3]]:20}:", 10}"
+  const int * const q = a;
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:24}:"std::span<int const> const q"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:25-[[@LINE-2]]:25}:"{"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:26-[[@LINE-3]]:26}:", 10}"
+  int tmp;
+  tmp = p[5];
+  tmp = q[5];
+}
+
+
 void local_array_subscript_variable_extent() {
   int n = 10;
   int tmp;
@@ -102,8 +113,8 @@
   int * p;
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:10}:"std::span<int> p"
   // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}}
-  Int_ptr_t q;
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span<int> q"
+  Int_t * q;
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span<Int_t> q"
   // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}}
   tmp = p[5];
   tmp = q[5];
@@ -168,15 +179,42 @@
 
 void unsupported_multi_decl(int * x) {
   int * p = x, * q = new int[10];
-  // CHECK-NOT: fix-it:"{{.*}}":[[@LINE-1]]
+  // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
   *p = q[5];
 }
 
+void macroVariableIdentifier() {
+#define MY_NAME p
+#define MY_NAME_ARG(x) q
+
+  // Although fix-its include macros, the macros do not overlap with
+  // the bounds of the source range of these fix-its. So these fix-its
+  // are valid.
+  
+  int * MY_NAME = new int[10];
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:18}:"std::span<int> MY_NAME"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:19-[[@LINE-2]]:19}:"{"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:30-[[@LINE-3]]:30}:", 10}"
+  int * MY_NAME_ARG( 'x' ) = new int[10];
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:29}:"std::span<int> MY_NAME_ARG( 'x' )"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:30-[[@LINE-2]]:30}:"{"
+  // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:41-[[@LINE-3]]:41}:", 10}"
+  p[5] = 5;
+  q[5] = 5;
+#undef MY_NAME
+#undef MY_NAME_ARG
+}
+
 void unsupported_fixit_overlapping_macro(int * x) {
   int tmp;
-  // In the case below, a tentative fix-it replaces `MY_INT * p =` with `std::span<MY_INT> p `.
-  // It overlaps with the use of the macro `MY_INT`.  The fix-it is
-  // discarded then.
+  // In the case below, a tentative fix-it replaces `MY_INT * p =` with `std::span<MY_INT> p `. 
+  // The bounds of the source range of the fix-it overlap with the use of the macro
+  // `MY_INT`.  The fix-it is discarded then.
+
+  // FIXME: we do not have to discard a fix-it if its begin location
+  // overlaps with the begin location of a macro. Similar for end
+  // locations.
+       
 #define MY_INT int
   MY_INT * p = new int[10];
   // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
@@ -227,6 +265,8 @@
   tmp = r[(unsigned int)-1]; // a cast-to-unsigned-expression is also non-negative
 }
 
+#define DEFINE_PTR(X) int* ptr = (X);
+
 void all_vars_in_macro() {
   int* local;
   DEFINE_PTR(local)
@@ -239,10 +279,10 @@
   ptr[1] = 0;
   int tmp;
   ptr[2] = 30;
-  auto p = new int[10];
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
-  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
+  int * p = new int[10];
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span<int> p"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}"
   tmp = p[5];
   int val = *p;
   // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:14}:""
Index: clang/lib/Analysis/UnsafeBufferUsage.cpp
===================================================================
--- clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1683,7 +1683,7 @@
 //   `Init` a pointer to the initializer expression
 //   `Ctx` a reference to the ASTContext
 static FixItList
-populateInitializerFixItWithSpan(const Expr *Init, ASTContext &Ctx,
+FixVarInitializerWithSpan(const Expr *Init, ASTContext &Ctx,
                                  const StringRef UserFillPlaceHolder) {
   const SourceManager &SM = Ctx.getSourceManager();
   const LangOptions &LangOpts = Ctx.getLangOpts();
@@ -1789,53 +1789,60 @@
 }
 
 // For a `VarDecl` of the form `T  * var (= Init)?`, this
-// function generates a fix-it for the declaration, which re-declares `var` to
-// be of `span<T>` type and transforms the initializer, if present, to a span
-// constructor---`span<T> var {Init, Extent}`, where `Extent` may need the user
-// to fill in.
+// function generates fix-its that
+//  1) replaces `T * var` with `std::span<T> var`; and
+//  2) changes `Init` accordingly to a span constructor, if it exists.
 //
 // FIXME: support Multi-level pointers
 //
 // Parameters:
 //   `D` a pointer the variable declaration node
 //   `Ctx` a reference to the ASTContext
+//   `UserFillPlaceHolder` the user-input placeholder text
 // Returns:
-//    the generated fix-it
-static FixItList fixVarDeclWithSpan(const VarDecl *D, ASTContext &Ctx,
-                                    const StringRef UserFillPlaceHolder) {
-  const QualType &SpanEltT = D->getType()->getPointeeType();
-  assert(!SpanEltT.isNull() && "Trying to fix a non-pointer type variable!");
-
+//    the non-empty fix-it list, if fix-its are successfuly generated; empty
+//    list otherwise.
+static FixItList fixLocalVarDeclWithSpan(const VarDecl *D, ASTContext &Ctx,
+                                         const StringRef UserFillPlaceHolder) {
   FixItList FixIts{};
-  std::optional<SourceLocation>
-      ReplacementLastLoc; // the inclusive end location of the replacement
-  const SourceManager &SM = Ctx.getSourceManager();
+  std::optional<std::string> SpanTyText = createSpanTypeForVarDecl(D, Ctx);
+
+  if (!SpanTyText)
+    return {};
+
+  // Will hold the text for `std::span<T> Ident`:
+  std::stringstream SS;
+
+  SS << *SpanTyText;
+  // Append qualifiers to the type of `D`, if any:
+  if (D->getType().hasQualifiers())
+    SS << " " << D->getType().getQualifiers().getAsString();
 
+  // The end of the range of the original source that will be replaced
+  // by `std::span<T> ident`:
+  SourceLocation EndLocForReplacement = D->getEndLoc();
+  std::optional<StringRef> IdentText =
+      getVarDeclIdentifierText(D, Ctx.getSourceManager(), Ctx.getLangOpts());
+
+  if (!IdentText)
+    return {};
+  // Fix the initializer if it exists:
   if (const Expr *Init = D->getInit()) {
     FixItList InitFixIts =
-        populateInitializerFixItWithSpan(Init, Ctx, UserFillPlaceHolder);
-
+        FixVarInitializerWithSpan(Init, Ctx, UserFillPlaceHolder);
     if (InitFixIts.empty())
       return {};
-
-    // The loc right before the initializer:
-    ReplacementLastLoc = Init->getBeginLoc().getLocWithOffset(-1);
     FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts.begin()),
                   std::make_move_iterator(InitFixIts.end()));
-  } else
-    ReplacementLastLoc = getEndCharLoc(D, SM, Ctx.getLangOpts());
-
-  // Producing fix-it for variable declaration---make `D` to be of span type:
-  SmallString<32> Replacement;
-  raw_svector_ostream OS(Replacement);
-
-  OS << "std::span<" << SpanEltT.getAsString() << "> " << D->getName();
-
-  if (!ReplacementLastLoc)
+    // If the declaration has the form `T *ident = init`, we want to replace
+    // `T *ident = ` with `std::span<T> ident`:
+    EndLocForReplacement = Init->getBeginLoc().getLocWithOffset(-1);
+  }
+  SS << " " << IdentText->str();
+  if (!EndLocForReplacement.isValid())
     return {};
-
   FixIts.push_back(FixItHint::CreateReplacement(
-      SourceRange{D->getBeginLoc(), *ReplacementLastLoc}, OS.str()));
+      SourceRange(D->getBeginLoc(), EndLocForReplacement), SS.str()));
   return FixIts;
 }
 
@@ -2085,7 +2092,7 @@
   (void)DS;
 
   // FIXME: handle cases where DS has multiple declarations
-  return fixVarDeclWithSpan(VD, Ctx, getUserFillPlaceHolder());
+  return fixLocalVarDeclWithSpan(VD, Ctx, getUserFillPlaceHolder());
 }
 
 // TODO: we should be consistent to use `std::nullopt` to represent no-fix due
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to