/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===- CoreEngine.h - Path-Sensitive Dataflow Engine ------------*- C++ -*-===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // |
9 | | // This file defines a generic engine for intraprocedural, path-sensitive, |
10 | | // dataflow analysis via graph reachability. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H |
15 | | #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H |
16 | | |
17 | | #include "clang/AST/Stmt.h" |
18 | | #include "clang/Analysis/AnalysisDeclContext.h" |
19 | | #include "clang/Analysis/CFG.h" |
20 | | #include "clang/Analysis/ProgramPoint.h" |
21 | | #include "clang/Basic/LLVM.h" |
22 | | #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" |
23 | | #include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" |
24 | | #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" |
25 | | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" |
26 | | #include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h" |
27 | | #include "llvm/ADT/SmallVector.h" |
28 | | #include "llvm/ADT/iterator_range.h" |
29 | | #include "llvm/Support/Casting.h" |
30 | | #include <cassert> |
31 | | #include <memory> |
32 | | #include <utility> |
33 | | #include <vector> |
34 | | |
35 | | namespace clang { |
36 | | |
37 | | class AnalyzerOptions; |
38 | | class CXXBindTemporaryExpr; |
39 | | class Expr; |
40 | | class LabelDecl; |
41 | | |
42 | | namespace ento { |
43 | | |
44 | | class FunctionSummariesTy; |
45 | | class ExprEngine; |
46 | | |
47 | | //===----------------------------------------------------------------------===// |
48 | | /// CoreEngine - Implements the core logic of the graph-reachability |
49 | | /// analysis. It traverses the CFG and generates the ExplodedGraph. |
50 | | /// Program "states" are treated as opaque void pointers. |
51 | | /// The template class CoreEngine (which subclasses CoreEngine) |
52 | | /// provides the matching component to the engine that knows the actual types |
53 | | /// for states. Note that this engine only dispatches to transfer functions |
54 | | /// at the statement and block-level. The analyses themselves must implement |
55 | | /// any transfer function logic and the sub-expression level (if any). |
56 | | class CoreEngine { |
57 | | friend class CommonNodeBuilder; |
58 | | friend class EndOfFunctionNodeBuilder; |
59 | | friend class ExprEngine; |
60 | | friend class IndirectGotoNodeBuilder; |
61 | | friend class NodeBuilder; |
62 | | friend struct NodeBuilderContext; |
63 | | friend class SwitchNodeBuilder; |
64 | | |
65 | | public: |
66 | | using BlocksExhausted = |
67 | | std::vector<std::pair<BlockEdge, const ExplodedNode *>>; |
68 | | |
69 | | using BlocksAborted = |
70 | | std::vector<std::pair<const CFGBlock *, const ExplodedNode *>>; |
71 | | |
72 | | private: |
73 | | ExprEngine &ExprEng; |
74 | | |
75 | | /// G - The simulation graph. Each node is a (location,state) pair. |
76 | | mutable ExplodedGraph G; |
77 | | |
78 | | /// WList - A set of queued nodes that need to be processed by the |
79 | | /// worklist algorithm. It is up to the implementation of WList to decide |
80 | | /// the order that nodes are processed. |
81 | | std::unique_ptr<WorkList> WList; |
82 | | std::unique_ptr<WorkList> CTUWList; |
83 | | |
84 | | /// BCounterFactory - A factory object for created BlockCounter objects. |
85 | | /// These are used to record for key nodes in the ExplodedGraph the |
86 | | /// number of times different CFGBlocks have been visited along a path. |
87 | | BlockCounter::Factory BCounterFactory; |
88 | | |
89 | | /// The locations where we stopped doing work because we visited a location |
90 | | /// too many times. |
91 | | BlocksExhausted blocksExhausted; |
92 | | |
93 | | /// The locations where we stopped because the engine aborted analysis, |
94 | | /// usually because it could not reason about something. |
95 | | BlocksAborted blocksAborted; |
96 | | |
97 | | /// The information about functions shared by the whole translation unit. |
98 | | /// (This data is owned by AnalysisConsumer.) |
99 | | FunctionSummariesTy *FunctionSummaries; |
100 | | |
101 | | /// Add path tags with some useful data along the path when we see that |
102 | | /// something interesting is happening. This field is the allocator for such |
103 | | /// tags. |
104 | | DataTag::Factory DataTags; |
105 | | |
106 | | void setBlockCounter(BlockCounter C); |
107 | | |
108 | | void generateNode(const ProgramPoint &Loc, |
109 | | ProgramStateRef State, |
110 | | ExplodedNode *Pred); |
111 | | |
112 | | void HandleBlockEdge(const BlockEdge &E, ExplodedNode *Pred); |
113 | | void HandleBlockEntrance(const BlockEntrance &E, ExplodedNode *Pred); |
114 | | void HandleBlockExit(const CFGBlock *B, ExplodedNode *Pred); |
115 | | |
116 | | void HandleCallEnter(const CallEnter &CE, ExplodedNode *Pred); |
117 | | |
118 | | void HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, ExplodedNode *Pred); |
119 | | |
120 | | void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B, |
121 | | ExplodedNode *Pred); |
122 | | void HandleCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE, |
123 | | const CFGBlock *B, ExplodedNode *Pred); |
124 | | |
125 | | /// Handle conditional logic for running static initializers. |
126 | | void HandleStaticInit(const DeclStmt *DS, const CFGBlock *B, |
127 | | ExplodedNode *Pred); |
128 | | |
129 | | void HandleVirtualBaseBranch(const CFGBlock *B, ExplodedNode *Pred); |
130 | | |
131 | | private: |
132 | | ExplodedNode *generateCallExitBeginNode(ExplodedNode *N, |
133 | | const ReturnStmt *RS); |
134 | | |
135 | | public: |
136 | | /// Construct a CoreEngine object to analyze the provided CFG. |
137 | | CoreEngine(ExprEngine &exprengine, |
138 | | FunctionSummariesTy *FS, |
139 | | AnalyzerOptions &Opts); |
140 | | |
141 | | CoreEngine(const CoreEngine &) = delete; |
142 | | CoreEngine &operator=(const CoreEngine &) = delete; |
143 | | |
144 | | /// getGraph - Returns the exploded graph. |
145 | 16.2k | ExplodedGraph &getGraph() { return G; } |
146 | | |
147 | | /// ExecuteWorkList - Run the worklist algorithm for a maximum number of |
148 | | /// steps. Returns true if there is still simulation state on the worklist. |
149 | | bool ExecuteWorkList(const LocationContext *L, unsigned Steps, |
150 | | ProgramStateRef InitState); |
151 | | |
152 | | /// Returns true if there is still simulation state on the worklist. |
153 | | bool ExecuteWorkListWithInitialState(const LocationContext *L, |
154 | | unsigned Steps, |
155 | | ProgramStateRef InitState, |
156 | | ExplodedNodeSet &Dst); |
157 | | |
158 | | /// Dispatch the work list item based on the given location information. |
159 | | /// Use Pred parameter as the predecessor state. |
160 | | void dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc, |
161 | | const WorkListUnit& WU); |
162 | | |
163 | | // Functions for external checking of whether we have unfinished work |
164 | 383 | bool wasBlockAborted() const { return !blocksAborted.empty(); } |
165 | 388 | bool wasBlocksExhausted() const { return !blocksExhausted.empty(); } |
166 | 384 | bool hasWorkRemaining() const { return wasBlocksExhausted() || |
167 | 384 | WList->hasWork()383 || |
168 | 384 | wasBlockAborted()383 ; } |
169 | | |
170 | | /// Inform the CoreEngine that a basic block was aborted because |
171 | | /// it could not be completely analyzed. |
172 | 2 | void addAbortedBlock(const ExplodedNode *node, const CFGBlock *block) { |
173 | 2 | blocksAborted.push_back(std::make_pair(block, node)); |
174 | 2 | } |
175 | | |
176 | 76.0k | WorkList *getWorkList() const { return WList.get(); } |
177 | 341 | WorkList *getCTUWorkList() const { return CTUWList.get(); } |
178 | | |
179 | 4 | auto exhausted_blocks() const { |
180 | 4 | return llvm::iterator_range(blocksExhausted); |
181 | 4 | } |
182 | | |
183 | 0 | auto aborted_blocks() const { return llvm::iterator_range(blocksAborted); } |
184 | | |
185 | | /// Enqueue the given set of nodes onto the work list. |
186 | | void enqueue(ExplodedNodeSet &Set); |
187 | | |
188 | | /// Enqueue nodes that were created as a result of processing |
189 | | /// a statement onto the work list. |
190 | | void enqueue(ExplodedNodeSet &Set, const CFGBlock *Block, unsigned Idx); |
191 | | |
192 | | /// enqueue the nodes corresponding to the end of function onto the |
193 | | /// end of path / work list. |
194 | | void enqueueEndOfFunction(ExplodedNodeSet &Set, const ReturnStmt *RS); |
195 | | |
196 | | /// Enqueue a single node created as a result of statement processing. |
197 | | void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx); |
198 | | |
199 | 7.04k | DataTag::Factory &getDataTags() { return DataTags; } |
200 | | }; |
201 | | |
202 | | // TODO: Turn into a class. |
203 | | struct NodeBuilderContext { |
204 | | const CoreEngine &Eng; |
205 | | const CFGBlock *Block; |
206 | | const LocationContext *LC; |
207 | | |
208 | | NodeBuilderContext(const CoreEngine &E, const CFGBlock *B, |
209 | | const LocationContext *L) |
210 | 1.79M | : Eng(E), Block(B), LC(L) { |
211 | 1.79M | assert(B); |
212 | 1.79M | } |
213 | | |
214 | | NodeBuilderContext(const CoreEngine &E, const CFGBlock *B, ExplodedNode *N) |
215 | 1.79M | : NodeBuilderContext(E, B, N->getLocationContext()) {} |
216 | | |
217 | | /// Return the CFGBlock associated with this builder. |
218 | 1.65M | const CFGBlock *getBlock() const { return Block; } |
219 | | |
220 | | /// Returns the number of times the current basic block has been |
221 | | /// visited on the exploded graph path. |
222 | 349k | unsigned blockCount() const { |
223 | 349k | return Eng.WList->getBlockCounter().getNumVisited( |
224 | 349k | LC->getStackFrame(), |
225 | 349k | Block->getBlockID()); |
226 | 349k | } |
227 | | }; |
228 | | |
229 | | /// \class NodeBuilder |
230 | | /// This is the simplest builder which generates nodes in the |
231 | | /// ExplodedGraph. |
232 | | /// |
233 | | /// The main benefit of the builder is that it automatically tracks the |
234 | | /// frontier nodes (or destination set). This is the set of nodes which should |
235 | | /// be propagated to the next step / builder. They are the nodes which have been |
236 | | /// added to the builder (either as the input node set or as the newly |
237 | | /// constructed nodes) but did not have any outgoing transitions added. |
238 | | class NodeBuilder { |
239 | | virtual void anchor(); |
240 | | |
241 | | protected: |
242 | | const NodeBuilderContext &C; |
243 | | |
244 | | /// Specifies if the builder results have been finalized. For example, if it |
245 | | /// is set to false, autotransitions are yet to be generated. |
246 | | bool Finalized; |
247 | | |
248 | | bool HasGeneratedNodes = false; |
249 | | |
250 | | /// The frontier set - a set of nodes which need to be propagated after |
251 | | /// the builder dies. |
252 | | ExplodedNodeSet &Frontier; |
253 | | |
254 | | /// Checks if the results are ready. |
255 | 66.5k | virtual bool checkResults() { |
256 | 66.5k | return Finalized; |
257 | 66.5k | } |
258 | | |
259 | 6.34M | bool hasNoSinksInFrontier() { |
260 | 6.34M | for (const auto I : Frontier) |
261 | 6.34M | if (I->isSink()) |
262 | 0 | return false; |
263 | 6.34M | return true; |
264 | 6.34M | } |
265 | | |
266 | | /// Allow subclasses to finalize results before result_begin() is executed. |
267 | 66.5k | virtual void finalizeResults() {} |
268 | | |
269 | | ExplodedNode *generateNodeImpl(const ProgramPoint &PP, |
270 | | ProgramStateRef State, |
271 | | ExplodedNode *Pred, |
272 | | bool MarkAsSink = false); |
273 | | |
274 | | public: |
275 | | NodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, |
276 | | const NodeBuilderContext &Ctx, bool F = true) |
277 | 2.86M | : C(Ctx), Finalized(F), Frontier(DstSet) { |
278 | 2.86M | Frontier.Add(SrcNode); |
279 | 2.86M | } |
280 | | |
281 | | NodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, |
282 | | const NodeBuilderContext &Ctx, bool F = true) |
283 | 6.34M | : C(Ctx), Finalized(F), Frontier(DstSet) { |
284 | 6.34M | Frontier.insert(SrcSet); |
285 | 6.34M | assert(hasNoSinksInFrontier()); |
286 | 6.34M | } |
287 | | |
288 | 9.20M | virtual ~NodeBuilder() = default; |
289 | | |
290 | | /// Generates a node in the ExplodedGraph. |
291 | | ExplodedNode *generateNode(const ProgramPoint &PP, |
292 | | ProgramStateRef State, |
293 | 2.02M | ExplodedNode *Pred) { |
294 | 2.02M | return generateNodeImpl( |
295 | 2.02M | PP, State, Pred, |
296 | 2.02M | /*MarkAsSink=*/State->isPosteriorlyOverconstrained()); |
297 | 2.02M | } |
298 | | |
299 | | /// Generates a sink in the ExplodedGraph. |
300 | | /// |
301 | | /// When a node is marked as sink, the exploration from the node is stopped - |
302 | | /// the node becomes the last node on the path and certain kinds of bugs are |
303 | | /// suppressed. |
304 | | ExplodedNode *generateSink(const ProgramPoint &PP, |
305 | | ProgramStateRef State, |
306 | 10.6k | ExplodedNode *Pred) { |
307 | 10.6k | return generateNodeImpl(PP, State, Pred, true); |
308 | 10.6k | } |
309 | | |
310 | 44.6k | const ExplodedNodeSet &getResults() { |
311 | 44.6k | finalizeResults(); |
312 | 44.6k | assert(checkResults()); |
313 | 44.6k | return Frontier; |
314 | 44.6k | } |
315 | | |
316 | | using iterator = ExplodedNodeSet::iterator; |
317 | | |
318 | | /// Iterators through the results frontier. |
319 | 21.9k | iterator begin() { |
320 | 21.9k | finalizeResults(); |
321 | 21.9k | assert(checkResults()); |
322 | 21.9k | return Frontier.begin(); |
323 | 21.9k | } |
324 | | |
325 | 0 | iterator end() { |
326 | 0 | finalizeResults(); |
327 | 0 | return Frontier.end(); |
328 | 0 | } |
329 | | |
330 | 178k | const NodeBuilderContext &getContext() { return C; } |
331 | 169k | bool hasGeneratedNodes() { return HasGeneratedNodes; } |
332 | | |
333 | 60.5k | void takeNodes(const ExplodedNodeSet &S) { |
334 | 60.5k | for (const auto I : S) |
335 | 60.5k | Frontier.erase(I); |
336 | 60.5k | } |
337 | | |
338 | 1.72M | void takeNodes(ExplodedNode *N) { Frontier.erase(N); } |
339 | 1.67M | void addNodes(const ExplodedNodeSet &S) { Frontier.insert(S); } |
340 | 0 | void addNodes(ExplodedNode *N) { Frontier.Add(N); } |
341 | | }; |
342 | | |
343 | | /// \class NodeBuilderWithSinks |
344 | | /// This node builder keeps track of the generated sink nodes. |
345 | | class NodeBuilderWithSinks: public NodeBuilder { |
346 | | void anchor() override; |
347 | | |
348 | | protected: |
349 | | SmallVector<ExplodedNode*, 2> sinksGenerated; |
350 | | ProgramPoint &Location; |
351 | | |
352 | | public: |
353 | | NodeBuilderWithSinks(ExplodedNode *Pred, ExplodedNodeSet &DstSet, |
354 | | const NodeBuilderContext &Ctx, ProgramPoint &L) |
355 | 169k | : NodeBuilder(Pred, DstSet, Ctx), Location(L) {} |
356 | | |
357 | | ExplodedNode *generateNode(ProgramStateRef State, |
358 | | ExplodedNode *Pred, |
359 | 167k | const ProgramPointTag *Tag = nullptr) { |
360 | 167k | const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag)0 : Location); |
361 | 167k | return NodeBuilder::generateNode(LocalLoc, State, Pred); |
362 | 167k | } |
363 | | |
364 | | ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred, |
365 | 2.05k | const ProgramPointTag *Tag = nullptr) { |
366 | 2.05k | const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location0 ); |
367 | 2.05k | ExplodedNode *N = NodeBuilder::generateSink(LocalLoc, State, Pred); |
368 | 2.05k | if (N && N->isSink()) |
369 | 2.05k | sinksGenerated.push_back(N); |
370 | 2.05k | return N; |
371 | 2.05k | } |
372 | | |
373 | 0 | const SmallVectorImpl<ExplodedNode*> &getSinks() const { |
374 | 0 | return sinksGenerated; |
375 | 0 | } |
376 | | }; |
377 | | |
378 | | /// \class StmtNodeBuilder |
379 | | /// This builder class is useful for generating nodes that resulted from |
380 | | /// visiting a statement. The main difference from its parent NodeBuilder is |
381 | | /// that it creates a statement specific ProgramPoint. |
382 | | class StmtNodeBuilder: public NodeBuilder { |
383 | | NodeBuilder *EnclosingBldr; |
384 | | |
385 | | public: |
386 | | /// Constructs a StmtNodeBuilder. If the builder is going to process |
387 | | /// nodes currently owned by another builder(with larger scope), use |
388 | | /// Enclosing builder to transfer ownership. |
389 | | StmtNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, |
390 | | const NodeBuilderContext &Ctx, |
391 | | NodeBuilder *Enclosing = nullptr) |
392 | 2.39M | : NodeBuilder(SrcNode, DstSet, Ctx), EnclosingBldr(Enclosing) { |
393 | 2.39M | if (EnclosingBldr) |
394 | 0 | EnclosingBldr->takeNodes(SrcNode); |
395 | 2.39M | } |
396 | | |
397 | | StmtNodeBuilder(ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, |
398 | | const NodeBuilderContext &Ctx, |
399 | | NodeBuilder *Enclosing = nullptr) |
400 | 1.25M | : NodeBuilder(SrcSet, DstSet, Ctx), EnclosingBldr(Enclosing) { |
401 | 1.25M | if (EnclosingBldr) |
402 | 0 | for (const auto I : SrcSet) |
403 | 0 | EnclosingBldr->takeNodes(I); |
404 | 1.25M | } |
405 | | |
406 | | ~StmtNodeBuilder() override; |
407 | | |
408 | | using NodeBuilder::generateNode; |
409 | | using NodeBuilder::generateSink; |
410 | | |
411 | | ExplodedNode *generateNode(const Stmt *S, |
412 | | ExplodedNode *Pred, |
413 | | ProgramStateRef St, |
414 | | const ProgramPointTag *tag = nullptr, |
415 | 1.60M | ProgramPoint::Kind K = ProgramPoint::PostStmtKind){ |
416 | 1.60M | const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, |
417 | 1.60M | Pred->getLocationContext(), tag); |
418 | 1.60M | return NodeBuilder::generateNode(L, St, Pred); |
419 | 1.60M | } |
420 | | |
421 | | ExplodedNode *generateSink(const Stmt *S, |
422 | | ExplodedNode *Pred, |
423 | | ProgramStateRef St, |
424 | | const ProgramPointTag *tag = nullptr, |
425 | 24 | ProgramPoint::Kind K = ProgramPoint::PostStmtKind){ |
426 | 24 | const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, |
427 | 24 | Pred->getLocationContext(), tag); |
428 | 24 | return NodeBuilder::generateSink(L, St, Pred); |
429 | 24 | } |
430 | | }; |
431 | | |
432 | | /// BranchNodeBuilder is responsible for constructing the nodes |
433 | | /// corresponding to the two branches of the if statement - true and false. |
434 | | class BranchNodeBuilder: public NodeBuilder { |
435 | | const CFGBlock *DstT; |
436 | | const CFGBlock *DstF; |
437 | | |
438 | | bool InFeasibleTrue; |
439 | | bool InFeasibleFalse; |
440 | | |
441 | | void anchor() override; |
442 | | |
443 | | public: |
444 | | BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, |
445 | | const NodeBuilderContext &C, |
446 | | const CFGBlock *dstT, const CFGBlock *dstF) |
447 | 1.00k | : NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF), |
448 | 1.00k | InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) { |
449 | | // The branch node builder does not generate autotransitions. |
450 | | // If there are no successors it means that both branches are infeasible. |
451 | 1.00k | takeNodes(SrcNode); |
452 | 1.00k | } |
453 | | |
454 | | BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, |
455 | | const NodeBuilderContext &C, |
456 | | const CFGBlock *dstT, const CFGBlock *dstF) |
457 | 60.5k | : NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF), |
458 | 60.5k | InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) { |
459 | 60.5k | takeNodes(SrcSet); |
460 | 60.5k | } |
461 | | |
462 | | ExplodedNode *generateNode(ProgramStateRef State, bool branch, |
463 | | ExplodedNode *Pred); |
464 | | |
465 | 0 | const CFGBlock *getTargetBlock(bool branch) const { |
466 | 0 | return branch ? DstT : DstF; |
467 | 0 | } |
468 | | |
469 | 30.8k | void markInfeasible(bool branch) { |
470 | 30.8k | if (branch) |
471 | 15.1k | InFeasibleTrue = true; |
472 | 15.7k | else |
473 | 15.7k | InFeasibleFalse = true; |
474 | 30.8k | } |
475 | | |
476 | 211k | bool isFeasible(bool branch) { |
477 | 211k | return branch ? !InFeasibleTrue106k : !InFeasibleFalse104k ; |
478 | 211k | } |
479 | | }; |
480 | | |
481 | | class IndirectGotoNodeBuilder { |
482 | | CoreEngine& Eng; |
483 | | const CFGBlock *Src; |
484 | | const CFGBlock &DispatchBlock; |
485 | | const Expr *E; |
486 | | ExplodedNode *Pred; |
487 | | |
488 | | public: |
489 | | IndirectGotoNodeBuilder(ExplodedNode *pred, const CFGBlock *src, |
490 | | const Expr *e, const CFGBlock *dispatch, CoreEngine* eng) |
491 | 8 | : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {} |
492 | | |
493 | | class iterator { |
494 | | friend class IndirectGotoNodeBuilder; |
495 | | |
496 | | CFGBlock::const_succ_iterator I; |
497 | | |
498 | 16 | iterator(CFGBlock::const_succ_iterator i) : I(i) {} |
499 | | |
500 | | public: |
501 | | // This isn't really a conventional iterator. |
502 | | // We just implement the deref as a no-op for now to make range-based for |
503 | | // loops work. |
504 | 8 | const iterator &operator*() const { return *this; } |
505 | | |
506 | 8 | iterator &operator++() { ++I; return *this; } |
507 | 16 | bool operator!=(const iterator &X) const { return I != X.I; } |
508 | | |
509 | 0 | const LabelDecl *getLabel() const { |
510 | 0 | return cast<LabelStmt>((*I)->getLabel())->getDecl(); |
511 | 0 | } |
512 | | |
513 | 8 | const CFGBlock *getBlock() const { |
514 | 8 | return *I; |
515 | 8 | } |
516 | | }; |
517 | | |
518 | 8 | iterator begin() { return iterator(DispatchBlock.succ_begin()); } |
519 | 8 | iterator end() { return iterator(DispatchBlock.succ_end()); } |
520 | | |
521 | | ExplodedNode *generateNode(const iterator &I, |
522 | | ProgramStateRef State, |
523 | | bool isSink = false); |
524 | | |
525 | 8 | const Expr *getTarget() const { return E; } |
526 | | |
527 | 8 | ProgramStateRef getState() const { return Pred->State; } |
528 | | |
529 | 8 | const LocationContext *getLocationContext() const { |
530 | 8 | return Pred->getLocationContext(); |
531 | 8 | } |
532 | | }; |
533 | | |
534 | | class SwitchNodeBuilder { |
535 | | CoreEngine& Eng; |
536 | | const CFGBlock *Src; |
537 | | const Expr *Condition; |
538 | | ExplodedNode *Pred; |
539 | | |
540 | | public: |
541 | | SwitchNodeBuilder(ExplodedNode *pred, const CFGBlock *src, |
542 | | const Expr *condition, CoreEngine* eng) |
543 | 356 | : Eng(*eng), Src(src), Condition(condition), Pred(pred) {} |
544 | | |
545 | | class iterator { |
546 | | friend class SwitchNodeBuilder; |
547 | | |
548 | | CFGBlock::const_succ_reverse_iterator I; |
549 | | |
550 | 712 | iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {} |
551 | | |
552 | | public: |
553 | 849 | iterator &operator++() { ++I; return *this; } |
554 | 1.20k | bool operator!=(const iterator &X) const { return I != X.I; } |
555 | 356 | bool operator==(const iterator &X) const { return I == X.I; } |
556 | | |
557 | 973 | const CaseStmt *getCase() const { |
558 | 973 | return cast<CaseStmt>((*I)->getLabel()); |
559 | 973 | } |
560 | | |
561 | 1.74k | const CFGBlock *getBlock() const { |
562 | 1.74k | return *I; |
563 | 1.74k | } |
564 | | }; |
565 | | |
566 | 356 | iterator begin() { return iterator(Src->succ_rbegin()+1); } |
567 | 356 | iterator end() { return iterator(Src->succ_rend()); } |
568 | | |
569 | 230 | const SwitchStmt *getSwitch() const { |
570 | 230 | return cast<SwitchStmt>(Src->getTerminator()); |
571 | 230 | } |
572 | | |
573 | | ExplodedNode *generateCaseStmtNode(const iterator &I, |
574 | | ProgramStateRef State); |
575 | | |
576 | | ExplodedNode *generateDefaultCaseNode(ProgramStateRef State, |
577 | | bool isSink = false); |
578 | | |
579 | 356 | const Expr *getCondition() const { return Condition; } |
580 | | |
581 | 356 | ProgramStateRef getState() const { return Pred->State; } |
582 | | |
583 | 356 | const LocationContext *getLocationContext() const { |
584 | 356 | return Pred->getLocationContext(); |
585 | 356 | } |
586 | | }; |
587 | | |
588 | | } // namespace ento |
589 | | |
590 | | } // namespace clang |
591 | | |
592 | | #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H |