https://github.com/NagyDonat updated https://github.com/llvm/llvm-project/pull/139939
From 8a33087fcd94d326cac602a6be83a1b34b43e1ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Wed, 14 May 2025 19:24:37 +0200 Subject: [PATCH 01/10] [WIP][analyzer] Refactor `ExplodedGraph::trim()` ...because its implementation was using a complicated two-pass graph traversal while in fact one pass is sufficient for performing that trimming operation. Note that this commit changes the interface of `trim`: it no longer accepts nullpointers within the array `Sinks` and `BugReporter.cpp` (the single non-debug caller) was modified accordingly. This also affects the interface of `DumpGraph` (which calls `trim` under the hood), but that's a debug helper which is only called if some developer compiles a tweaked version of the analyzer for local debugging and it is unlikely that a developer would pass nullpointers to it. WORK IN PROGRESS -- DO NOT MERGE! After this commit the analyzer will pick different representants from the bug report equivalence classes (because some iteration order changes), which breaks lots of testcases. --- clang/lib/StaticAnalyzer/Core/BugReporter.cpp | 3 +- .../lib/StaticAnalyzer/Core/ExplodedGraph.cpp | 110 ++++++------------ 2 files changed, 35 insertions(+), 78 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index d5bc3ac2962d5..709fb18f14789 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -2633,7 +2633,8 @@ BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph, assert(I->isValid() && "We only allow BugReporterVisitors and BugReporter itself to " "invalidate reports!"); - Nodes.emplace_back(I->getErrorNode()); + if (const ExplodedNode *ErrNode = I->getErrorNode()) + Nodes.emplace_back(ErrNode); } // The trimmed graph is created in the body of the constructor to ensure diff --git a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp index 098922d94061f..85f84af4167e0 100644 --- a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -442,60 +442,21 @@ std::unique_ptr<ExplodedGraph> ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, InterExplodedGraphMap *ForwardMap, InterExplodedGraphMap *InverseMap) const { - // FIXME: The two-pass algorithm of this function (which was introduced in - // 2008) is terribly overcomplicated and should be replaced by a single - // (backward) pass. - - if (Nodes.empty()) + if (Sinks.empty()) return nullptr; - using Pass1Ty = llvm::DenseSet<const ExplodedNode *>; - Pass1Ty Pass1; - - using Pass2Ty = InterExplodedGraphMap; - InterExplodedGraphMap Pass2Scratch; - Pass2Ty &Pass2 = ForwardMap ? *ForwardMap : Pass2Scratch; - - SmallVector<const ExplodedNode*, 10> WL1, WL2; - - // ===- Pass 1 (reverse DFS) -=== - for (const auto Sink : Sinks) - if (Sink) - WL1.push_back(Sink); - - // Process the first worklist until it is empty. - while (!WL1.empty()) { - const ExplodedNode *N = WL1.pop_back_val(); - - // Have we already visited this node? If so, continue to the next one. - if (!Pass1.insert(N).second) - continue; - - // If this is the root enqueue it to the second worklist. - if (N->Preds.empty()) { - assert(N == getRoot() && "Found non-root node with no predecessors!"); - WL2.push_back(N); - continue; - } - - // Visit our predecessors and enqueue them. - WL1.append(N->Preds.begin(), N->Preds.end()); - } + std::unique_ptr<ExplodedGraph> Trimmed = std::make_unique<ExplodedGraph>(); - // We didn't hit the root? Return with a null pointer for the new graph. - if (WL2.empty()) - return nullptr; + SmallVector<const ExplodedNode*, 32> Worklist{Sinks}; - assert(WL2.size() == 1 && "There must be only one root!"); + InterExplodedGraphMap Scratch; + if (!ForwardMap) + ForwardMap = &Scratch; - // Create an empty graph. - std::unique_ptr<ExplodedGraph> G = std::make_unique<ExplodedGraph>(); + while (!Worklist.empty()) { + const ExplodedNode *N = Worklist.pop_back_val(); - // ===- Pass 2 (forward DFS to construct the new graph) -=== - while (!WL2.empty()) { - const ExplodedNode *N = WL2.pop_back_val(); - - auto [Place, Inserted] = Pass2.try_emplace(N); + auto [Place, Inserted] = ForwardMap->try_emplace(N); // Skip this node if we have already processed it. if (!Inserted) @@ -503,48 +464,43 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, // Create the corresponding node in the new graph and record the mapping // from the old node to the new node. - ExplodedNode *NewN = G->createUncachedNode(N->getLocation(), N->State, + ExplodedNode *NewN = Trimmed->createUncachedNode(N->getLocation(), N->State, N->getID(), N->isSink()); Place->second = NewN; // Also record the reverse mapping from the new node to the old node. if (InverseMap) (*InverseMap)[NewN] = N; - // If this node is the root, designate it as such in the graph. - if (N->Preds.empty()) { - assert(N == getRoot()); - G->designateAsRoot(NewN); - } - - // In the case that some of the intended predecessors of NewN have already - // been created, we should hook them up as predecessors. + // If this is the root node, designate is as the root in the trimmed graph as well. + if (N == getRoot()) + Trimmed->designateAsRoot(NewN); - // Walk through the predecessors of 'N' and hook up their corresponding - // nodes in the new graph (if any) to the freshly created node. + // Iterate over the predecessors of the node: if they are already present + // in the trimmed graph, then add the corresponding edges with + // `addPredecessor()`, otherwise add them to the worklist. for (const ExplodedNode *Pred : N->Preds) { - Pass2Ty::iterator PI = Pass2.find(Pred); - if (PI == Pass2.end()) - continue; - - NewN->addPredecessor(const_cast<ExplodedNode *>(PI->second), *G); + auto Iterator = ForwardMap->find(Pred); + if (Iterator != ForwardMap->end()) { + NewN->addPredecessor(const_cast<ExplodedNode *>(Iterator->second), *Trimmed); + } else { + Worklist.push_back(Pred); + } } - // In the case that some of the intended successors of NewN have already - // been created, we should hook them up as successors. Otherwise, enqueue - // the new nodes from the original graph that should have nodes created - // in the new graph. + // Iterate over the successors of the node: if they are present in the + // trimmed graph, then add the corresponding edges with `addPredecessor()`. + // (If they are not present in the trimmed graph, we don't add them to the + // worklist. Maybe we'll reach them through a different direction, maybe + // they will be omitted from the trimmed graph.) for (const ExplodedNode *Succ : N->Succs) { - Pass2Ty::iterator PI = Pass2.find(Succ); - if (PI != Pass2.end()) { - const_cast<ExplodedNode *>(PI->second)->addPredecessor(NewN, *G); - continue; + auto Iterator = ForwardMap->find(Succ); + if (Iterator != ForwardMap->end()) { + const_cast<ExplodedNode *>(Iterator->second)->addPredecessor(NewN, *Trimmed); } - - // Enqueue nodes to the worklist that were marked during pass 1. - if (Pass1.count(Succ)) - WL2.push_back(Succ); } } - return G; + assert(Trimmed->getRoot() && "The root must be reachable from any nonempty set of sinks!"); + + return Trimmed; } From 348e740362e6f2bd9e747affa26e3a5bf826c4d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Thu, 15 May 2025 13:57:48 +0200 Subject: [PATCH 02/10] Simplify map lookup; unbrace --- clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp index 85f84af4167e0..121f1a5eadbe4 100644 --- a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -479,12 +479,10 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, // in the trimmed graph, then add the corresponding edges with // `addPredecessor()`, otherwise add them to the worklist. for (const ExplodedNode *Pred : N->Preds) { - auto Iterator = ForwardMap->find(Pred); - if (Iterator != ForwardMap->end()) { - NewN->addPredecessor(const_cast<ExplodedNode *>(Iterator->second), *Trimmed); - } else { + if (const ExplodedNode *Mapped = ForwardMap->lookup(Pred)) + NewN->addPredecessor(const_cast<ExplodedNode *>(Mapped), *Trimmed); + else Worklist.push_back(Pred); - } } // Iterate over the successors of the node: if they are present in the @@ -492,12 +490,9 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, // (If they are not present in the trimmed graph, we don't add them to the // worklist. Maybe we'll reach them through a different direction, maybe // they will be omitted from the trimmed graph.) - for (const ExplodedNode *Succ : N->Succs) { - auto Iterator = ForwardMap->find(Succ); - if (Iterator != ForwardMap->end()) { - const_cast<ExplodedNode *>(Iterator->second)->addPredecessor(NewN, *Trimmed); - } - } + for (const ExplodedNode *Succ : N->Succs) + if (const ExplodedNode *Mapped = ForwardMap->lookup(Succ)) + const_cast<ExplodedNode *>(Mapped)->addPredecessor(NewN, *Trimmed); } assert(Trimmed->getRoot() && "The root must be reachable from any nonempty set of sinks!"); From 300b7ce25a45ca1cd95a000de6c0568c6393e6c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Thu, 15 May 2025 14:03:35 +0200 Subject: [PATCH 03/10] Get rid of InverseMap because it was unused --- .../Core/PathSensitive/ExplodedGraph.h | 7 ++----- clang/lib/StaticAnalyzer/Core/BugReporter.cpp | 6 +++--- clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp | 16 ++++++---------- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h index e995151927c96..cf913c064933e 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -413,15 +413,12 @@ class ExplodedGraph { /// /// \param Nodes The nodes which must appear in the final graph. Presumably /// these are end-of-path nodes (i.e. they have no successors). - /// \param[out] ForwardMap An optional map from nodes in this graph to nodes + /// \param[out] NodeMap An optional map from nodes in this graph to nodes /// in the returned graph. - /// \param[out] InverseMap An optional map from nodes in the returned graph to - /// nodes in this graph. /// \returns The trimmed graph std::unique_ptr<ExplodedGraph> trim(ArrayRef<const NodeTy *> Nodes, - InterExplodedGraphMap *ForwardMap = nullptr, - InterExplodedGraphMap *InverseMap = nullptr) const; + InterExplodedGraphMap *NodeMap = nullptr) const; /// Enable tracking of recently allocated nodes for potential reclamation /// when calling reclaimRecentlyAllocatedNodes(). diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index 709fb18f14789..188de7da50c62 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -2639,8 +2639,8 @@ BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph, // The trimmed graph is created in the body of the constructor to ensure // that the DenseMaps have been initialized already. - InterExplodedGraphMap ForwardMap; - TrimmedGraph = OriginalGraph->trim(Nodes, &ForwardMap); + InterExplodedGraphMap NodeMap; + TrimmedGraph = OriginalGraph->trim(Nodes, &NodeMap); // Find the (first) error node in the trimmed graph. We just need to consult // the node map which maps from nodes in the original graph to nodes @@ -2648,7 +2648,7 @@ BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph, llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes; for (PathSensitiveBugReport *Report : bugReports) { - const ExplodedNode *NewNode = ForwardMap.lookup(Report->getErrorNode()); + const ExplodedNode *NewNode = NodeMap.lookup(Report->getErrorNode()); assert(NewNode && "Failed to construct a trimmed graph that contains this error " "node!"); diff --git a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp index 121f1a5eadbe4..7a13dbe5961b8 100644 --- a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -440,8 +440,7 @@ ExplodedNode *ExplodedGraph::createUncachedNode(const ProgramPoint &L, std::unique_ptr<ExplodedGraph> ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, - InterExplodedGraphMap *ForwardMap, - InterExplodedGraphMap *InverseMap) const { + InterExplodedGraphMap *NodeMap) const { if (Sinks.empty()) return nullptr; @@ -450,13 +449,13 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, SmallVector<const ExplodedNode*, 32> Worklist{Sinks}; InterExplodedGraphMap Scratch; - if (!ForwardMap) - ForwardMap = &Scratch; + if (!NodeMap) + NodeMap = &Scratch; while (!Worklist.empty()) { const ExplodedNode *N = Worklist.pop_back_val(); - auto [Place, Inserted] = ForwardMap->try_emplace(N); + auto [Place, Inserted] = NodeMap->try_emplace(N); // Skip this node if we have already processed it. if (!Inserted) @@ -468,9 +467,6 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, N->getID(), N->isSink()); Place->second = NewN; - // Also record the reverse mapping from the new node to the old node. - if (InverseMap) (*InverseMap)[NewN] = N; - // If this is the root node, designate is as the root in the trimmed graph as well. if (N == getRoot()) Trimmed->designateAsRoot(NewN); @@ -479,7 +475,7 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, // in the trimmed graph, then add the corresponding edges with // `addPredecessor()`, otherwise add them to the worklist. for (const ExplodedNode *Pred : N->Preds) { - if (const ExplodedNode *Mapped = ForwardMap->lookup(Pred)) + if (const ExplodedNode *Mapped = NodeMap->lookup(Pred)) NewN->addPredecessor(const_cast<ExplodedNode *>(Mapped), *Trimmed); else Worklist.push_back(Pred); @@ -491,7 +487,7 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, // worklist. Maybe we'll reach them through a different direction, maybe // they will be omitted from the trimmed graph.) for (const ExplodedNode *Succ : N->Succs) - if (const ExplodedNode *Mapped = ForwardMap->lookup(Succ)) + if (const ExplodedNode *Mapped = NodeMap->lookup(Succ)) const_cast<ExplodedNode *>(Mapped)->addPredecessor(NewN, *Trimmed); } From 7ea7d8330e4ac8b8d637336395342deb574e4f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Thu, 15 May 2025 14:07:07 +0200 Subject: [PATCH 04/10] Eliminate const_cast by using the proper type --- .../StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h | 2 +- clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h index cf913c064933e..7fb1b8dc45bfd 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -298,7 +298,7 @@ class ExplodedNode : public llvm::FoldingSetNode { }; using InterExplodedGraphMap = - llvm::DenseMap<const ExplodedNode *, const ExplodedNode *>; + llvm::DenseMap<const ExplodedNode *, ExplodedNode *>; class ExplodedGraph { protected: diff --git a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp index 7a13dbe5961b8..ee76271e2eb5d 100644 --- a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -475,8 +475,8 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, // in the trimmed graph, then add the corresponding edges with // `addPredecessor()`, otherwise add them to the worklist. for (const ExplodedNode *Pred : N->Preds) { - if (const ExplodedNode *Mapped = NodeMap->lookup(Pred)) - NewN->addPredecessor(const_cast<ExplodedNode *>(Mapped), *Trimmed); + if (ExplodedNode *Mapped = NodeMap->lookup(Pred)) + NewN->addPredecessor(Mapped, *Trimmed); else Worklist.push_back(Pred); } @@ -487,8 +487,8 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, // worklist. Maybe we'll reach them through a different direction, maybe // they will be omitted from the trimmed graph.) for (const ExplodedNode *Succ : N->Succs) - if (const ExplodedNode *Mapped = NodeMap->lookup(Succ)) - const_cast<ExplodedNode *>(Mapped)->addPredecessor(NewN, *Trimmed); + if (ExplodedNode *Mapped = NodeMap->lookup(Succ)) + Mapped->addPredecessor(NewN, *Trimmed); } assert(Trimmed->getRoot() && "The root must be reachable from any nonempty set of sinks!"); From c2a6891a417c854b2679236707a6a49f3a487b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Thu, 15 May 2025 14:59:50 +0200 Subject: [PATCH 05/10] Avoid copying a vector of node pointers --- .../Core/PathSensitive/ExplodedGraph.h | 17 ++++++++++++----- clang/lib/StaticAnalyzer/Core/BugReporter.cpp | 6 +++--- clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp | 6 ++---- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 3 ++- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h index 7fb1b8dc45bfd..911d9d350acab 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -300,6 +300,9 @@ class ExplodedNode : public llvm::FoldingSetNode { using InterExplodedGraphMap = llvm::DenseMap<const ExplodedNode *, ExplodedNode *>; +using TrimGraphWorklist = + SmallVector<const ExplodedNode*, 32>; + class ExplodedGraph { protected: friend class CoreEngine; @@ -411,13 +414,17 @@ class ExplodedGraph { /// Creates a trimmed version of the graph that only contains paths leading /// to the given nodes. /// - /// \param Nodes The nodes which must appear in the final graph. Presumably - /// these are end-of-path nodes (i.e. they have no successors). - /// \param[out] NodeMap An optional map from nodes in this graph to nodes - /// in the returned graph. + /// \param[in,out] Worklist Vector of nodes which must appear in the final + /// graph. Presumably these are end-of-path nodes + /// (i.e. they have no successors). This argument is + /// consumed and emptied by the trimming algorithm. + /// + /// \param[out] NodeMap If specified, this will be filled to map nodes from + /// this map to nodes in the returned graph. + /// /// \returns The trimmed graph std::unique_ptr<ExplodedGraph> - trim(ArrayRef<const NodeTy *> Nodes, + trim(TrimGraphWorklist &Worklist, InterExplodedGraphMap *NodeMap = nullptr) const; /// Enable tracking of recently allocated nodes for potential reclamation diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index 188de7da50c62..67972b2e8ec2c 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -2628,19 +2628,19 @@ class BugPathGetter { BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph, ArrayRef<PathSensitiveBugReport *> &bugReports) { - SmallVector<const ExplodedNode *, 32> Nodes; + TrimGraphWorklist Worklist; for (const auto I : bugReports) { assert(I->isValid() && "We only allow BugReporterVisitors and BugReporter itself to " "invalidate reports!"); if (const ExplodedNode *ErrNode = I->getErrorNode()) - Nodes.emplace_back(ErrNode); + Worklist.emplace_back(ErrNode); } // The trimmed graph is created in the body of the constructor to ensure // that the DenseMaps have been initialized already. InterExplodedGraphMap NodeMap; - TrimmedGraph = OriginalGraph->trim(Nodes, &NodeMap); + TrimmedGraph = OriginalGraph->trim(Worklist, &NodeMap); // Find the (first) error node in the trimmed graph. We just need to consult // the node map which maps from nodes in the original graph to nodes diff --git a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp index ee76271e2eb5d..cbf160a83ab2a 100644 --- a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -439,15 +439,13 @@ ExplodedNode *ExplodedGraph::createUncachedNode(const ProgramPoint &L, } std::unique_ptr<ExplodedGraph> -ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks, +ExplodedGraph::trim(TrimGraphWorklist &Worklist, InterExplodedGraphMap *NodeMap) const { - if (Sinks.empty()) + if (Worklist.empty()) return nullptr; std::unique_ptr<ExplodedGraph> Trimmed = std::make_unique<ExplodedGraph>(); - SmallVector<const ExplodedNode*, 32> Worklist{Sinks}; - InterExplodedGraphMap Scratch; if (!NodeMap) NodeMap = &Scratch; diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index ebad83dad0c8f..6a7069954c731 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -4096,7 +4096,8 @@ std::string ExprEngine::DumpGraph(bool trim, StringRef Filename) { std::string ExprEngine::DumpGraph(ArrayRef<const ExplodedNode *> Nodes, StringRef Filename) { - std::unique_ptr<ExplodedGraph> TrimmedG(G.trim(Nodes)); + TrimGraphWorklist Worklist{Nodes}; + std::unique_ptr<ExplodedGraph> TrimmedG(G.trim(Worklist)); if (!TrimmedG) { llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n"; From a8ced536abc7d31bf4479246e87e2a9f550d9f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Thu, 15 May 2025 15:03:09 +0200 Subject: [PATCH 06/10] Delete an unused type alias --- .../clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h index 911d9d350acab..0e30a42800422 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -409,8 +409,6 @@ class ExplodedGraph { llvm::BumpPtrAllocator & getAllocator() { return BVC.getAllocator(); } BumpVectorContext &getNodeAllocator() { return BVC; } - using NodeMap = llvm::DenseMap<const ExplodedNode *, ExplodedNode *>; - /// Creates a trimmed version of the graph that only contains paths leading /// to the given nodes. /// From 42d30762c3dbb18914eaed9398eb28d28cedde7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Thu, 15 May 2025 15:16:18 +0200 Subject: [PATCH 07/10] Capitalize the parameter 'bugReports' --- clang/lib/StaticAnalyzer/Core/BugReporter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index 67972b2e8ec2c..f080516574db8 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -2627,9 +2627,9 @@ class BugPathGetter { } // namespace BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph, - ArrayRef<PathSensitiveBugReport *> &bugReports) { + ArrayRef<PathSensitiveBugReport *> &BugReports) { TrimGraphWorklist Worklist; - for (const auto I : bugReports) { + for (const auto I : BugReports) { assert(I->isValid() && "We only allow BugReporterVisitors and BugReporter itself to " "invalidate reports!"); @@ -2647,7 +2647,7 @@ BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph, // in the new graph. llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes; - for (PathSensitiveBugReport *Report : bugReports) { + for (PathSensitiveBugReport *Report : BugReports) { const ExplodedNode *NewNode = NodeMap.lookup(Report->getErrorNode()); assert(NewNode && "Failed to construct a trimmed graph that contains this error " From f6b4ef520af22f8437b8b6423e68dcfae81c8690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Thu, 15 May 2025 15:23:30 +0200 Subject: [PATCH 08/10] Clarify that PathSensitiveBugReport::ErrorNode is never null The declaration of this data member was specifying `nullptr` as an initializer, but each constructor of the class initializes it to a non-null value (which is taken as an argument) and nothing changes its value later. --- .../clang/StaticAnalyzer/Core/BugReporter/BugReporter.h | 5 +++-- clang/lib/StaticAnalyzer/Core/BugReporter.cpp | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 8e1d25b3eefa1..7152a76d8649c 100644 --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -294,8 +294,9 @@ class PathSensitiveBugReport : public BugReport { protected: /// The ExplodedGraph node against which the report was thrown. It corresponds - /// to the end of the execution path that demonstrates the bug. - const ExplodedNode *ErrorNode = nullptr; + /// to the end of the execution path that demonstrates the bug. This is never + /// a nullpointer. + const ExplodedNode *ErrorNode; /// The range that corresponds to ErrorNode's program point. It is usually /// highlighted in the report. diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index f080516574db8..ef2bcdb79561c 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -2171,6 +2171,7 @@ PathSensitiveBugReport::PathSensitiveBugReport( : BugReport(Kind::PathSensitive, bt, shortDesc, desc), ErrorNode(errorNode), ErrorNodeRange(getStmt() ? getStmt()->getSourceRange() : SourceRange()), UniqueingLocation(LocationToUnique), UniqueingDecl(DeclToUnique) { + assert(ErrorNode && "The error node must not be null!"); assert(!isDependency(ErrorNode->getState() ->getAnalysisManager() .getCheckerManager() @@ -2633,8 +2634,7 @@ BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph, assert(I->isValid() && "We only allow BugReporterVisitors and BugReporter itself to " "invalidate reports!"); - if (const ExplodedNode *ErrNode = I->getErrorNode()) - Worklist.emplace_back(ErrNode); + Worklist.emplace_back(I->getErrorNode()); } // The trimmed graph is created in the body of the constructor to ensure From fde270e59862924f2ce282323ce93e83d9cd4ff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Thu, 15 May 2025 15:28:25 +0200 Subject: [PATCH 09/10] Fix misleading declaration of a loop variable It looks like an iterator, let's clarify its type and use a better name. --- clang/lib/StaticAnalyzer/Core/BugReporter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index ef2bcdb79561c..3b22b22be741d 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -2630,11 +2630,11 @@ class BugPathGetter { BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph, ArrayRef<PathSensitiveBugReport *> &BugReports) { TrimGraphWorklist Worklist; - for (const auto I : BugReports) { - assert(I->isValid() && + for (PathSensitiveBugReport *BR : BugReports) { + assert(BR->isValid() && "We only allow BugReporterVisitors and BugReporter itself to " "invalidate reports!"); - Worklist.emplace_back(I->getErrorNode()); + Worklist.emplace_back(BR->getErrorNode()); } // The trimmed graph is created in the body of the constructor to ensure From 64b117aa17e4546e58edd49d139073939a080c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Thu, 15 May 2025 15:30:06 +0200 Subject: [PATCH 10/10] Satisfy git-clang-format --- .../clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h index 0e30a42800422..235afa468692c 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -300,8 +300,7 @@ class ExplodedNode : public llvm::FoldingSetNode { using InterExplodedGraphMap = llvm::DenseMap<const ExplodedNode *, ExplodedNode *>; -using TrimGraphWorklist = - SmallVector<const ExplodedNode*, 32>; +using TrimGraphWorklist = SmallVector<const ExplodedNode *, 32>; class ExplodedGraph { protected: _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits