mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-19 13:16:46 +00:00
[-Wunsafe-buffer-usage] Use Strategy
to determine whether to fix a parameter
- Use Strategy to determine whether to fix a parameter - Fix the `Strategy` construction so that only variables on the graph are assigned the `std::span` strategy Reviewed by: t-rasmud (Rashmi Mudduluru), NoQ (Artem Dergachev) Differential revision: https://reviews.llvm.org/D157441
This commit is contained in:
parent
e0be78be42
commit
700baeb765
@ -35,6 +35,10 @@ public:
|
||||
/// variables, where `Var` is in, contains parameters.
|
||||
virtual VarGrpRef getGroupOfVar(const VarDecl *Var,
|
||||
bool *HasParm = nullptr) const =0;
|
||||
|
||||
/// Returns the non-empty group of variables that include parameters of the
|
||||
/// analyzing function, if such a group exists. An empty group, otherwise.
|
||||
virtual VarGrpRef getGroupOfParms() const =0;
|
||||
};
|
||||
|
||||
/// The interface that lets the caller handle unsafe buffer usage analysis
|
||||
|
@ -1634,12 +1634,10 @@ PointerDereferenceGadget::getFixits(const Strategy &S) const {
|
||||
CharSourceRange derefRange = clang::CharSourceRange::getCharRange(
|
||||
Op->getBeginLoc(), Op->getBeginLoc().getLocWithOffset(1));
|
||||
// Inserts the [0]
|
||||
std::optional<SourceLocation> EndOfOperand =
|
||||
getEndCharLoc(BaseDeclRefExpr, SM, Ctx.getLangOpts());
|
||||
if (EndOfOperand) {
|
||||
if (auto LocPastOperand =
|
||||
getPastLoc(BaseDeclRefExpr, SM, Ctx.getLangOpts())) {
|
||||
return FixItList{{FixItHint::CreateRemoval(derefRange),
|
||||
FixItHint::CreateInsertion(
|
||||
(*EndOfOperand).getLocWithOffset(1), "[0]")}};
|
||||
FixItHint::CreateInsertion(*LocPastOperand, "[0]")}};
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1978,18 +1976,9 @@ static bool hasConflictingOverload(const FunctionDecl *FD) {
|
||||
// return f(std::span(p, <# size #>));
|
||||
// }
|
||||
//
|
||||
// The actual fix-its may contain more details, e.g., the attribute may be guard
|
||||
// by a macro
|
||||
// #if __has_cpp_attribute(clang::unsafe_buffer_usage)
|
||||
// [[clang::unsafe_buffer_usage]]
|
||||
// #endif
|
||||
//
|
||||
// `ParmsMask` is an array of size of `FD->getNumParams()` such
|
||||
// that `ParmsMask[i]` is true iff the `i`-th parameter will be fixed with some
|
||||
// strategy.
|
||||
static std::optional<FixItList>
|
||||
createOverloadsForFixedParams(const std::vector<bool> &ParmsMask, const Strategy &S,
|
||||
const FunctionDecl *FD, const ASTContext &Ctx,
|
||||
createOverloadsForFixedParams(const Strategy &S, const FunctionDecl *FD,
|
||||
const ASTContext &Ctx,
|
||||
UnsafeBufferUsageHandler &Handler) {
|
||||
// FIXME: need to make this conflict checking better:
|
||||
if (hasConflictingOverload(FD))
|
||||
@ -1999,21 +1988,33 @@ createOverloadsForFixedParams(const std::vector<bool> &ParmsMask, const Strategy
|
||||
const LangOptions &LangOpts = Ctx.getLangOpts();
|
||||
const unsigned NumParms = FD->getNumParams();
|
||||
std::vector<std::string> NewTysTexts(NumParms);
|
||||
std::vector<bool> ParmsMask(NumParms, false);
|
||||
bool AtLeastOneParmToFix = false;
|
||||
|
||||
for (unsigned i = 0; i < NumParms; i++) {
|
||||
if (!ParmsMask[i])
|
||||
const ParmVarDecl *PVD = FD->getParamDecl(i);
|
||||
|
||||
if (S.lookup(PVD) == Strategy::Kind::Wontfix)
|
||||
continue;
|
||||
if (S.lookup(PVD) != Strategy::Kind::Span)
|
||||
// Not supported, not suppose to happen:
|
||||
return std::nullopt;
|
||||
|
||||
std::optional<Qualifiers> PteTyQuals = std::nullopt;
|
||||
std::optional<std::string> PteTyText =
|
||||
getPointeeTypeText(FD->getParamDecl(i), SM, LangOpts, &PteTyQuals);
|
||||
getPointeeTypeText(PVD, SM, LangOpts, &PteTyQuals);
|
||||
|
||||
if (!PteTyText)
|
||||
// something wrong in obtaining the text of the pointee type, give up
|
||||
return std::nullopt;
|
||||
// FIXME: whether we should create std::span type depends on the Strategy.
|
||||
NewTysTexts[i] = getSpanTypeText(*PteTyText, PteTyQuals);
|
||||
ParmsMask[i] = true;
|
||||
AtLeastOneParmToFix = true;
|
||||
}
|
||||
if (!AtLeastOneParmToFix)
|
||||
// No need to create function overloads:
|
||||
return {};
|
||||
// FIXME Respect indentation of the original code.
|
||||
|
||||
// A lambda that creates the text representation of a function declaration
|
||||
@ -2322,28 +2323,18 @@ static FixItList createFunctionOverloadsForParms(
|
||||
const VariableGroupsManager &VarGrpMgr, const FunctionDecl *FD,
|
||||
const Strategy &S, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler) {
|
||||
FixItList FixItsSharedByParms{};
|
||||
std::vector<bool> ParmsNeedFixMask(FD->getNumParams(), false);
|
||||
const VarDecl *FirstParmNeedsFix = nullptr;
|
||||
|
||||
for (unsigned i = 0; i < FD->getNumParams(); i++)
|
||||
if (FixItsForVariable.count(FD->getParamDecl(i))) {
|
||||
ParmsNeedFixMask[i] = true;
|
||||
FirstParmNeedsFix = FD->getParamDecl(i);
|
||||
}
|
||||
if (FirstParmNeedsFix) {
|
||||
// In case at least one parameter needs to be fixed:
|
||||
std::optional<FixItList> OverloadFixes =
|
||||
createOverloadsForFixedParams(ParmsNeedFixMask, S, FD, Ctx, Handler);
|
||||
std::optional<FixItList> OverloadFixes =
|
||||
createOverloadsForFixedParams(S, FD, Ctx, Handler);
|
||||
|
||||
if (OverloadFixes) {
|
||||
FixItsSharedByParms.append(*OverloadFixes);
|
||||
} else {
|
||||
// Something wrong in generating `OverloadFixes`, need to remove the
|
||||
// whole group, where parameters are in, from `FixItsForVariable` (Note
|
||||
// that all parameters should be in the same group):
|
||||
for (auto *Member : VarGrpMgr.getGroupOfVar(FirstParmNeedsFix))
|
||||
FixItsForVariable.erase(Member);
|
||||
}
|
||||
if (OverloadFixes) {
|
||||
FixItsSharedByParms.append(*OverloadFixes);
|
||||
} else {
|
||||
// Something wrong in generating `OverloadFixes`, need to remove the
|
||||
// whole group, where parameters are in, from `FixItsForVariable` (Note
|
||||
// that all parameters should be in the same group):
|
||||
for (auto *Member : VarGrpMgr.getGroupOfParms())
|
||||
FixItsForVariable.erase(Member);
|
||||
}
|
||||
return FixItsSharedByParms;
|
||||
}
|
||||
@ -2448,8 +2439,9 @@ getFixIts(FixableGadgetSets &FixablesForAllVars, const Strategy &S,
|
||||
return FinalFixItsForVariable;
|
||||
}
|
||||
|
||||
template <typename VarDeclIterTy>
|
||||
static Strategy
|
||||
getNaiveStrategy(const llvm::SmallVectorImpl<const VarDecl *> &UnsafeVars) {
|
||||
getNaiveStrategy(llvm::iterator_range<VarDeclIterTy> UnsafeVars) {
|
||||
Strategy S;
|
||||
for (const VarDecl *VD : UnsafeVars) {
|
||||
S.set(VD, Strategy::Kind::Span);
|
||||
@ -2486,6 +2478,10 @@ public:
|
||||
return std::nullopt;
|
||||
return Groups[It->second];
|
||||
}
|
||||
|
||||
VarGrpRef getGroupOfParms() const override {
|
||||
return GrpsUnionForParms.getArrayRef();
|
||||
}
|
||||
};
|
||||
|
||||
void clang::checkUnsafeBufferUsage(const Decl *D,
|
||||
@ -2579,6 +2575,14 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
|
||||
it->first, it->first->getBeginLoc(),
|
||||
("failed to produce fixit for '" + it->first->getNameAsString() +
|
||||
"' : neither local nor a parameter"));
|
||||
#endif
|
||||
it = FixablesForAllVars.byVar.erase(it);
|
||||
} else if (it->first->getType().getCanonicalType()->isReferenceType()) {
|
||||
#ifndef NDEBUG
|
||||
Handler.addDebugNoteForVar(it->first, it->first->getBeginLoc(),
|
||||
("failed to produce fixit for '" +
|
||||
it->first->getNameAsString() +
|
||||
"' : has a reference type"));
|
||||
#endif
|
||||
it = FixablesForAllVars.byVar.erase(it);
|
||||
} else if (Tracker.hasUnclaimedUses(it->first)) {
|
||||
@ -2605,10 +2609,6 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
|
||||
}
|
||||
}
|
||||
|
||||
llvm::SmallVector<const VarDecl *, 16> UnsafeVars;
|
||||
for (const auto &[VD, ignore] : FixablesForAllVars.byVar)
|
||||
UnsafeVars.push_back(VD);
|
||||
|
||||
// Fixpoint iteration for pointer assignments
|
||||
using DepMapTy = DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
|
||||
DepMapTy DependenciesMap{};
|
||||
@ -2737,7 +2737,13 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
|
||||
++I;
|
||||
}
|
||||
|
||||
Strategy NaiveStrategy = getNaiveStrategy(UnsafeVars);
|
||||
// We assign strategies to variables that are 1) in the graph and 2) can be
|
||||
// fixed. Other variables have the default "Won't fix" strategy.
|
||||
Strategy NaiveStrategy = getNaiveStrategy(llvm::make_filter_range(
|
||||
VisitedVars, [&FixablesForAllVars](const VarDecl *V) {
|
||||
// If a warned variable has no "Fixable", it is considered unfixable:
|
||||
return FixablesForAllVars.byVar.count(V);
|
||||
}));
|
||||
VariableGroupsManagerImpl VarGrpMgr(Groups, VarGrpMap, GrpsUnionForParms);
|
||||
|
||||
if (isa<NamedDecl>(D))
|
||||
|
@ -68,18 +68,15 @@ void * multiParmAllFix(int *p, int **q, int a[], int * r);
|
||||
|
||||
// Fixing local variables implicates fixing parameters
|
||||
void multiParmLocalAllFix(int *p, int * r) {
|
||||
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:28-[[@LINE-1]]:34}:"std::span<int> p"
|
||||
// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:36-[[@LINE-2]]:43}:"std::span<int> r"
|
||||
// CHECK: fix-it:{{.*}}:{[[@LINE+1]]:3-[[@LINE+1]]:10}:"std::span<int> x"
|
||||
int * 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, and change 'p', 'z', and 'r' to safe types to make function 'multiParmLocalAllFix' bounds-safe}}
|
||||
// CHECK: fix-it:{{.*}}:{[[@LINE+1]]:3-[[@LINE+1]]:10}:"std::span<int> z"
|
||||
int * z; // expected-warning{{'z' is an unsafe pointer used for buffer access}} \
|
||||
expected-note{{change type of 'z' to 'std::span' to preserve bounds information, and change 'x', 'p', and 'r' to safe types to make function 'multiParmLocalAllFix' bounds-safe}}
|
||||
// CHECK-NOT: fix-it:{{.*}}:{[[@LINE-1]]:
|
||||
// CHECK-NOT: fix-it:{{.*}}:{[[@LINE+1]]:
|
||||
int * x; // expected-warning{{'x' is an unsafe pointer used for buffer access}}
|
||||
// CHECK-NOT: fix-it:{{.*}}:{[[@LINE+1]]:
|
||||
int * z; // expected-warning{{'z' is an unsafe pointer used for buffer access}}
|
||||
int * y;
|
||||
|
||||
x = p;
|
||||
y = x;
|
||||
y = x; // FIXME: we do not fix `y = x` here as the `.data()` fix-it is not generally correct
|
||||
// `x` needs to be fixed so does the pointer assigned to `x`, i.e.,`p`
|
||||
x[5] = 5; // expected-note{{used in buffer access here}}
|
||||
z = r;
|
||||
@ -89,33 +86,26 @@ void multiParmLocalAllFix(int *p, int * r) {
|
||||
// fixing `x` involves fixing all `p`, `r` and `z`. Similar for
|
||||
// fixing `z`.
|
||||
}
|
||||
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void multiParmLocalAllFix(int *p, int * r) {return multiParmLocalAllFix(std::span<int>(p, <# size #>), std::span<int>(r, <# size #>));}\n"
|
||||
// CHECK-NOT: fix-it:{{.*}}:{[[@LINE-1]]:
|
||||
|
||||
|
||||
// Fixing parameters implicates fixing local variables
|
||||
// CHECK: fix-it:{{.*}}:{[[@LINE+2]]:29-[[@LINE+2]]:35}:"std::span<int> p"
|
||||
// CHECK: fix-it:{{.*}}:{[[@LINE+1]]:37-[[@LINE+1]]:44}:"std::span<int> r"
|
||||
// CHECK-NOT: fix-it:{{.*}}:{[[@LINE+1]]:
|
||||
void multiParmLocalAllFix2(int *p, int * r) { // expected-warning{{'p' is an unsafe pointer used for buffer access}} \
|
||||
expected-note{{change type of 'p' to 'std::span' to preserve bounds information, and change 'x', 'r', and 'z' to safe types to make function 'multiParmLocalAllFix2' bounds-safe}} \
|
||||
expected-warning{{'r' is an unsafe pointer used for buffer access}} \
|
||||
expected-note{{change type of 'r' to 'std::span' to preserve bounds information, and change 'p', 'x', and 'z' to safe types to make function 'multiParmLocalAllFix2' bounds-safe}}
|
||||
expected-warning{{'r' is an unsafe pointer used for buffer access}}
|
||||
int * x = new int[10];
|
||||
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span<int> x"
|
||||
// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
|
||||
// CHECK: fix-it:{{.*}}:{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}"
|
||||
// CHECK-NOT: fix-it:{{.*}}:{[[@LINE-1]]:
|
||||
int * z = new int[10];
|
||||
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span<int> z"
|
||||
// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
|
||||
// CHECK: fix-it:{{.*}}:{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}"
|
||||
// CHECK-NOT: fix-it:{{.*}}:{[[@LINE-1]]:
|
||||
int * y;
|
||||
|
||||
p = x;
|
||||
y = x;
|
||||
y = x; // FIXME: we do not fix `y = x` here as the `.data()` fix-it is not generally correct
|
||||
p[5] = 5; // expected-note{{used in buffer access here}}
|
||||
r = z;
|
||||
r[5] = 5; // expected-note{{used in buffer access here}}
|
||||
}
|
||||
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void multiParmLocalAllFix2(int *p, int * r) {return multiParmLocalAllFix2(std::span<int>(p, <# size #>), std::span<int>(r, <# size #>));}\n"
|
||||
// CHECK-NOT: fix-it:{{.*}}:{[[@LINE-1]]:
|
||||
|
||||
|
||||
// No fix emitted for any of the parameter since parameter `r` cannot be fixed
|
||||
|
@ -2,18 +2,14 @@
|
||||
|
||||
void foo1a() {
|
||||
int *r = new int[7];
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> r"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:22-[[@LINE-3]]:22}:", 7}"
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
|
||||
int *p = new int[4];
|
||||
// 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]]:22-[[@LINE-3]]:22}:", 4}"
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
|
||||
p = r;
|
||||
int tmp = p[9];
|
||||
int *q;
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> q"
|
||||
q = r;
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
|
||||
q = r; // FIXME: we do not fix `q = r` here as the `.data()` fix-it is not generally correct
|
||||
}
|
||||
|
||||
void foo1b() {
|
||||
@ -37,15 +33,13 @@ void foo1b() {
|
||||
|
||||
void foo1c() {
|
||||
int *r = new int[7];
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> r"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:22-[[@LINE-3]]:22}:", 7}"
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
|
||||
int *p = new int[4];
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
|
||||
p = r;
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
|
||||
p = r; // FIXME: we do not fix `p = r` here as the `.data()` fix-it is not generally correct
|
||||
int tmp = r[9];
|
||||
int *q;
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> q"
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
|
||||
q = r;
|
||||
tmp = q[9];
|
||||
}
|
||||
@ -70,18 +64,12 @@ void foo2a() {
|
||||
|
||||
void foo2b() {
|
||||
int *r = new int[7];
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> r"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:22-[[@LINE-3]]:22}:", 7}"
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
|
||||
int *p = new int[5];
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-3]]:22-[[@LINE-3]]:22}:", 5}"
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
|
||||
int *q = new int[4];
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> q"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:22-[[@LINE-3]]:22}:", 4}"
|
||||
p = q;
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
|
||||
p = q; // FIXME: we do not fix `p = q` here as the `.data()` fix-it is not generally correct
|
||||
int tmp = q[8];
|
||||
q = r;
|
||||
}
|
||||
@ -107,14 +95,12 @@ void foo2c() {
|
||||
|
||||
void foo3a() {
|
||||
int *r = new int[7];
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> r"
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
|
||||
int *p = new int[5];
|
||||
// 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]]:22-[[@LINE-3]]:22}:", 5}"
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
|
||||
int *q = new int[4];
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> q"
|
||||
q = p;
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
|
||||
q = p; // FIXME: we do not fix `q = p` here as the `.data()` fix-it is not generally correct
|
||||
int tmp = p[8];
|
||||
q = r;
|
||||
}
|
||||
|
@ -62,13 +62,11 @@ void test_grouping() {
|
||||
int *z = new int[8];
|
||||
int tmp;
|
||||
int *y = new int[10];
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> y"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
|
||||
tmp = y[5];
|
||||
|
||||
int *x = new int[10];
|
||||
x = y;
|
||||
x = y; // FIXME: we do not fix `x = y` here as the `.data()` fix-it is not generally correct
|
||||
|
||||
int *w = z;
|
||||
}
|
||||
|
@ -27,17 +27,17 @@ void rhs_span3() {
|
||||
int *q = new int[6];
|
||||
int *p = q; // expected-warning{{'p' is an unsafe pointer used for buffer access}}
|
||||
p[5] = 10; // expected-note{{used in buffer access here}}
|
||||
int *r = q;
|
||||
int *r = q; // FIXME: we do not fix `int *r = q` here as the `.data()` fix-it is not generally correct
|
||||
}
|
||||
|
||||
void test_grouping() {
|
||||
int *z = new int[8];
|
||||
int tmp;
|
||||
int *y = new int[10]; // expected-warning{{'y' is an unsafe pointer used for buffer access}} expected-note{{change type of 'y' to 'std::span' to preserve bounds information}}
|
||||
int *y = new int[10]; // expected-warning{{'y' is an unsafe pointer used for buffer access}}
|
||||
tmp = y[5]; // expected-note{{used in buffer access here}}
|
||||
|
||||
int *x = new int[10];
|
||||
x = y;
|
||||
x = y; // FIXME: we do not fix `x = y` here as the `.data()` fix-it is not generally correct
|
||||
|
||||
int *w = z;
|
||||
}
|
||||
|
@ -6,17 +6,13 @@ void bar(int * param) {}
|
||||
|
||||
void foo1a() {
|
||||
int *r = new int[7];
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> r"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:22-[[@LINE-3]]:22}:", 7}"
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
|
||||
int *p = new int[4];
|
||||
// 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]]:22-[[@LINE-3]]:22}:", 4}"
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
|
||||
p = r;
|
||||
int tmp = p[9];
|
||||
int *q;
|
||||
q = r;
|
||||
q = r; // FIXME: we do not fix `q = r` here as the `.data()` fix-it is not generally correct
|
||||
}
|
||||
|
||||
void uuc_if_body() {
|
||||
|
@ -3,11 +3,11 @@ void bar(int * param) {}
|
||||
|
||||
void foo1a() {
|
||||
int *r = new int[7];
|
||||
int *p = new int[4]; // expected-warning{{'p' is an unsafe pointer used for buffer access}} expected-note{{change type of 'p' to 'std::span' to preserve bounds information, and change 'r' to 'std::span' to propagate bounds information between them}}
|
||||
int *p = new int[4]; // expected-warning{{'p' is an unsafe pointer used for buffer access}}
|
||||
p = r;
|
||||
int tmp = p[9]; // expected-note{{used in buffer access here}}
|
||||
int *q;
|
||||
q = r;
|
||||
q = r; // FIXME: we do not fix `q = r` here as the `.data()` fix-it is not generally correct
|
||||
}
|
||||
|
||||
void uuc_if_body() {
|
||||
|
@ -18,9 +18,9 @@ void local_assign_both_span() {
|
||||
void local_assign_rhs_span() {
|
||||
int tmp;
|
||||
int* p = new int[10];
|
||||
int* q = new int[10]; // expected-warning{{'q' is an unsafe pointer used for buffer access}} expected-note{{change type of 'q' to 'std::span' to preserve bounds information}}
|
||||
int* q = new int[10]; // expected-warning{{'q' is an unsafe pointer used for buffer access}}
|
||||
tmp = q[4]; // expected-note{{used in buffer access here}}
|
||||
p = q;
|
||||
p = q; // FIXME: we do not fix `p = q` here as the `.data()` fix-it is not generally correct
|
||||
}
|
||||
|
||||
void local_assign_no_span() {
|
||||
@ -49,10 +49,10 @@ void lhs_span_multi_assign() {
|
||||
|
||||
void rhs_span() {
|
||||
int *x = new int[3];
|
||||
int *y; // expected-warning{{'y' is an unsafe pointer used for buffer access}} expected-note{{change type of 'y' to 'std::span' to preserve bounds information}}
|
||||
int *y; // expected-warning{{'y' is an unsafe pointer used for buffer access}}
|
||||
y[5] = 10; // expected-note{{used in buffer access here}}
|
||||
|
||||
x = y;
|
||||
x = y; // FIXME: we do not fix `x = y` here as the `.data()` fix-it is not generally correct
|
||||
}
|
||||
|
||||
void rhs_span1() {
|
||||
@ -65,43 +65,43 @@ void rhs_span1() {
|
||||
|
||||
void rhs_span2() {
|
||||
int *q = new int[6];
|
||||
int *p = q; // expected-warning{{'p' is an unsafe pointer used for buffer access}}
|
||||
int *p = q; // expected-warning{{'p' is an unsafe pointer used for buffer access}}
|
||||
p[5] = 10; // expected-note{{used in buffer access here}}
|
||||
int *r = q;
|
||||
int *r = q; // FIXME: we do not fix `int *r = q` here as the `.data()` fix-it is not generally correct
|
||||
}
|
||||
|
||||
void test_grouping() {
|
||||
int *z = new int[8];
|
||||
int tmp;
|
||||
int *y = new int[10]; // expected-warning{{'y' is an unsafe pointer used for buffer access}} expected-note{{change type of 'y' to 'std::span' to preserve bounds information}}
|
||||
int *y = new int[10]; // expected-warning{{'y' is an unsafe pointer used for buffer access}}
|
||||
tmp = y[5]; // expected-note{{used in buffer access here}}
|
||||
|
||||
int *x = new int[10];
|
||||
x = y;
|
||||
x = y; // FIXME: we do not fix `x = y` here as the `.data()` fix-it is not generally correct
|
||||
|
||||
int *w = z;
|
||||
}
|
||||
|
||||
void test_grouping1() {
|
||||
int tmp;
|
||||
int *y = new int[10]; // expected-warning{{'y' is an unsafe pointer used for buffer access}} expected-note{{change type of 'y' to 'std::span' to preserve bounds information}}
|
||||
int *y = new int[10]; // expected-warning{{'y' is an unsafe pointer used for buffer access}}
|
||||
tmp = y[5]; // expected-note{{used in buffer access here}}
|
||||
int *x = new int[10];
|
||||
x = y;
|
||||
x = y; // FIXME: we do not fix `x = y` here as the `.data()` fix-it is not generally correct
|
||||
|
||||
int *w = new int[10]; // expected-warning{{'w' is an unsafe pointer used for buffer access}} expected-note{{change type of 'w' to 'std::span' to preserve bounds information}}
|
||||
int *w = new int[10]; // expected-warning{{'w' is an unsafe pointer used for buffer access}}
|
||||
tmp = w[5]; // expected-note{{used in buffer access here}}
|
||||
int *z = new int[10];
|
||||
z = w;
|
||||
z = w; // FIXME: we do not fix `z = w` here as the `.data()` fix-it is not generally correct
|
||||
}
|
||||
|
||||
void foo1a() {
|
||||
int *r = new int[7];
|
||||
int *p = new int[4]; // expected-warning{{'p' is an unsafe pointer used for buffer access}} expected-note{{change type of 'p' to 'std::span' to preserve bounds information, and change 'r' to 'std::span' to propagate bounds information between them}}
|
||||
int *p = new int[4]; // expected-warning{{'p' is an unsafe pointer used for buffer access}}
|
||||
p = r;
|
||||
int tmp = p[9]; // expected-note{{used in buffer access here}}
|
||||
int *q;
|
||||
q = r;
|
||||
q = r; // FIXME: we do not fix `q = r` here as the `.data()` fix-it is not generally correct
|
||||
}
|
||||
|
||||
void foo1b() {
|
||||
@ -115,12 +115,12 @@ void foo1b() {
|
||||
}
|
||||
|
||||
void foo1c() {
|
||||
int *r = new int[7]; // expected-warning{{'r' is an unsafe pointer used for buffer access}} expected-note{{change type of 'r' to 'std::span' to preserve bounds information, and change 'q' to 'std::span' to propagate bounds information between them}}
|
||||
int *r = new int[7]; // expected-warning{{'r' is an unsafe pointer used for buffer access}}
|
||||
int *p = new int[4];
|
||||
p = r;
|
||||
p = r; // FIXME: we do not fix `p = r` here as the `.data()` fix-it is not generally correct
|
||||
int tmp = r[9]; // expected-note{{used in buffer access here}}
|
||||
int *q; // expected-warning{{'q' is an unsafe pointer used for buffer access}} expected-note{{change type of 'q' to 'std::span' to preserve bounds information, and change 'r' to 'std::span' to propagate bounds information between them}}
|
||||
q = r;
|
||||
int *q; // expected-warning{{'q' is an unsafe pointer used for buffer access}}
|
||||
q = r; // FIXME: we do not fix `q = r` here as the `.data()` fix-it is not generally correct
|
||||
tmp = q[9]; // expected-note{{used in buffer access here}}
|
||||
}
|
||||
|
||||
@ -136,8 +136,8 @@ void foo2a() {
|
||||
void foo2b() {
|
||||
int *r = new int[7];
|
||||
int *p = new int[5];
|
||||
int *q = new int[4]; // expected-warning{{'q' is an unsafe pointer used for buffer access}} expected-note{{change type of 'q' to 'std::span' to preserve bounds information, and change 'r' to 'std::span' to propagate bounds information between them}}
|
||||
p = q;
|
||||
int *q = new int[4]; // expected-warning{{'q' is an unsafe pointer used for buffer access}}
|
||||
p = q; // FIXME: we do not fix `p = q` here as the `.data()` fix-it is not generally correct
|
||||
int tmp = q[8]; // expected-note{{used in buffer access here}}
|
||||
q = r;
|
||||
}
|
||||
@ -154,9 +154,9 @@ void foo2c() {
|
||||
|
||||
void foo3a() {
|
||||
int *r = new int[7];
|
||||
int *p = new int[5]; // expected-warning{{'p' is an unsafe pointer used for buffer access}} expected-note{{change type of 'p' to 'std::span' to preserve bounds information}}
|
||||
int *p = new int[5]; // expected-warning{{'p' is an unsafe pointer used for buffer access}}
|
||||
int *q = new int[4];
|
||||
q = p;
|
||||
q = p; // FIXME: we do not fix `q = p` here as the `.data()` fix-it is not generally correct
|
||||
int tmp = p[8]; // expected-note{{used in buffer access here}}
|
||||
q = r;
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ void suppressedVarInGroup3() {
|
||||
int * b;
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
|
||||
int * c;
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:10}:"std::span<int> c"
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
|
||||
|
||||
c[5] = 5;
|
||||
#pragma clang unsafe_buffer_usage begin
|
||||
@ -182,6 +182,7 @@ void suppressedVarInGroup3() {
|
||||
#pragma clang unsafe_buffer_usage end
|
||||
a = b;
|
||||
b = c;
|
||||
// FIXME: we do not fix `a = b` and `b = c` because the `.data()` fix-it is not generally correct.
|
||||
}
|
||||
|
||||
// The implication edges are: `a` -> `b` -> `c` -> `a`.
|
||||
|
Loading…
x
Reference in New Issue
Block a user