[clang] 9ca929f - [NFC][analyzer] Eliminate BranchNodeBuilder (#192744)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 20 01:25:26 PDT 2026
Author: DonĂ¡t Nagy
Date: 2026-04-20T10:25:22+02:00
New Revision: 9ca929f53508f93e282f37cb3e1295b53d7e58fb
URL: https://github.com/llvm/llvm-project/commit/9ca929f53508f93e282f37cb3e1295b53d7e58fb
DIFF: https://github.com/llvm/llvm-project/commit/9ca929f53508f93e282f37cb3e1295b53d7e58fb.diff
LOG: [NFC][analyzer] Eliminate BranchNodeBuilder (#192744)
This commit removes the class `BranchNodeBuilder` because it didn't
provide enough advantages to justify its existence. (This class wasn't
as bad as `SwitchNodeBuilder` and `IndirectGotoNodeBuilder`, but its
single method was very simple so I still think that it is better to
eliminate it.)
To be able to unify the use of `LocationContext`s in `processBranch`,
this commit also replaces the overcomplicated helper function
`getInlinedLocationContext` with use of `LocationContext::inTopFrame()`.
The code of this helper function was written in March 2012, before the
introduction of `inTopFrame` (November 2012). It was originally in the
body of the method `ExprEngine::processCFGBlockEntrance` and when I
extracted it in 2025 by commit 9600a12f0de233324b559f60997b9c2db153fede
(because I also needed to call it from `processBranch`) I didn't notice
that I can achieve the same goal with simpler logic.
Additionally, a last stray reference to `friend class SwitchNodeBuilder`
is removed (it was overlooked I removed that class in
c80443cd37b2e2788cba67ffa180a6331e5f0791).
Added:
Modified:
clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 7dfdca0d54a67..57b0947093b78 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -316,21 +316,6 @@ class NodeBuilder {
void addNodes(ExplodedNode *N) { Frontier.insert(N); }
};
-/// BranchNodeBuilder is responsible for constructing the nodes
-/// corresponding to the two branches of the if statement - true and false.
-class BranchNodeBuilder : public NodeBuilder {
- const CFGBlock *DstT;
- const CFGBlock *DstF;
-
-public:
- BranchNodeBuilder(ExplodedNodeSet &DstSet, const NodeBuilderContext &C,
- const CFGBlock *DT, const CFGBlock *DF)
- : NodeBuilder(DstSet, C), DstT(DT), DstF(DF) {}
-
- ExplodedNode *generateNode(ProgramStateRef State, bool branch,
- ExplodedNode *Pred);
-};
-
} // namespace ento
} // namespace clang
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index bb2297a6889c9..2988b1bbad68f 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -64,11 +64,9 @@ class ExplodedGraph;
// successors to it at any time after creating it.
class ExplodedNode : public llvm::FoldingSetNode {
- friend class BranchNodeBuilder;
friend class CoreEngine;
friend class ExplodedGraph;
friend class NodeBuilder;
- friend class SwitchNodeBuilder;
/// Efficiently stores a list of ExplodedNodes, or an optional flag.
///
diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 17bee557fe029..89d6bc7a6df3e 100644
--- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -693,17 +693,3 @@ ExplodedNode *NodeBuilder::generateNode(const ProgramPoint &Loc,
return N;
}
-
-ExplodedNode *BranchNodeBuilder::generateNode(ProgramStateRef State,
- bool Branch,
- ExplodedNode *NodePred) {
- const CFGBlock *Dst = Branch ? DstT : DstF;
-
- if (!Dst)
- return nullptr;
-
- ProgramPoint Loc =
- BlockEdge(C.getBlock(), Dst, NodePred->getLocationContext());
- ExplodedNode *Succ = NodeBuilder::generateNode(Loc, State, NodePred);
- return Succ;
-}
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 35abd792a5ad0..b69b45acb7989 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1641,13 +1641,13 @@ void ExprEngine::processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
ExplodedNodeSet &Dst,
const CFGBlock *DstT,
const CFGBlock *DstF) {
- BranchNodeBuilder TempDtorBuilder(Dst, *currBldrCtx, DstT, DstF);
ProgramStateRef State = Pred->getState();
const LocationContext *LC = Pred->getLocationContext();
- if (getObjectUnderConstruction(State, BTE, LC)) {
- TempDtorBuilder.generateNode(State, true, Pred);
- } else {
- TempDtorBuilder.generateNode(State, false, Pred);
+
+ std::optional<SVal> Obj = getObjectUnderConstruction(State, BTE, LC);
+ if (const CFGBlock *DstBlock = Obj ? DstT : DstF) {
+ BlockEdge BE(getCurrBlock(), DstBlock, LC);
+ Dst.insert(Engine.makeNode(BE, State, Pred));
}
}
@@ -2547,20 +2547,6 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
return true;
}
-/// Return the innermost location context which is inlined at `Node`, unless
-/// it's the top-level (entry point) location context.
-static const LocationContext *getInlinedLocationContext(ExplodedNode *Node,
- ExplodedGraph &G) {
- const LocationContext *CalleeLC = Node->getLocation().getLocationContext();
- const LocationContext *RootLC =
- G.getRoot()->getLocation().getLocationContext();
-
- if (CalleeLC->getStackFrame() == RootLC->getStackFrame())
- return nullptr;
-
- return CalleeLC;
-}
-
/// Block entrance. (Update counters).
/// FIXME: `BlockEdge &L` is only used for debug statistics, consider removing
/// it and using `BlockEntrance &BE` (where `BlockEntrance` is a subtype of
@@ -2620,7 +2606,8 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
const ExplodedNode *Sink =
Builder.generateSink(TaggedLoc, Pred->getState(), Pred);
- if (const LocationContext *LC = getInlinedLocationContext(Pred, G)) {
+ const LocationContext *LC = Pred->getLocationContext();
+ if (!LC->inTopFrame()) {
// FIXME: This will unconditionally prevent inlining this function (even
// from other entry points), which is not a reasonable heuristic: even if
// we reached max block count on this particular execution path, there
@@ -2846,10 +2833,17 @@ void ExprEngine::processBranch(
assert((!Condition || !isa<CXXBindTemporaryExpr>(Condition)) &&
"CXXBindTemporaryExprs are handled by processBindTemporary.");
+ const LocationContext *LC = Pred->getLocationContext();
+
// Check for NULL conditions; e.g. "for(;;)"
if (!Condition) {
- BranchNodeBuilder NullCondBldr(Dst, *currBldrCtx, DstT, DstF);
- NullCondBldr.generateNode(Pred->getState(), true, Pred);
+ if (!DstT) {
+ // I _hope_ that this "null condition + null transition to loop body"
+ // case is impossible, but I cannot prove this, so let's cover it.
+ return;
+ }
+ BlockEdge BE(getCurrBlock(), DstT, LC);
+ Dst.insert(Engine.makeNode(BE, Pred->getState(), Pred));
return;
}
@@ -2868,7 +2862,6 @@ void ExprEngine::processBranch(
if (CheckersOutSet.empty())
return;
- BranchNodeBuilder Builder(Dst, *currBldrCtx, DstT, DstF);
for (ExplodedNode *PredN : CheckersOutSet) {
ProgramStateRef PrevState = PredN->getState();
@@ -2914,7 +2907,10 @@ void ExprEngine::processBranch(
// default). If we intend to support and stabilize the loop widening,
// we must ensure that it 'plays nicely' with this logic.
if (!SkipTrueBranch || AMgr.options.ShouldWidenLoops) {
- Builder.generateNode(StTrue, true, PredN);
+ if (DstT) {
+ BlockEdge BE(getCurrBlock(), DstT, LC);
+ Dst.insert(Engine.makeNode(BE, StTrue, PredN));
+ }
} else if (!AMgr.options.InlineFunctionsWithAmbiguousLoops) {
// FIXME: There is an ancient and arbitrary heuristic in
// `ExprEngine::processCFGBlockEntrance` which prevents all further
@@ -2931,7 +2927,7 @@ void ExprEngine::processBranch(
// (activates if the third iteration can be entered, and will not
// recognize cases where the fourth iteration would't be completed), but
// should be good enough for practical purposes.
- if (const LocationContext *LC = getInlinedLocationContext(Pred, G)) {
+ if (!LC->inTopFrame()) {
Engine.FunctionSummaries->markShouldNotInline(
LC->getStackFrame()->getDecl());
}
@@ -2954,8 +2950,10 @@ void ExprEngine::processBranch(
bool BeforeFirstIteration = IterationsCompletedInLoop == std::optional{0};
bool SkipFalseBranch = BothFeasible && BeforeFirstIteration &&
AMgr.options.ShouldAssumeAtLeastOneIteration;
- if (!SkipFalseBranch)
- Builder.generateNode(StFalse, false, PredN);
+ if (!SkipFalseBranch && DstF) {
+ BlockEdge BE(getCurrBlock(), DstF, LC);
+ Dst.insert(Engine.makeNode(BE, StFalse, PredN));
+ }
}
}
}
@@ -2971,15 +2969,15 @@ void ExprEngine::processStaticInitializer(const DeclStmt *DS,
const CFGBlock *DstT,
const CFGBlock *DstF) {
const auto *VD = cast<VarDecl>(DS->getSingleDecl());
- ProgramStateRef state = Pred->getState();
- bool initHasRun = state->contains<InitializedGlobalsSet>(VD);
- BranchNodeBuilder Builder(Dst, *currBldrCtx, DstT, DstF);
+ ProgramStateRef State = Pred->getState();
+ bool InitHasRun = State->contains<InitializedGlobalsSet>(VD);
+ if (!InitHasRun)
+ State = State->add<InitializedGlobalsSet>(VD);
- if (!initHasRun) {
- state = state->add<InitializedGlobalsSet>(VD);
+ if (const CFGBlock *DstBlock = InitHasRun ? DstT : DstF) {
+ BlockEdge BE(getCurrBlock(), DstBlock, Pred->getLocationContext());
+ Dst.insert(Engine.makeNode(BE, State, Pred));
}
-
- Builder.generateNode(state, initHasRun, Pred);
}
/// processIndirectGoto - Called by CoreEngine. Used to generate successor
More information about the cfe-commits
mailing list