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