Skip to content

Commit acc8a33

Browse files
committed
[-Wunsafe-buffer-usage][NFC] Refactor getFixIts---where fix-its are generated
Refactor the getFixIts function for better readability. Reviewed by: NoQ (Artem Dergachev), t-rasmud (Rashmi Mudduluru) Differential revision: https://reviews.llvm.org/D156762
1 parent 80b787e commit acc8a33

File tree

1 file changed

+62
-58
lines changed

1 file changed

+62
-58
lines changed

clang/lib/Analysis/UnsafeBufferUsage.cpp

Lines changed: 62 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2212,16 +2212,30 @@ static bool overlapWithMacro(const FixItList &FixIts) {
22122212
});
22132213
}
22142214

2215-
static bool impossibleToFixForVar(const FixableGadgetSets &FixablesForAllVars,
2216-
const Strategy &S,
2217-
const VarDecl * Var) {
2218-
for (const auto &F : FixablesForAllVars.byVar.find(Var)->second) {
2219-
std::optional<FixItList> Fixits = F->getFixits(S);
2220-
if (!Fixits) {
2221-
return true;
2215+
// Erases variables in `FixItsForVariable`, if such a variable has an unfixable
2216+
// group mate. A variable `v` is unfixable iff `FixItsForVariable` does not
2217+
// contain `v`.
2218+
static void eraseVarsForUnfixableGroupMates(
2219+
std::map<const VarDecl *, FixItList> &FixItsForVariable,
2220+
const VariableGroupsManager &VarGrpMgr) {
2221+
// Variables will be removed from `FixItsForVariable`:
2222+
SmallVector<const VarDecl *, 8> ToErase;
2223+
2224+
for (auto [VD, Ignore] : FixItsForVariable) {
2225+
VarGrpRef Grp = VarGrpMgr.getGroupOfVar(VD);
2226+
if (llvm::any_of(Grp,
2227+
[&FixItsForVariable](const VarDecl *GrpMember) -> bool {
2228+
return FixItsForVariable.find(GrpMember) ==
2229+
FixItsForVariable.end();
2230+
})) {
2231+
// At least one group member cannot be fixed, so we have to erase the
2232+
// whole group:
2233+
for (const VarDecl *Member : Grp)
2234+
ToErase.push_back(Member);
22222235
}
22232236
}
2224-
return false;
2237+
for (auto *VarToErase : ToErase)
2238+
FixItsForVariable.erase(VarToErase);
22252239
}
22262240

22272241
static std::map<const VarDecl *, FixItList>
@@ -2230,7 +2244,14 @@ getFixIts(FixableGadgetSets &FixablesForAllVars, const Strategy &S,
22302244
/* The function decl under analysis */ const Decl *D,
22312245
const DeclUseTracker &Tracker, UnsafeBufferUsageHandler &Handler,
22322246
const VariableGroupsManager &VarGrpMgr) {
2247+
// `FixItsForVariable` will map each variable to a set of fix-its directly
2248+
// associated to the variable itself. Fix-its of distinct variables in
2249+
// `FixItsForVariable` are disjoint.
22332250
std::map<const VarDecl *, FixItList> FixItsForVariable;
2251+
2252+
// Populate `FixItsForVariable` with fix-its directly associated with each
2253+
// variable. Fix-its directly associated to a variable 'v' are the ones
2254+
// produced by the `FixableGadget`s whose claimed variable is 'v'.
22342255
for (const auto &[VD, Fixables] : FixablesForAllVars.byVar) {
22352256
FixItsForVariable[VD] =
22362257
fixVariable(VD, S.lookup(VD), D, Tracker, Ctx, Handler);
@@ -2240,64 +2261,36 @@ getFixIts(FixableGadgetSets &FixablesForAllVars, const Strategy &S,
22402261
FixItsForVariable.erase(VD);
22412262
continue;
22422263
}
2243-
bool ImpossibleToFix = false;
2244-
llvm::SmallVector<FixItHint, 16> FixItsForVD;
22452264
for (const auto &F : Fixables) {
22462265
std::optional<FixItList> Fixits = F->getFixits(S);
2247-
if (!Fixits) {
2248-
#ifndef NDEBUG
2249-
Handler.addDebugNoteForVar(
2250-
VD, F->getBaseStmt()->getBeginLoc(),
2251-
("gadget '" + F->getDebugName() + "' refused to produce a fix")
2252-
.str());
2253-
#endif
2254-
ImpossibleToFix = true;
2255-
break;
2256-
} else {
2257-
const FixItList CorrectFixes = Fixits.value();
2258-
FixItsForVD.insert(FixItsForVD.end(), CorrectFixes.begin(),
2259-
CorrectFixes.end());
2260-
}
2261-
}
22622266

2263-
if (ImpossibleToFix) {
2264-
FixItsForVariable.erase(VD);
2265-
continue;
2266-
}
2267-
2268-
2269-
{
2270-
const auto VarGroupForVD = VarGrpMgr.getGroupOfVar(VD);
2271-
for (const VarDecl * V : VarGroupForVD) {
2272-
if (V == VD) {
2273-
continue;
2274-
}
2275-
if (impossibleToFixForVar(FixablesForAllVars, S, V)) {
2276-
ImpossibleToFix = true;
2277-
break;
2278-
}
2279-
}
2280-
2281-
if (ImpossibleToFix) {
2282-
FixItsForVariable.erase(VD);
2283-
for (const VarDecl * V : VarGroupForVD) {
2284-
FixItsForVariable.erase(V);
2285-
}
2267+
if (Fixits) {
2268+
FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
2269+
Fixits->begin(), Fixits->end());
22862270
continue;
22872271
}
2288-
}
2289-
FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
2290-
FixItsForVD.begin(), FixItsForVD.end());
2291-
2292-
// Fix-it shall not overlap with macros or/and templates:
2293-
if (overlapWithMacro(FixItsForVariable[VD]) ||
2294-
clang::internal::anyConflict(FixItsForVariable[VD],
2295-
Ctx.getSourceManager())) {
2272+
#ifndef NDEBUG
2273+
Handler.addDebugNoteForVar(
2274+
VD, F->getBaseStmt()->getBeginLoc(),
2275+
("gadget '" + F->getDebugName() + "' refused to produce a fix")
2276+
.str());
2277+
#endif
22962278
FixItsForVariable.erase(VD);
2297-
continue;
2279+
break;
22982280
}
22992281
}
23002282

2283+
// `FixItsForVariable` now contains only variables that can be
2284+
// fixed. A variable can be fixed if its' declaration and all Fixables
2285+
// associated to it can all be fixed.
2286+
2287+
// To further remove from `FixItsForVariable` variables whose group mates
2288+
// cannot be fixed...
2289+
eraseVarsForUnfixableGroupMates(FixItsForVariable, VarGrpMgr);
2290+
// Now `FixItsForVariable` gets further reduced: a variable is in
2291+
// `FixItsForVariable` iff it can be fixed and all its group mates can be
2292+
// fixed.
2293+
23012294
// The map that maps each variable `v` to fix-its for the whole group where
23022295
// `v` is in:
23032296
std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
@@ -2315,10 +2308,20 @@ getFixIts(FixableGadgetSets &FixablesForAllVars, const Strategy &S,
23152308
FixItsForVariable[GrpMate].end());
23162309
}
23172310
}
2311+
// Fix-its that will be applied in one step shall NOT:
2312+
// 1. overlap with macros or/and templates; or
2313+
// 2. conflict with each other.
2314+
// Otherwise, the fix-its will be dropped.
2315+
for (auto Iter = FinalFixItsForVariable.begin();
2316+
Iter != FinalFixItsForVariable.end();)
2317+
if (overlapWithMacro(Iter->second) ||
2318+
clang::internal::anyConflict(Iter->second, Ctx.getSourceManager())) {
2319+
Iter = FinalFixItsForVariable.erase(Iter);
2320+
} else
2321+
Iter++;
23182322
return FinalFixItsForVariable;
23192323
}
23202324

2321-
23222325
static Strategy
23232326
getNaiveStrategy(const llvm::SmallVectorImpl<const VarDecl *> &UnsafeVars) {
23242327
Strategy S;
@@ -2356,6 +2359,7 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
23562359
assert(D && D->getBody());
23572360
// We do not want to visit a Lambda expression defined inside a method independently.
23582361
// Instead, it should be visited along with the outer method.
2362+
// FIXME: do we want to do the same thing for `BlockDecl`s?
23592363
if (const auto *fd = dyn_cast<CXXMethodDecl>(D)) {
23602364
if (fd->getParent()->isLambda() && fd->getParent()->isLocalClass())
23612365
return;

0 commit comments

Comments
 (0)