Skip to content

Commit c0e634d

Browse files
committed
applyGadgets once per function and avoid fixits in field initializers
findGadgets() collects all gadgets into a single list, using a single DeclUseTracker. Then applyGadgets() is called once with the full list for a method (including for a ctor with initializers). Handle ObjC interface variables as they return null from getParent(). Instead go through getContainingInterface() to get the DeclContext. Disable fixits in field initializers as the machinery will not expect a statement that is not a function body at this time.
1 parent 273f93f commit c0e634d

File tree

2 files changed

+47
-33
lines changed

2 files changed

+47
-33
lines changed

clang/lib/Analysis/UnsafeBufferUsage.cpp

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,14 +1386,18 @@ class DerefSimplePtrArithFixableGadget : public FixableGadget {
13861386
};
13871387

13881388
/// Scan the function and return a list of gadgets found with provided kits.
1389-
static std::tuple<FixableGadgetList, WarningGadgetList, DeclUseTracker>
1390-
findGadgets(const Stmt *S, ASTContext &Ctx,
1391-
const UnsafeBufferUsageHandler &Handler, bool EmitSuggestions) {
1389+
static void findGadgets(const Stmt *S, ASTContext &Ctx,
1390+
const UnsafeBufferUsageHandler &Handler,
1391+
bool EmitSuggestions, FixableGadgetList &FixableGadgets,
1392+
WarningGadgetList &WarningGadgets,
1393+
DeclUseTracker &Tracker) {
13921394

13931395
struct GadgetFinderCallback : MatchFinder::MatchCallback {
1394-
FixableGadgetList FixableGadgets;
1395-
WarningGadgetList WarningGadgets;
1396-
DeclUseTracker Tracker;
1396+
GadgetFinderCallback(FixableGadgetList &FixableGadgets,
1397+
WarningGadgetList &WarningGadgets,
1398+
DeclUseTracker &Tracker)
1399+
: FixableGadgets(FixableGadgets), WarningGadgets(WarningGadgets),
1400+
Tracker(Tracker) {}
13971401

13981402
void run(const MatchFinder::MatchResult &Result) override {
13991403
// In debug mode, assert that we've found exactly one gadget.
@@ -1434,10 +1438,14 @@ findGadgets(const Stmt *S, ASTContext &Ctx,
14341438
assert(numFound >= 1 && "Gadgets not found in match result!");
14351439
assert(numFound <= 1 && "Conflicting bind tags in gadgets!");
14361440
}
1441+
1442+
FixableGadgetList &FixableGadgets;
1443+
WarningGadgetList &WarningGadgets;
1444+
DeclUseTracker &Tracker;
14371445
};
14381446

14391447
MatchFinder M;
1440-
GadgetFinderCallback CB;
1448+
GadgetFinderCallback CB{FixableGadgets, WarningGadgets, Tracker};
14411449

14421450
// clang-format off
14431451
M.addMatcher(
@@ -1484,8 +1492,6 @@ findGadgets(const Stmt *S, ASTContext &Ctx,
14841492
}
14851493

14861494
M.match(*S, Ctx);
1487-
return {std::move(CB.FixableGadgets), std::move(CB.WarningGadgets),
1488-
std::move(CB.Tracker)};
14891495
}
14901496

14911497
// Compares AST nodes by source locations.
@@ -3312,19 +3318,19 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
33123318

33133319
SmallVector<Stmt *> Stmts;
33143320

3315-
// We do not want to visit a Lambda expression defined inside a method
3316-
// independently. Instead, it should be visited along with the outer method.
3317-
// FIXME: do we want to do the same thing for `BlockDecl`s?
3318-
if (const auto *fd = dyn_cast<CXXMethodDecl>(D)) {
3319-
if (fd->getParent()->isLambda() && fd->getParent()->isLocalClass())
3320-
return;
3321-
}
3322-
3323-
// Do not emit fixit suggestions for functions declared in an
3324-
// extern "C" block.
33253321
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
3322+
// We do not want to visit a Lambda expression defined inside a method
3323+
// independently. Instead, it should be visited along with the outer method.
3324+
// FIXME: do we want to do the same thing for `BlockDecl`s?
3325+
if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
3326+
if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
3327+
return;
3328+
}
3329+
33263330
for (FunctionDecl *FReDecl : FD->redecls()) {
33273331
if (FReDecl->isExternC()) {
3332+
// Do not emit fixit suggestions for functions declared in an
3333+
// extern "C" block.
33283334
EmitSuggestions = false;
33293335
break;
33303336
}
@@ -3337,26 +3343,29 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
33373343
Stmts.push_back(CI->getInit());
33383344
}
33393345
}
3340-
}
3341-
3342-
if (const auto *FD = dyn_cast<FieldDecl>(D)) {
3346+
} else if (const auto *FlD = dyn_cast<FieldDecl>(D)) {
33433347
// Visit in-class initializers for fields.
3344-
if (!FD->hasInClassInitializer())
3348+
if (!FlD->hasInClassInitializer())
33453349
return;
3346-
3347-
Stmts.push_back(FD->getInClassInitializer());
3348-
}
3349-
3350-
if (isa<BlockDecl>(D) || isa<ObjCMethodDecl>(D)) {
3350+
Stmts.push_back(FlD->getInClassInitializer());
3351+
// In a FieldDecl there is no function body, there is only a single
3352+
// statement, and the suggestions machinery is not set up to handle that
3353+
// kind of structure yet and would give poor suggestions or likely even hit
3354+
// asserts.
3355+
EmitSuggestions = false;
3356+
} else if (isa<BlockDecl>(D) || isa<ObjCMethodDecl>(D)) {
33513357
Stmts.push_back(D->getBody());
33523358
}
33533359

33543360
assert(!Stmts.empty());
33553361

3362+
FixableGadgetList FixableGadgets;
3363+
WarningGadgetList WarningGadgets;
3364+
DeclUseTracker Tracker;
33563365
for (Stmt *S : Stmts) {
3357-
auto [FixableGadgets, WarningGadgets, Tracker] =
3358-
findGadgets(S, D->getASTContext(), Handler, EmitSuggestions);
3359-
applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
3360-
std::move(Tracker), Handler, EmitSuggestions);
3366+
findGadgets(S, D->getASTContext(), Handler, EmitSuggestions, FixableGadgets,
3367+
WarningGadgets, Tracker);
33613368
}
3369+
applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
3370+
std::move(Tracker), Handler, EmitSuggestions);
33623371
}

clang/lib/Sema/AnalysisBasedWarnings.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2472,7 +2472,12 @@ class CallableVisitor : public RecursiveASTVisitor<CallableVisitor> {
24722472
: Callback(Callback) {}
24732473

24742474
bool VisitFieldDecl(FieldDecl *Node) {
2475-
if (cast<DeclContext>(Node->getParent())->isDependentContext())
2475+
DeclContext *DeclCtx;
2476+
if (auto *ID = dyn_cast<ObjCIvarDecl>(Node))
2477+
DeclCtx = cast<DeclContext>(ID->getContainingInterface());
2478+
else
2479+
DeclCtx = cast<DeclContext>(Node->getParent());
2480+
if (DeclCtx->isDependentContext())
24762481
return true; // Not to analyze dependent decl
24772482
if (Node->hasInClassInitializer())
24782483
Callback(Node);

0 commit comments

Comments
 (0)