-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[-Wunsafe-buffer-usage] Minimize fixit range for pointer variables #81935
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2304,20 +2304,6 @@ static FixItList fixLocalVarDeclWithSpan(const VarDecl *D, ASTContext &Ctx, | |
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) { | ||
DEBUG_NOTE_DECL_FAIL(D, " : failed to locate the identifier"); | ||
return {}; | ||
} | ||
// Fix the initializer if it exists: | ||
if (const Expr *Init = D->getInit()) { | ||
std::optional<FixItList> InitFixIts = | ||
|
@@ -2326,15 +2312,22 @@ static FixItList fixLocalVarDeclWithSpan(const VarDecl *D, ASTContext &Ctx, | |
return {}; | ||
FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()), | ||
std::make_move_iterator(InitFixIts->end())); | ||
// 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(); | ||
// For declaration of the form `T * ident = init;`, we want to replace | ||
// `T * ` with `std::span<T>`. | ||
// We ignore CV-qualifiers so for `T * const ident;` we also want to replace | ||
// just `T *` with `std::span<T>`. | ||
const SourceLocation EndLocForReplacement = D->getTypeSpecEndLoc(); | ||
if (!EndLocForReplacement.isValid()) { | ||
DEBUG_NOTE_DECL_FAIL(D, " : failed to locate the end of the declaration"); | ||
return {}; | ||
} | ||
// The only exception is that for `T *ident` we'll add a single space between | ||
// "std::span<T>" and "ident". | ||
// FIXME: The condition is false for identifiers expended from macros. | ||
if (EndLocForReplacement.getLocWithOffset(1) == getVarDeclIdentifierLoc(D)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In case the identifier is a macro expansion, e.g.,
, the if-condition will evaluate to false because the files of the two source locations are different. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right! I added a FIXME |
||
SS << " "; | ||
|
||
FixIts.push_back(FixItHint::CreateReplacement( | ||
SourceRange(D->getBeginLoc(), EndLocForReplacement), SS.str())); | ||
return FixIts; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \ | ||
// RUN: -fsafe-buffer-usage-suggestions \ | ||
// RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s | ||
|
||
int ptr(unsigned idx) { | ||
int * ptr = new int[1]; | ||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>" | ||
int a; | ||
a = ptr[idx]; | ||
return a; | ||
} | ||
|
||
int ptr_to_const(unsigned idx) { | ||
const int * ptr = new int[1]; | ||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span<int const>" | ||
int a; | ||
a = ptr[idx]; | ||
return a; | ||
} | ||
|
||
int const_ptr(unsigned idx) { | ||
int * const ptr = new int[1]; | ||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>" | ||
int a; | ||
a = ptr[idx]; | ||
return a; | ||
} | ||
|
||
int const_ptr_to_const(unsigned idx) { | ||
const int * const ptr = new int[1]; | ||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span<int const>" | ||
int a; | ||
a = ptr[idx]; | ||
return a; | ||
} | ||
|
||
int ptr_to_const_volatile(unsigned idx) { | ||
const volatile int * ptr = new int[1]; | ||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:23}:"std::span<int const volatile>" | ||
int a; | ||
a = ptr[idx]; | ||
return a; | ||
} | ||
|
||
int const_volatile_ptr(unsigned idx) { | ||
int * const volatile ptr = new int[1]; | ||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>" | ||
int a; | ||
a = ptr[idx]; | ||
return a; | ||
} | ||
|
||
int const_volatile_ptr_to_const_volatile(unsigned idx) { | ||
const volatile int * const volatile ptr = new int[1]; | ||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:23}:"std::span<int const volatile>" | ||
int a; | ||
a = ptr[idx]; | ||
return a; | ||
} | ||
|
||
typedef const int * my_const_int_star; | ||
int typedef_ptr_to_const(unsigned idx) { | ||
my_const_int_star ptr = new int[1]; | ||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]: | ||
int a; | ||
a = ptr[idx]; | ||
return a; | ||
} | ||
|
||
typedef int * const my_int_star_const; | ||
int typedef_const_ptr(unsigned idx) { | ||
my_int_star_const ptr = new int[1]; | ||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]: | ||
int a; | ||
a = ptr[idx]; | ||
return a; | ||
} | ||
|
||
typedef const int * const my_const_int_star_const; | ||
int typedef_const_ptr_to_const(unsigned idx) { | ||
my_const_int_star_const ptr = new int[1]; | ||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]: | ||
int a; | ||
a = ptr[idx]; | ||
return a; | ||
} | ||
|
||
int ptr_to_decltype(unsigned idx) { | ||
int a; | ||
decltype(a) * ptr = new int[1]; | ||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:16}:"std::span<decltype(a)>" | ||
a = ptr[idx]; | ||
return a; | ||
} | ||
|
||
int decltype_ptr(unsigned idx) { | ||
int * p; | ||
decltype(p) ptr = new int[1]; | ||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]: | ||
int a; | ||
a = ptr[idx]; | ||
return a; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks a correct optimization to me! I probably didn't realize the existence of
getTypeSpecEndLoc()
when I did this.