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