Coverage Report

Created: 2023-11-11 10:31

/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