Skip to content

Commit 0ba604e

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 9c0a0ca commit 0ba604e

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
@@ -1972,14 +1972,18 @@ class DerefSimplePtrArithFixableGadget : public FixableGadget {
19721972
};
19731973

19741974
/// Scan the function and return a list of gadgets found with provided kits.
1975-
static std::tuple<FixableGadgetList, WarningGadgetList, DeclUseTracker>
1976-
findGadgets(const Stmt *S, ASTContext &Ctx,
1977-
const UnsafeBufferUsageHandler &Handler, bool EmitSuggestions) {
1975+
static void findGadgets(const Stmt *S, ASTContext &Ctx,
1976+
const UnsafeBufferUsageHandler &Handler,
1977+
bool EmitSuggestions, FixableGadgetList &FixableGadgets,
1978+
WarningGadgetList &WarningGadgets,
1979+
DeclUseTracker &Tracker) {
19781980

19791981
struct GadgetFinderCallback : MatchFinder::MatchCallback {
1980-
FixableGadgetList FixableGadgets;
1981-
WarningGadgetList WarningGadgets;
1982-
DeclUseTracker Tracker;
1982+
GadgetFinderCallback(FixableGadgetList &FixableGadgets,
1983+
WarningGadgetList &WarningGadgets,
1984+
DeclUseTracker &Tracker)
1985+
: FixableGadgets(FixableGadgets), WarningGadgets(WarningGadgets),
1986+
Tracker(Tracker) {}
19831987

19841988
void run(const MatchFinder::MatchResult &Result) override {
19851989
// In debug mode, assert that we've found exactly one gadget.
@@ -2020,10 +2024,14 @@ findGadgets(const Stmt *S, ASTContext &Ctx,
20202024
assert(numFound >= 1 && "Gadgets not found in match result!");
20212025
assert(numFound <= 1 && "Conflicting bind tags in gadgets!");
20222026
}
2027+
2028+
FixableGadgetList &FixableGadgets;
2029+
WarningGadgetList &WarningGadgets;
2030+
DeclUseTracker &Tracker;
20232031
};
20242032

20252033
MatchFinder M;
2026-
GadgetFinderCallback CB;
2034+
GadgetFinderCallback CB{FixableGadgets, WarningGadgets, Tracker};
20272035

20282036
// clang-format off
20292037
M.addMatcher(
@@ -2069,8 +2077,6 @@ findGadgets(const Stmt *S, ASTContext &Ctx,
20692077
}
20702078

20712079
M.match(*S, Ctx);
2072-
return {std::move(CB.FixableGadgets), std::move(CB.WarningGadgets),
2073-
std::move(CB.Tracker)};
20742080
}
20752081

20762082
// Compares AST nodes by source locations.
@@ -3896,19 +3902,19 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
38963902

38973903
SmallVector<Stmt *> Stmts;
38983904

3899-
// We do not want to visit a Lambda expression defined inside a method
3900-
// independently. Instead, it should be visited along with the outer method.
3901-
// FIXME: do we want to do the same thing for `BlockDecl`s?
3902-
if (const auto *fd = dyn_cast<CXXMethodDecl>(D)) {
3903-
if (fd->getParent()->isLambda() && fd->getParent()->isLocalClass())
3904-
return;
3905-
}
3906-
3907-
// Do not emit fixit suggestions for functions declared in an
3908-
// extern "C" block.
39093905
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
3906+
// We do not want to visit a Lambda expression defined inside a method
3907+
// independently. Instead, it should be visited along with the outer method.
3908+
// FIXME: do we want to do the same thing for `BlockDecl`s?
3909+
if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
3910+
if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
3911+
return;
3912+
}
3913+
39103914
for (FunctionDecl *FReDecl : FD->redecls()) {
39113915
if (FReDecl->isExternC()) {
3916+
// Do not emit fixit suggestions for functions declared in an
3917+
// extern "C" block.
39123918
EmitSuggestions = false;
39133919
break;
39143920
}
@@ -3921,26 +3927,29 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
39213927
Stmts.push_back(CI->getInit());
39223928
}
39233929
}
3924-
}
3925-
3926-
if (const auto *FD = dyn_cast<FieldDecl>(D)) {
3930+
} else if (const auto *FlD = dyn_cast<FieldDecl>(D)) {
39273931
// Visit in-class initializers for fields.
3928-
if (!FD->hasInClassInitializer())
3932+
if (!FlD->hasInClassInitializer())
39293933
return;
3930-
3931-
Stmts.push_back(FD->getInClassInitializer());
3932-
}
3933-
3934-
if (isa<BlockDecl>(D) || isa<ObjCMethodDecl>(D)) {
3934+
Stmts.push_back(FlD->getInClassInitializer());
3935+
// In a FieldDecl there is no function body, there is only a single
3936+
// statement, and the suggestions machinery is not set up to handle that
3937+
// kind of structure yet and would give poor suggestions or likely even hit
3938+
// asserts.
3939+
EmitSuggestions = false;
3940+
} else if (isa<BlockDecl>(D) || isa<ObjCMethodDecl>(D)) {
39353941
Stmts.push_back(D->getBody());
39363942
}
39373943

39383944
assert(!Stmts.empty());
39393945

3946+
FixableGadgetList FixableGadgets;
3947+
WarningGadgetList WarningGadgets;
3948+
DeclUseTracker Tracker;
39403949
for (Stmt *S : Stmts) {
3941-
auto [FixableGadgets, WarningGadgets, Tracker] =
3942-
findGadgets(S, D->getASTContext(), Handler, EmitSuggestions);
3943-
applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
3944-
std::move(Tracker), Handler, EmitSuggestions);
3950+
findGadgets(S, D->getASTContext(), Handler, EmitSuggestions, FixableGadgets,
3951+
WarningGadgets, Tracker);
39453952
}
3953+
applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
3954+
std::move(Tracker), Handler, EmitSuggestions);
39463955
}

clang/lib/Sema/AnalysisBasedWarnings.cpp

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

25132513
bool VisitFieldDecl(FieldDecl *Node) {
2514-
if (cast<DeclContext>(Node->getParent())->isDependentContext())
2514+
DeclContext *DeclCtx;
2515+
if (auto *ID = dyn_cast<ObjCIvarDecl>(Node))
2516+
DeclCtx = cast<DeclContext>(ID->getContainingInterface());
2517+
else
2518+
DeclCtx = cast<DeclContext>(Node->getParent());
2519+
if (DeclCtx->isDependentContext())
25152520
return true; // Not to analyze dependent decl
25162521
if (Node->hasInClassInitializer())
25172522
Callback(Node);

0 commit comments

Comments
 (0)