@@ -2212,16 +2212,30 @@ static bool overlapWithMacro(const FixItList &FixIts) {
2212
2212
});
2213
2213
}
2214
2214
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);
2222
2235
}
2223
2236
}
2224
- return false ;
2237
+ for (auto *VarToErase : ToErase)
2238
+ FixItsForVariable.erase (VarToErase);
2225
2239
}
2226
2240
2227
2241
static std::map<const VarDecl *, FixItList>
@@ -2230,7 +2244,14 @@ getFixIts(FixableGadgetSets &FixablesForAllVars, const Strategy &S,
2230
2244
/* The function decl under analysis */ const Decl *D,
2231
2245
const DeclUseTracker &Tracker, UnsafeBufferUsageHandler &Handler,
2232
2246
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.
2233
2250
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'.
2234
2255
for (const auto &[VD, Fixables] : FixablesForAllVars.byVar ) {
2235
2256
FixItsForVariable[VD] =
2236
2257
fixVariable (VD, S.lookup (VD), D, Tracker, Ctx, Handler);
@@ -2240,64 +2261,36 @@ getFixIts(FixableGadgetSets &FixablesForAllVars, const Strategy &S,
2240
2261
FixItsForVariable.erase (VD);
2241
2262
continue ;
2242
2263
}
2243
- bool ImpossibleToFix = false ;
2244
- llvm::SmallVector<FixItHint, 16 > FixItsForVD;
2245
2264
for (const auto &F : Fixables) {
2246
2265
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
- }
2262
2266
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 ());
2286
2270
continue ;
2287
2271
}
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
2296
2278
FixItsForVariable.erase (VD);
2297
- continue ;
2279
+ break ;
2298
2280
}
2299
2281
}
2300
2282
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
+
2301
2294
// The map that maps each variable `v` to fix-its for the whole group where
2302
2295
// `v` is in:
2303
2296
std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
@@ -2315,10 +2308,20 @@ getFixIts(FixableGadgetSets &FixablesForAllVars, const Strategy &S,
2315
2308
FixItsForVariable[GrpMate].end ());
2316
2309
}
2317
2310
}
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++;
2318
2322
return FinalFixItsForVariable;
2319
2323
}
2320
2324
2321
-
2322
2325
static Strategy
2323
2326
getNaiveStrategy (const llvm::SmallVectorImpl<const VarDecl *> &UnsafeVars) {
2324
2327
Strategy S;
@@ -2356,6 +2359,7 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
2356
2359
assert (D && D->getBody ());
2357
2360
// We do not want to visit a Lambda expression defined inside a method independently.
2358
2361
// Instead, it should be visited along with the outer method.
2362
+ // FIXME: do we want to do the same thing for `BlockDecl`s?
2359
2363
if (const auto *fd = dyn_cast<CXXMethodDecl>(D)) {
2360
2364
if (fd->getParent ()->isLambda () && fd->getParent ()->isLocalClass ())
2361
2365
return ;
0 commit comments