File indexing completed on 2026-05-10 08:36:26
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef LLVM_CLANG_ANALYSIS_CFG_H
0015 #define LLVM_CLANG_ANALYSIS_CFG_H
0016
0017 #include "clang/AST/Attr.h"
0018 #include "clang/AST/ExprCXX.h"
0019 #include "clang/AST/ExprObjC.h"
0020 #include "clang/Analysis/ConstructionContext.h"
0021 #include "clang/Analysis/Support/BumpVector.h"
0022 #include "clang/Basic/LLVM.h"
0023 #include "llvm/ADT/DenseMap.h"
0024 #include "llvm/ADT/GraphTraits.h"
0025 #include "llvm/ADT/PointerIntPair.h"
0026 #include "llvm/ADT/iterator_range.h"
0027 #include "llvm/Support/Allocator.h"
0028 #include "llvm/Support/raw_ostream.h"
0029 #include <bitset>
0030 #include <cassert>
0031 #include <cstddef>
0032 #include <iterator>
0033 #include <memory>
0034 #include <optional>
0035 #include <vector>
0036
0037 namespace clang {
0038
0039 class ASTContext;
0040 class BinaryOperator;
0041 class CFG;
0042 class CXXBaseSpecifier;
0043 class CXXBindTemporaryExpr;
0044 class CXXCtorInitializer;
0045 class CXXDeleteExpr;
0046 class CXXDestructorDecl;
0047 class CXXNewExpr;
0048 class CXXRecordDecl;
0049 class Decl;
0050 class FieldDecl;
0051 class LangOptions;
0052 class VarDecl;
0053
0054
0055 class CFGElement {
0056 public:
0057 enum Kind {
0058
0059 Initializer,
0060 ScopeBegin,
0061 ScopeEnd,
0062 NewAllocator,
0063 LifetimeEnds,
0064 LoopExit,
0065
0066 Statement,
0067 Constructor,
0068 CXXRecordTypedCall,
0069 STMT_BEGIN = Statement,
0070 STMT_END = CXXRecordTypedCall,
0071
0072 AutomaticObjectDtor,
0073 DeleteDtor,
0074 BaseDtor,
0075 MemberDtor,
0076 TemporaryDtor,
0077 DTOR_BEGIN = AutomaticObjectDtor,
0078 DTOR_END = TemporaryDtor,
0079 CleanupFunction,
0080 };
0081
0082 protected:
0083
0084 llvm::PointerIntPair<void *, 2> Data1;
0085 llvm::PointerIntPair<void *, 2> Data2;
0086
0087 CFGElement(Kind kind, const void *Ptr1, const void *Ptr2 = nullptr)
0088 : Data1(const_cast<void*>(Ptr1), ((unsigned) kind) & 0x3),
0089 Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) {
0090 assert(getKind() == kind);
0091 }
0092
0093 CFGElement() = default;
0094
0095 public:
0096
0097
0098 template<typename T>
0099 T castAs() const {
0100 assert(T::isKind(*this));
0101 T t;
0102 CFGElement& e = t;
0103 e = *this;
0104 return t;
0105 }
0106
0107
0108
0109 template <typename T> std::optional<T> getAs() const {
0110 if (!T::isKind(*this))
0111 return std::nullopt;
0112 T t;
0113 CFGElement& e = t;
0114 e = *this;
0115 return t;
0116 }
0117
0118 Kind getKind() const {
0119 unsigned x = Data2.getInt();
0120 x <<= 2;
0121 x |= Data1.getInt();
0122 return (Kind) x;
0123 }
0124
0125 void dumpToStream(llvm::raw_ostream &OS) const;
0126
0127 void dump() const {
0128 dumpToStream(llvm::errs());
0129 }
0130 };
0131
0132 class CFGStmt : public CFGElement {
0133 public:
0134 explicit CFGStmt(const Stmt *S, Kind K = Statement) : CFGElement(K, S) {
0135 assert(isKind(*this));
0136 }
0137
0138 const Stmt *getStmt() const {
0139 return static_cast<const Stmt *>(Data1.getPointer());
0140 }
0141
0142 private:
0143 friend class CFGElement;
0144
0145 static bool isKind(const CFGElement &E) {
0146 return E.getKind() >= STMT_BEGIN && E.getKind() <= STMT_END;
0147 }
0148
0149 protected:
0150 CFGStmt() = default;
0151 };
0152
0153
0154
0155
0156 class CFGConstructor : public CFGStmt {
0157 public:
0158 explicit CFGConstructor(const CXXConstructExpr *CE,
0159 const ConstructionContext *C)
0160 : CFGStmt(CE, Constructor) {
0161 assert(C);
0162 Data2.setPointer(const_cast<ConstructionContext *>(C));
0163 }
0164
0165 const ConstructionContext *getConstructionContext() const {
0166 return static_cast<ConstructionContext *>(Data2.getPointer());
0167 }
0168
0169 private:
0170 friend class CFGElement;
0171
0172 CFGConstructor() = default;
0173
0174 static bool isKind(const CFGElement &E) {
0175 return E.getKind() == Constructor;
0176 }
0177 };
0178
0179
0180
0181
0182
0183
0184
0185 class CFGCXXRecordTypedCall : public CFGStmt {
0186 public:
0187
0188
0189 static bool isCXXRecordTypedCall(const Expr *E) {
0190 assert(isa<CallExpr>(E) || isa<ObjCMessageExpr>(E));
0191
0192
0193
0194 return !E->isGLValue() &&
0195 E->getType().getCanonicalType()->getAsCXXRecordDecl();
0196 }
0197
0198 explicit CFGCXXRecordTypedCall(const Expr *E, const ConstructionContext *C)
0199 : CFGStmt(E, CXXRecordTypedCall) {
0200 assert(isCXXRecordTypedCall(E));
0201 assert(C && (isa<TemporaryObjectConstructionContext>(C) ||
0202
0203 isa<ReturnedValueConstructionContext>(C) ||
0204 isa<VariableConstructionContext>(C) ||
0205 isa<ConstructorInitializerConstructionContext>(C) ||
0206 isa<ArgumentConstructionContext>(C) ||
0207 isa<LambdaCaptureConstructionContext>(C)));
0208 Data2.setPointer(const_cast<ConstructionContext *>(C));
0209 }
0210
0211 const ConstructionContext *getConstructionContext() const {
0212 return static_cast<ConstructionContext *>(Data2.getPointer());
0213 }
0214
0215 private:
0216 friend class CFGElement;
0217
0218 CFGCXXRecordTypedCall() = default;
0219
0220 static bool isKind(const CFGElement &E) {
0221 return E.getKind() == CXXRecordTypedCall;
0222 }
0223 };
0224
0225
0226
0227 class CFGInitializer : public CFGElement {
0228 public:
0229 explicit CFGInitializer(const CXXCtorInitializer *initializer)
0230 : CFGElement(Initializer, initializer) {}
0231
0232 CXXCtorInitializer* getInitializer() const {
0233 return static_cast<CXXCtorInitializer*>(Data1.getPointer());
0234 }
0235
0236 private:
0237 friend class CFGElement;
0238
0239 CFGInitializer() = default;
0240
0241 static bool isKind(const CFGElement &E) {
0242 return E.getKind() == Initializer;
0243 }
0244 };
0245
0246
0247 class CFGNewAllocator : public CFGElement {
0248 public:
0249 explicit CFGNewAllocator(const CXXNewExpr *S)
0250 : CFGElement(NewAllocator, S) {}
0251
0252
0253 const CXXNewExpr *getAllocatorExpr() const {
0254 return static_cast<CXXNewExpr *>(Data1.getPointer());
0255 }
0256
0257 private:
0258 friend class CFGElement;
0259
0260 CFGNewAllocator() = default;
0261
0262 static bool isKind(const CFGElement &elem) {
0263 return elem.getKind() == NewAllocator;
0264 }
0265 };
0266
0267
0268
0269
0270
0271
0272
0273 class CFGLoopExit : public CFGElement {
0274 public:
0275 explicit CFGLoopExit(const Stmt *stmt) : CFGElement(LoopExit, stmt) {}
0276
0277 const Stmt *getLoopStmt() const {
0278 return static_cast<Stmt *>(Data1.getPointer());
0279 }
0280
0281 private:
0282 friend class CFGElement;
0283
0284 CFGLoopExit() = default;
0285
0286 static bool isKind(const CFGElement &elem) {
0287 return elem.getKind() == LoopExit;
0288 }
0289 };
0290
0291
0292 class CFGLifetimeEnds : public CFGElement {
0293 public:
0294 explicit CFGLifetimeEnds(const VarDecl *var, const Stmt *stmt)
0295 : CFGElement(LifetimeEnds, var, stmt) {}
0296
0297 const VarDecl *getVarDecl() const {
0298 return static_cast<VarDecl *>(Data1.getPointer());
0299 }
0300
0301 const Stmt *getTriggerStmt() const {
0302 return static_cast<Stmt *>(Data2.getPointer());
0303 }
0304
0305 private:
0306 friend class CFGElement;
0307
0308 CFGLifetimeEnds() = default;
0309
0310 static bool isKind(const CFGElement &elem) {
0311 return elem.getKind() == LifetimeEnds;
0312 }
0313 };
0314
0315
0316
0317 class CFGScopeBegin : public CFGElement {
0318 public:
0319 CFGScopeBegin() {}
0320 CFGScopeBegin(const VarDecl *VD, const Stmt *S)
0321 : CFGElement(ScopeBegin, VD, S) {}
0322
0323
0324 const Stmt *getTriggerStmt() const {
0325 return static_cast<Stmt*>(Data2.getPointer());
0326 }
0327
0328
0329 const VarDecl *getVarDecl() const {
0330 return static_cast<VarDecl *>(Data1.getPointer());
0331 }
0332
0333 private:
0334 friend class CFGElement;
0335 static bool isKind(const CFGElement &E) {
0336 Kind kind = E.getKind();
0337 return kind == ScopeBegin;
0338 }
0339 };
0340
0341
0342
0343 class CFGScopeEnd : public CFGElement {
0344 public:
0345 CFGScopeEnd() {}
0346 CFGScopeEnd(const VarDecl *VD, const Stmt *S) : CFGElement(ScopeEnd, VD, S) {}
0347
0348 const VarDecl *getVarDecl() const {
0349 return static_cast<VarDecl *>(Data1.getPointer());
0350 }
0351
0352 const Stmt *getTriggerStmt() const {
0353 return static_cast<Stmt *>(Data2.getPointer());
0354 }
0355
0356 private:
0357 friend class CFGElement;
0358 static bool isKind(const CFGElement &E) {
0359 Kind kind = E.getKind();
0360 return kind == ScopeEnd;
0361 }
0362 };
0363
0364
0365
0366 class CFGImplicitDtor : public CFGElement {
0367 protected:
0368 CFGImplicitDtor() = default;
0369
0370 CFGImplicitDtor(Kind kind, const void *data1, const void *data2 = nullptr)
0371 : CFGElement(kind, data1, data2) {
0372 assert(kind >= DTOR_BEGIN && kind <= DTOR_END);
0373 }
0374
0375 public:
0376 const CXXDestructorDecl *getDestructorDecl(ASTContext &astContext) const;
0377 bool isNoReturn(ASTContext &astContext) const;
0378
0379 private:
0380 friend class CFGElement;
0381
0382 static bool isKind(const CFGElement &E) {
0383 Kind kind = E.getKind();
0384 return kind >= DTOR_BEGIN && kind <= DTOR_END;
0385 }
0386 };
0387
0388 class CFGCleanupFunction final : public CFGElement {
0389 public:
0390 CFGCleanupFunction() = default;
0391 CFGCleanupFunction(const VarDecl *VD)
0392 : CFGElement(Kind::CleanupFunction, VD) {
0393 assert(VD->hasAttr<CleanupAttr>());
0394 }
0395
0396 const VarDecl *getVarDecl() const {
0397 return static_cast<VarDecl *>(Data1.getPointer());
0398 }
0399
0400
0401 const FunctionDecl *getFunctionDecl() const {
0402 const CleanupAttr *A = getVarDecl()->getAttr<CleanupAttr>();
0403 return A->getFunctionDecl();
0404 }
0405
0406 private:
0407 friend class CFGElement;
0408
0409 static bool isKind(const CFGElement E) {
0410 return E.getKind() == Kind::CleanupFunction;
0411 }
0412 };
0413
0414
0415
0416
0417 class CFGAutomaticObjDtor: public CFGImplicitDtor {
0418 public:
0419 CFGAutomaticObjDtor(const VarDecl *var, const Stmt *stmt)
0420 : CFGImplicitDtor(AutomaticObjectDtor, var, stmt) {}
0421
0422 const VarDecl *getVarDecl() const {
0423 return static_cast<VarDecl*>(Data1.getPointer());
0424 }
0425
0426
0427 const Stmt *getTriggerStmt() const {
0428 return static_cast<Stmt*>(Data2.getPointer());
0429 }
0430
0431 private:
0432 friend class CFGElement;
0433
0434 CFGAutomaticObjDtor() = default;
0435
0436 static bool isKind(const CFGElement &elem) {
0437 return elem.getKind() == AutomaticObjectDtor;
0438 }
0439 };
0440
0441
0442 class CFGDeleteDtor : public CFGImplicitDtor {
0443 public:
0444 CFGDeleteDtor(const CXXRecordDecl *RD, const CXXDeleteExpr *DE)
0445 : CFGImplicitDtor(DeleteDtor, RD, DE) {}
0446
0447 const CXXRecordDecl *getCXXRecordDecl() const {
0448 return static_cast<CXXRecordDecl*>(Data1.getPointer());
0449 }
0450
0451
0452 const CXXDeleteExpr *getDeleteExpr() const {
0453 return static_cast<CXXDeleteExpr *>(Data2.getPointer());
0454 }
0455
0456 private:
0457 friend class CFGElement;
0458
0459 CFGDeleteDtor() = default;
0460
0461 static bool isKind(const CFGElement &elem) {
0462 return elem.getKind() == DeleteDtor;
0463 }
0464 };
0465
0466
0467
0468 class CFGBaseDtor : public CFGImplicitDtor {
0469 public:
0470 CFGBaseDtor(const CXXBaseSpecifier *base)
0471 : CFGImplicitDtor(BaseDtor, base) {}
0472
0473 const CXXBaseSpecifier *getBaseSpecifier() const {
0474 return static_cast<const CXXBaseSpecifier*>(Data1.getPointer());
0475 }
0476
0477 private:
0478 friend class CFGElement;
0479
0480 CFGBaseDtor() = default;
0481
0482 static bool isKind(const CFGElement &E) {
0483 return E.getKind() == BaseDtor;
0484 }
0485 };
0486
0487
0488
0489 class CFGMemberDtor : public CFGImplicitDtor {
0490 public:
0491 CFGMemberDtor(const FieldDecl *field)
0492 : CFGImplicitDtor(MemberDtor, field, nullptr) {}
0493
0494 const FieldDecl *getFieldDecl() const {
0495 return static_cast<const FieldDecl*>(Data1.getPointer());
0496 }
0497
0498 private:
0499 friend class CFGElement;
0500
0501 CFGMemberDtor() = default;
0502
0503 static bool isKind(const CFGElement &E) {
0504 return E.getKind() == MemberDtor;
0505 }
0506 };
0507
0508
0509
0510 class CFGTemporaryDtor : public CFGImplicitDtor {
0511 public:
0512 CFGTemporaryDtor(const CXXBindTemporaryExpr *expr)
0513 : CFGImplicitDtor(TemporaryDtor, expr, nullptr) {}
0514
0515 const CXXBindTemporaryExpr *getBindTemporaryExpr() const {
0516 return static_cast<const CXXBindTemporaryExpr *>(Data1.getPointer());
0517 }
0518
0519 private:
0520 friend class CFGElement;
0521
0522 CFGTemporaryDtor() = default;
0523
0524 static bool isKind(const CFGElement &E) {
0525 return E.getKind() == TemporaryDtor;
0526 }
0527 };
0528
0529
0530
0531 class CFGTerminator {
0532 public:
0533 enum Kind {
0534
0535
0536 StmtBranch,
0537
0538
0539
0540 TemporaryDtorsBranch,
0541
0542
0543
0544 VirtualBaseBranch,
0545
0546
0547
0548
0549 NumKindsMinusOne = VirtualBaseBranch
0550 };
0551
0552 private:
0553 static constexpr int KindBits = 2;
0554 static_assert((1 << KindBits) > NumKindsMinusOne,
0555 "Not enough room for kind!");
0556 llvm::PointerIntPair<Stmt *, KindBits> Data;
0557
0558 public:
0559 CFGTerminator() { assert(!isValid()); }
0560 CFGTerminator(Stmt *S, Kind K = StmtBranch) : Data(S, K) {}
0561
0562 bool isValid() const { return Data.getOpaqueValue() != nullptr; }
0563 Stmt *getStmt() { return Data.getPointer(); }
0564 const Stmt *getStmt() const { return Data.getPointer(); }
0565 Kind getKind() const { return static_cast<Kind>(Data.getInt()); }
0566
0567 bool isStmtBranch() const {
0568 return getKind() == StmtBranch;
0569 }
0570 bool isTemporaryDtorsBranch() const {
0571 return getKind() == TemporaryDtorsBranch;
0572 }
0573 bool isVirtualBaseBranch() const {
0574 return getKind() == VirtualBaseBranch;
0575 }
0576 };
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596
0597
0598
0599
0600
0601
0602
0603
0604 class CFGBlock {
0605 class ElementList {
0606 using ImplTy = BumpVector<CFGElement>;
0607
0608 ImplTy Impl;
0609
0610 public:
0611 ElementList(BumpVectorContext &C) : Impl(C, 4) {}
0612
0613 using iterator = std::reverse_iterator<ImplTy::iterator>;
0614 using const_iterator = std::reverse_iterator<ImplTy::const_iterator>;
0615 using reverse_iterator = ImplTy::iterator;
0616 using const_reverse_iterator = ImplTy::const_iterator;
0617 using const_reference = ImplTy::const_reference;
0618
0619 void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); }
0620
0621 reverse_iterator insert(reverse_iterator I, size_t Cnt, CFGElement E,
0622 BumpVectorContext &C) {
0623 return Impl.insert(I, Cnt, E, C);
0624 }
0625
0626 const_reference front() const { return Impl.back(); }
0627 const_reference back() const { return Impl.front(); }
0628
0629 iterator begin() { return Impl.rbegin(); }
0630 iterator end() { return Impl.rend(); }
0631 const_iterator begin() const { return Impl.rbegin(); }
0632 const_iterator end() const { return Impl.rend(); }
0633 reverse_iterator rbegin() { return Impl.begin(); }
0634 reverse_iterator rend() { return Impl.end(); }
0635 const_reverse_iterator rbegin() const { return Impl.begin(); }
0636 const_reverse_iterator rend() const { return Impl.end(); }
0637
0638 CFGElement operator[](size_t i) const {
0639 assert(i < Impl.size());
0640 return Impl[Impl.size() - 1 - i];
0641 }
0642
0643 size_t size() const { return Impl.size(); }
0644 bool empty() const { return Impl.empty(); }
0645 };
0646
0647
0648
0649
0650 template <bool IsConst> class ElementRefImpl {
0651
0652 template <bool IsOtherConst> friend class ElementRefImpl;
0653
0654 using CFGBlockPtr =
0655 std::conditional_t<IsConst, const CFGBlock *, CFGBlock *>;
0656
0657 using CFGElementPtr =
0658 std::conditional_t<IsConst, const CFGElement *, CFGElement *>;
0659
0660 protected:
0661 CFGBlockPtr Parent;
0662 size_t Index;
0663
0664 public:
0665 ElementRefImpl(CFGBlockPtr Parent, size_t Index)
0666 : Parent(Parent), Index(Index) {}
0667
0668 template <bool IsOtherConst>
0669 ElementRefImpl(ElementRefImpl<IsOtherConst> Other)
0670 : ElementRefImpl(Other.Parent, Other.Index) {}
0671
0672 size_t getIndexInBlock() const { return Index; }
0673
0674 CFGBlockPtr getParent() { return Parent; }
0675 CFGBlockPtr getParent() const { return Parent; }
0676
0677 bool operator<(ElementRefImpl Other) const {
0678 return std::make_pair(Parent, Index) <
0679 std::make_pair(Other.Parent, Other.Index);
0680 }
0681
0682 bool operator==(ElementRefImpl Other) const {
0683 return Parent == Other.Parent && Index == Other.Index;
0684 }
0685
0686 bool operator!=(ElementRefImpl Other) const { return !(*this == Other); }
0687 CFGElement operator*() const { return (*Parent)[Index]; }
0688 CFGElementPtr operator->() const { return &*(Parent->begin() + Index); }
0689
0690 void dumpToStream(llvm::raw_ostream &OS) const {
0691 OS << getIndexInBlock() + 1 << ": ";
0692 (*this)->dumpToStream(OS);
0693 }
0694
0695 void dump() const {
0696 dumpToStream(llvm::errs());
0697 }
0698 };
0699
0700 template <bool IsReverse, bool IsConst> class ElementRefIterator {
0701
0702 template <bool IsOtherReverse, bool IsOtherConst>
0703 friend class ElementRefIterator;
0704
0705 using CFGBlockRef =
0706 std::conditional_t<IsConst, const CFGBlock *, CFGBlock *>;
0707
0708 using UnderlayingIteratorTy = std::conditional_t<
0709 IsConst,
0710 std::conditional_t<IsReverse, ElementList::const_reverse_iterator,
0711 ElementList::const_iterator>,
0712 std::conditional_t<IsReverse, ElementList::reverse_iterator,
0713 ElementList::iterator>>;
0714
0715 using IteratorTraits = typename std::iterator_traits<UnderlayingIteratorTy>;
0716 using ElementRef = typename CFGBlock::ElementRefImpl<IsConst>;
0717
0718 public:
0719 using difference_type = typename IteratorTraits::difference_type;
0720 using value_type = ElementRef;
0721 using pointer = ElementRef *;
0722 using iterator_category = typename IteratorTraits::iterator_category;
0723
0724 private:
0725 CFGBlockRef Parent;
0726 UnderlayingIteratorTy Pos;
0727
0728 public:
0729 ElementRefIterator(CFGBlockRef Parent, UnderlayingIteratorTy Pos)
0730 : Parent(Parent), Pos(Pos) {}
0731
0732 template <bool IsOtherConst>
0733 ElementRefIterator(ElementRefIterator<false, IsOtherConst> E)
0734 : ElementRefIterator(E.Parent, E.Pos.base()) {}
0735
0736 template <bool IsOtherConst>
0737 ElementRefIterator(ElementRefIterator<true, IsOtherConst> E)
0738 : ElementRefIterator(E.Parent, std::make_reverse_iterator(E.Pos)) {}
0739
0740 bool operator<(ElementRefIterator Other) const {
0741 assert(Parent == Other.Parent);
0742 return Pos < Other.Pos;
0743 }
0744
0745 bool operator==(ElementRefIterator Other) const {
0746 return Parent == Other.Parent && Pos == Other.Pos;
0747 }
0748
0749 bool operator!=(ElementRefIterator Other) const {
0750 return !(*this == Other);
0751 }
0752
0753 private:
0754 template <bool IsOtherConst>
0755 static size_t
0756 getIndexInBlock(CFGBlock::ElementRefIterator<true, IsOtherConst> E) {
0757 return E.Parent->size() - (E.Pos - E.Parent->rbegin()) - 1;
0758 }
0759
0760 template <bool IsOtherConst>
0761 static size_t
0762 getIndexInBlock(CFGBlock::ElementRefIterator<false, IsOtherConst> E) {
0763 return E.Pos - E.Parent->begin();
0764 }
0765
0766 public:
0767 value_type operator*() { return {Parent, getIndexInBlock(*this)}; }
0768
0769 difference_type operator-(ElementRefIterator Other) const {
0770 return Pos - Other.Pos;
0771 }
0772
0773 ElementRefIterator operator++() {
0774 ++this->Pos;
0775 return *this;
0776 }
0777 ElementRefIterator operator++(int) {
0778 ElementRefIterator Ret = *this;
0779 ++*this;
0780 return Ret;
0781 }
0782 ElementRefIterator operator+(size_t count) {
0783 this->Pos += count;
0784 return *this;
0785 }
0786 ElementRefIterator operator-(size_t count) {
0787 this->Pos -= count;
0788 return *this;
0789 }
0790 };
0791
0792 public:
0793
0794 ElementList Elements;
0795
0796
0797
0798
0799 Stmt *Label = nullptr;
0800
0801
0802
0803 CFGTerminator Terminator;
0804
0805
0806
0807
0808 const Stmt *LoopTarget = nullptr;
0809
0810
0811 unsigned BlockID;
0812
0813 public:
0814
0815
0816
0817
0818
0819 class AdjacentBlock {
0820 enum Kind {
0821 AB_Normal,
0822 AB_Unreachable,
0823 AB_Alternate
0824 };
0825
0826 CFGBlock *ReachableBlock;
0827 llvm::PointerIntPair<CFGBlock *, 2> UnreachableBlock;
0828
0829 public:
0830
0831 AdjacentBlock(CFGBlock *B, bool IsReachable);
0832
0833
0834
0835 AdjacentBlock(CFGBlock *B, CFGBlock *AlternateBlock);
0836
0837
0838 CFGBlock *getReachableBlock() const {
0839 return ReachableBlock;
0840 }
0841
0842
0843 CFGBlock *getPossiblyUnreachableBlock() const {
0844 return UnreachableBlock.getPointer();
0845 }
0846
0847
0848
0849 operator CFGBlock*() const {
0850 return getReachableBlock();
0851 }
0852
0853 CFGBlock& operator *() const {
0854 return *getReachableBlock();
0855 }
0856
0857 CFGBlock* operator ->() const {
0858 return getReachableBlock();
0859 }
0860
0861 bool isReachable() const {
0862 Kind K = (Kind) UnreachableBlock.getInt();
0863 return K == AB_Normal || K == AB_Alternate;
0864 }
0865 };
0866
0867 private:
0868
0869 using AdjacentBlocks = BumpVector<AdjacentBlock>;
0870 AdjacentBlocks Preds;
0871 AdjacentBlocks Succs;
0872
0873
0874
0875
0876
0877
0878
0879
0880
0881
0882 LLVM_PREFERRED_TYPE(bool)
0883 unsigned HasNoReturnElement : 1;
0884
0885
0886 CFG *Parent;
0887
0888 public:
0889 explicit CFGBlock(unsigned blockid, BumpVectorContext &C, CFG *parent)
0890 : Elements(C), Terminator(nullptr), BlockID(blockid), Preds(C, 1),
0891 Succs(C, 1), HasNoReturnElement(false), Parent(parent) {}
0892
0893
0894 using iterator = ElementList::iterator;
0895 using const_iterator = ElementList::const_iterator;
0896 using reverse_iterator = ElementList::reverse_iterator;
0897 using const_reverse_iterator = ElementList::const_reverse_iterator;
0898
0899 size_t getIndexInCFG() const;
0900
0901 CFGElement front() const { return Elements.front(); }
0902 CFGElement back() const { return Elements.back(); }
0903
0904 iterator begin() { return Elements.begin(); }
0905 iterator end() { return Elements.end(); }
0906 const_iterator begin() const { return Elements.begin(); }
0907 const_iterator end() const { return Elements.end(); }
0908
0909 reverse_iterator rbegin() { return Elements.rbegin(); }
0910 reverse_iterator rend() { return Elements.rend(); }
0911 const_reverse_iterator rbegin() const { return Elements.rbegin(); }
0912 const_reverse_iterator rend() const { return Elements.rend(); }
0913
0914 using CFGElementRef = ElementRefImpl<false>;
0915 using ConstCFGElementRef = ElementRefImpl<true>;
0916
0917 using ref_iterator = ElementRefIterator<false, false>;
0918 using ref_iterator_range = llvm::iterator_range<ref_iterator>;
0919 using const_ref_iterator = ElementRefIterator<false, true>;
0920 using const_ref_iterator_range = llvm::iterator_range<const_ref_iterator>;
0921
0922 using reverse_ref_iterator = ElementRefIterator<true, false>;
0923 using reverse_ref_iterator_range = llvm::iterator_range<reverse_ref_iterator>;
0924
0925 using const_reverse_ref_iterator = ElementRefIterator<true, true>;
0926 using const_reverse_ref_iterator_range =
0927 llvm::iterator_range<const_reverse_ref_iterator>;
0928
0929 ref_iterator ref_begin() { return {this, begin()}; }
0930 ref_iterator ref_end() { return {this, end()}; }
0931 const_ref_iterator ref_begin() const { return {this, begin()}; }
0932 const_ref_iterator ref_end() const { return {this, end()}; }
0933
0934 reverse_ref_iterator rref_begin() { return {this, rbegin()}; }
0935 reverse_ref_iterator rref_end() { return {this, rend()}; }
0936 const_reverse_ref_iterator rref_begin() const { return {this, rbegin()}; }
0937 const_reverse_ref_iterator rref_end() const { return {this, rend()}; }
0938
0939 ref_iterator_range refs() { return {ref_begin(), ref_end()}; }
0940 const_ref_iterator_range refs() const { return {ref_begin(), ref_end()}; }
0941 reverse_ref_iterator_range rrefs() { return {rref_begin(), rref_end()}; }
0942 const_reverse_ref_iterator_range rrefs() const {
0943 return {rref_begin(), rref_end()};
0944 }
0945
0946 unsigned size() const { return Elements.size(); }
0947 bool empty() const { return Elements.empty(); }
0948
0949 CFGElement operator[](size_t i) const { return Elements[i]; }
0950
0951
0952 using pred_iterator = AdjacentBlocks::iterator;
0953 using const_pred_iterator = AdjacentBlocks::const_iterator;
0954 using pred_reverse_iterator = AdjacentBlocks::reverse_iterator;
0955 using const_pred_reverse_iterator = AdjacentBlocks::const_reverse_iterator;
0956 using pred_range = llvm::iterator_range<pred_iterator>;
0957 using pred_const_range = llvm::iterator_range<const_pred_iterator>;
0958
0959 using succ_iterator = AdjacentBlocks::iterator;
0960 using const_succ_iterator = AdjacentBlocks::const_iterator;
0961 using succ_reverse_iterator = AdjacentBlocks::reverse_iterator;
0962 using const_succ_reverse_iterator = AdjacentBlocks::const_reverse_iterator;
0963 using succ_range = llvm::iterator_range<succ_iterator>;
0964 using succ_const_range = llvm::iterator_range<const_succ_iterator>;
0965
0966 pred_iterator pred_begin() { return Preds.begin(); }
0967 pred_iterator pred_end() { return Preds.end(); }
0968 const_pred_iterator pred_begin() const { return Preds.begin(); }
0969 const_pred_iterator pred_end() const { return Preds.end(); }
0970
0971 pred_reverse_iterator pred_rbegin() { return Preds.rbegin(); }
0972 pred_reverse_iterator pred_rend() { return Preds.rend(); }
0973 const_pred_reverse_iterator pred_rbegin() const { return Preds.rbegin(); }
0974 const_pred_reverse_iterator pred_rend() const { return Preds.rend(); }
0975
0976 pred_range preds() {
0977 return pred_range(pred_begin(), pred_end());
0978 }
0979
0980 pred_const_range preds() const {
0981 return pred_const_range(pred_begin(), pred_end());
0982 }
0983
0984 succ_iterator succ_begin() { return Succs.begin(); }
0985 succ_iterator succ_end() { return Succs.end(); }
0986 const_succ_iterator succ_begin() const { return Succs.begin(); }
0987 const_succ_iterator succ_end() const { return Succs.end(); }
0988
0989 succ_reverse_iterator succ_rbegin() { return Succs.rbegin(); }
0990 succ_reverse_iterator succ_rend() { return Succs.rend(); }
0991 const_succ_reverse_iterator succ_rbegin() const { return Succs.rbegin(); }
0992 const_succ_reverse_iterator succ_rend() const { return Succs.rend(); }
0993
0994 succ_range succs() {
0995 return succ_range(succ_begin(), succ_end());
0996 }
0997
0998 succ_const_range succs() const {
0999 return succ_const_range(succ_begin(), succ_end());
1000 }
1001
1002 unsigned succ_size() const { return Succs.size(); }
1003 bool succ_empty() const { return Succs.empty(); }
1004
1005 unsigned pred_size() const { return Preds.size(); }
1006 bool pred_empty() const { return Preds.empty(); }
1007
1008
1009 class FilterOptions {
1010 public:
1011 LLVM_PREFERRED_TYPE(bool)
1012 unsigned IgnoreNullPredecessors : 1;
1013 LLVM_PREFERRED_TYPE(bool)
1014 unsigned IgnoreDefaultsWithCoveredEnums : 1;
1015
1016 FilterOptions()
1017 : IgnoreNullPredecessors(1), IgnoreDefaultsWithCoveredEnums(0) {}
1018 };
1019
1020 static bool FilterEdge(const FilterOptions &F, const CFGBlock *Src,
1021 const CFGBlock *Dst);
1022
1023 template <typename IMPL, bool IsPred>
1024 class FilteredCFGBlockIterator {
1025 private:
1026 IMPL I, E;
1027 const FilterOptions F;
1028 const CFGBlock *From;
1029
1030 public:
1031 explicit FilteredCFGBlockIterator(const IMPL &i, const IMPL &e,
1032 const CFGBlock *from,
1033 const FilterOptions &f)
1034 : I(i), E(e), F(f), From(from) {
1035 while (hasMore() && Filter(*I))
1036 ++I;
1037 }
1038
1039 bool hasMore() const { return I != E; }
1040
1041 FilteredCFGBlockIterator &operator++() {
1042 do { ++I; } while (hasMore() && Filter(*I));
1043 return *this;
1044 }
1045
1046 const CFGBlock *operator*() const { return *I; }
1047
1048 private:
1049 bool Filter(const CFGBlock *To) {
1050 return IsPred ? FilterEdge(F, To, From) : FilterEdge(F, From, To);
1051 }
1052 };
1053
1054 using filtered_pred_iterator =
1055 FilteredCFGBlockIterator<const_pred_iterator, true>;
1056
1057 using filtered_succ_iterator =
1058 FilteredCFGBlockIterator<const_succ_iterator, false>;
1059
1060 filtered_pred_iterator filtered_pred_start_end(const FilterOptions &f) const {
1061 return filtered_pred_iterator(pred_begin(), pred_end(), this, f);
1062 }
1063
1064 filtered_succ_iterator filtered_succ_start_end(const FilterOptions &f) const {
1065 return filtered_succ_iterator(succ_begin(), succ_end(), this, f);
1066 }
1067
1068
1069
1070 void setTerminator(CFGTerminator Term) { Terminator = Term; }
1071 void setLabel(Stmt *Statement) { Label = Statement; }
1072 void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; }
1073 void setHasNoReturnElement() { HasNoReturnElement = true; }
1074
1075
1076
1077 bool isInevitablySinking() const;
1078
1079 CFGTerminator getTerminator() const { return Terminator; }
1080
1081 Stmt *getTerminatorStmt() { return Terminator.getStmt(); }
1082 const Stmt *getTerminatorStmt() const { return Terminator.getStmt(); }
1083
1084
1085
1086
1087
1088
1089
1090 const Expr *getLastCondition() const;
1091
1092 Stmt *getTerminatorCondition(bool StripParens = true);
1093
1094 const Stmt *getTerminatorCondition(bool StripParens = true) const {
1095 return const_cast<CFGBlock*>(this)->getTerminatorCondition(StripParens);
1096 }
1097
1098 const Stmt *getLoopTarget() const { return LoopTarget; }
1099
1100 Stmt *getLabel() { return Label; }
1101 const Stmt *getLabel() const { return Label; }
1102
1103 bool hasNoReturnElement() const { return HasNoReturnElement; }
1104
1105 unsigned getBlockID() const { return BlockID; }
1106
1107 CFG *getParent() const { return Parent; }
1108
1109 void dump() const;
1110
1111 void dump(const CFG *cfg, const LangOptions &LO, bool ShowColors = false) const;
1112 void print(raw_ostream &OS, const CFG* cfg, const LangOptions &LO,
1113 bool ShowColors) const;
1114
1115 void printTerminator(raw_ostream &OS, const LangOptions &LO) const;
1116 void printTerminatorJson(raw_ostream &Out, const LangOptions &LO,
1117 bool AddQuotes) const;
1118
1119 void printAsOperand(raw_ostream &OS, bool ) {
1120 OS << "BB#" << getBlockID();
1121 }
1122
1123
1124 void addSuccessor(AdjacentBlock Succ, BumpVectorContext &C);
1125
1126 void appendStmt(Stmt *statement, BumpVectorContext &C) {
1127 Elements.push_back(CFGStmt(statement), C);
1128 }
1129
1130 void appendConstructor(CXXConstructExpr *CE, const ConstructionContext *CC,
1131 BumpVectorContext &C) {
1132 Elements.push_back(CFGConstructor(CE, CC), C);
1133 }
1134
1135 void appendCXXRecordTypedCall(Expr *E,
1136 const ConstructionContext *CC,
1137 BumpVectorContext &C) {
1138 Elements.push_back(CFGCXXRecordTypedCall(E, CC), C);
1139 }
1140
1141 void appendInitializer(CXXCtorInitializer *initializer,
1142 BumpVectorContext &C) {
1143 Elements.push_back(CFGInitializer(initializer), C);
1144 }
1145
1146 void appendNewAllocator(CXXNewExpr *NE,
1147 BumpVectorContext &C) {
1148 Elements.push_back(CFGNewAllocator(NE), C);
1149 }
1150
1151 void appendScopeBegin(const VarDecl *VD, const Stmt *S,
1152 BumpVectorContext &C) {
1153 Elements.push_back(CFGScopeBegin(VD, S), C);
1154 }
1155
1156 void appendScopeEnd(const VarDecl *VD, const Stmt *S, BumpVectorContext &C) {
1157 Elements.push_back(CFGScopeEnd(VD, S), C);
1158 }
1159
1160 void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C) {
1161 Elements.push_back(CFGBaseDtor(BS), C);
1162 }
1163
1164 void appendMemberDtor(FieldDecl *FD, BumpVectorContext &C) {
1165 Elements.push_back(CFGMemberDtor(FD), C);
1166 }
1167
1168 void appendTemporaryDtor(CXXBindTemporaryExpr *E, BumpVectorContext &C) {
1169 Elements.push_back(CFGTemporaryDtor(E), C);
1170 }
1171
1172 void appendAutomaticObjDtor(VarDecl *VD, Stmt *S, BumpVectorContext &C) {
1173 Elements.push_back(CFGAutomaticObjDtor(VD, S), C);
1174 }
1175
1176 void appendCleanupFunction(const VarDecl *VD, BumpVectorContext &C) {
1177 Elements.push_back(CFGCleanupFunction(VD), C);
1178 }
1179
1180 void appendLifetimeEnds(VarDecl *VD, Stmt *S, BumpVectorContext &C) {
1181 Elements.push_back(CFGLifetimeEnds(VD, S), C);
1182 }
1183
1184 void appendLoopExit(const Stmt *LoopStmt, BumpVectorContext &C) {
1185 Elements.push_back(CFGLoopExit(LoopStmt), C);
1186 }
1187
1188 void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) {
1189 Elements.push_back(CFGDeleteDtor(RD, DE), C);
1190 }
1191 };
1192
1193
1194
1195 class CFGCallback {
1196 public:
1197 CFGCallback() = default;
1198 virtual ~CFGCallback() = default;
1199
1200 virtual void logicAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) {}
1201 virtual void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) {}
1202 virtual void compareBitwiseEquality(const BinaryOperator *B,
1203 bool isAlwaysTrue) {}
1204 virtual void compareBitwiseOr(const BinaryOperator *B) {}
1205 };
1206
1207
1208
1209
1210
1211
1212
1213
1214 class CFG {
1215 public:
1216
1217
1218
1219
1220 class BuildOptions {
1221
1222
1223 std::bitset<Stmt::lastStmtConstant + 1> alwaysAddMask;
1224
1225 public:
1226 using ForcedBlkExprs = llvm::DenseMap<const Stmt *, const CFGBlock *>;
1227
1228 ForcedBlkExprs **forcedBlkExprs = nullptr;
1229 CFGCallback *Observer = nullptr;
1230 bool PruneTriviallyFalseEdges = true;
1231 bool AddEHEdges = false;
1232 bool AddInitializers = false;
1233 bool AddImplicitDtors = false;
1234 bool AddLifetime = false;
1235 bool AddLoopExit = false;
1236 bool AddTemporaryDtors = false;
1237 bool AddScopes = false;
1238 bool AddStaticInitBranches = false;
1239 bool AddCXXNewAllocator = false;
1240 bool AddCXXDefaultInitExprInCtors = false;
1241 bool AddCXXDefaultInitExprInAggregates = false;
1242 bool AddRichCXXConstructors = false;
1243 bool MarkElidedCXXConstructors = false;
1244 bool AddVirtualBaseBranches = false;
1245 bool OmitImplicitValueInitializers = false;
1246
1247 BuildOptions() = default;
1248
1249 bool alwaysAdd(const Stmt *stmt) const {
1250 return alwaysAddMask[stmt->getStmtClass()];
1251 }
1252
1253 BuildOptions &setAlwaysAdd(Stmt::StmtClass stmtClass, bool val = true) {
1254 alwaysAddMask[stmtClass] = val;
1255 return *this;
1256 }
1257
1258 BuildOptions &setAllAlwaysAdd() {
1259 alwaysAddMask.set();
1260 return *this;
1261 }
1262 };
1263
1264
1265 static std::unique_ptr<CFG> buildCFG(const Decl *D, Stmt *AST, ASTContext *C,
1266 const BuildOptions &BO);
1267
1268
1269
1270 CFGBlock *createBlock();
1271
1272
1273
1274
1275 void setEntry(CFGBlock *B) { Entry = B; }
1276
1277
1278
1279 void setIndirectGotoBlock(CFGBlock *B) { IndirectGotoBlock = B; }
1280
1281
1282
1283
1284
1285 using CFGBlockListTy = BumpVector<CFGBlock *>;
1286 using iterator = CFGBlockListTy::iterator;
1287 using const_iterator = CFGBlockListTy::const_iterator;
1288 using reverse_iterator = std::reverse_iterator<iterator>;
1289 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
1290
1291 CFGBlock & front() { return *Blocks.front(); }
1292 CFGBlock & back() { return *Blocks.back(); }
1293
1294 iterator begin() { return Blocks.begin(); }
1295 iterator end() { return Blocks.end(); }
1296 const_iterator begin() const { return Blocks.begin(); }
1297 const_iterator end() const { return Blocks.end(); }
1298
1299 iterator nodes_begin() { return iterator(Blocks.begin()); }
1300 iterator nodes_end() { return iterator(Blocks.end()); }
1301
1302 llvm::iterator_range<iterator> nodes() { return {begin(), end()}; }
1303 llvm::iterator_range<const_iterator> const_nodes() const {
1304 return {begin(), end()};
1305 }
1306
1307 const_iterator nodes_begin() const { return const_iterator(Blocks.begin()); }
1308 const_iterator nodes_end() const { return const_iterator(Blocks.end()); }
1309
1310 reverse_iterator rbegin() { return Blocks.rbegin(); }
1311 reverse_iterator rend() { return Blocks.rend(); }
1312 const_reverse_iterator rbegin() const { return Blocks.rbegin(); }
1313 const_reverse_iterator rend() const { return Blocks.rend(); }
1314
1315 llvm::iterator_range<reverse_iterator> reverse_nodes() {
1316 return {rbegin(), rend()};
1317 }
1318 llvm::iterator_range<const_reverse_iterator> const_reverse_nodes() const {
1319 return {rbegin(), rend()};
1320 }
1321
1322 CFGBlock & getEntry() { return *Entry; }
1323 const CFGBlock & getEntry() const { return *Entry; }
1324 CFGBlock & getExit() { return *Exit; }
1325 const CFGBlock & getExit() const { return *Exit; }
1326
1327 CFGBlock * getIndirectGotoBlock() { return IndirectGotoBlock; }
1328 const CFGBlock * getIndirectGotoBlock() const { return IndirectGotoBlock; }
1329
1330 using try_block_iterator = std::vector<const CFGBlock *>::const_iterator;
1331 using try_block_range = llvm::iterator_range<try_block_iterator>;
1332
1333 try_block_iterator try_blocks_begin() const {
1334 return TryDispatchBlocks.begin();
1335 }
1336
1337 try_block_iterator try_blocks_end() const {
1338 return TryDispatchBlocks.end();
1339 }
1340
1341 try_block_range try_blocks() const {
1342 return try_block_range(try_blocks_begin(), try_blocks_end());
1343 }
1344
1345 void addTryDispatchBlock(const CFGBlock *block) {
1346 TryDispatchBlocks.push_back(block);
1347 }
1348
1349
1350
1351
1352
1353 void addSyntheticDeclStmt(const DeclStmt *Synthetic,
1354 const DeclStmt *Source) {
1355 assert(Synthetic->isSingleDecl() && "Can handle single declarations only");
1356 assert(Synthetic != Source && "Don't include original DeclStmts in map");
1357 assert(!SyntheticDeclStmts.count(Synthetic) && "Already in map");
1358 SyntheticDeclStmts[Synthetic] = Source;
1359 }
1360
1361 using synthetic_stmt_iterator =
1362 llvm::DenseMap<const DeclStmt *, const DeclStmt *>::const_iterator;
1363 using synthetic_stmt_range = llvm::iterator_range<synthetic_stmt_iterator>;
1364
1365
1366
1367
1368
1369
1370 synthetic_stmt_iterator synthetic_stmt_begin() const {
1371 return SyntheticDeclStmts.begin();
1372 }
1373
1374
1375 synthetic_stmt_iterator synthetic_stmt_end() const {
1376 return SyntheticDeclStmts.end();
1377 }
1378
1379
1380 synthetic_stmt_range synthetic_stmts() const {
1381 return synthetic_stmt_range(synthetic_stmt_begin(), synthetic_stmt_end());
1382 }
1383
1384
1385
1386
1387
1388 template <typename Callback> void VisitBlockStmts(Callback &O) const {
1389 for (const_iterator I = begin(), E = end(); I != E; ++I)
1390 for (CFGBlock::const_iterator BI = (*I)->begin(), BE = (*I)->end();
1391 BI != BE; ++BI) {
1392 if (std::optional<CFGStmt> stmt = BI->getAs<CFGStmt>())
1393 O(const_cast<Stmt *>(stmt->getStmt()));
1394 }
1395 }
1396
1397
1398
1399
1400
1401
1402 unsigned getNumBlockIDs() const { return NumBlockIDs; }
1403
1404
1405
1406
1407 unsigned size() const { return NumBlockIDs; }
1408
1409
1410
1411
1412
1413 bool isLinear() const;
1414
1415
1416
1417
1418
1419 void viewCFG(const LangOptions &LO) const;
1420 void print(raw_ostream &OS, const LangOptions &LO, bool ShowColors) const;
1421 void dump(const LangOptions &LO, bool ShowColors) const;
1422
1423
1424
1425
1426
1427 CFG() : Blocks(BlkBVC, 10) {}
1428
1429 llvm::BumpPtrAllocator& getAllocator() {
1430 return BlkBVC.getAllocator();
1431 }
1432
1433 BumpVectorContext &getBumpVectorContext() {
1434 return BlkBVC;
1435 }
1436
1437 private:
1438 CFGBlock *Entry = nullptr;
1439 CFGBlock *Exit = nullptr;
1440
1441
1442 CFGBlock* IndirectGotoBlock = nullptr;
1443
1444 unsigned NumBlockIDs = 0;
1445
1446 BumpVectorContext BlkBVC;
1447
1448 CFGBlockListTy Blocks;
1449
1450
1451
1452 std::vector<const CFGBlock *> TryDispatchBlocks;
1453
1454
1455
1456 llvm::DenseMap<const DeclStmt *, const DeclStmt *> SyntheticDeclStmts;
1457 };
1458
1459 Expr *extractElementInitializerFromNestedAILE(const ArrayInitLoopExpr *AILE);
1460
1461 }
1462
1463
1464
1465
1466
1467 namespace llvm {
1468
1469
1470
1471 template <> struct simplify_type< ::clang::CFGTerminator> {
1472 using SimpleType = ::clang::Stmt *;
1473
1474 static SimpleType getSimplifiedValue(::clang::CFGTerminator Val) {
1475 return Val.getStmt();
1476 }
1477 };
1478
1479
1480
1481 template <> struct GraphTraits< ::clang::CFGBlock *> {
1482 using NodeRef = ::clang::CFGBlock *;
1483 using ChildIteratorType = ::clang::CFGBlock::succ_iterator;
1484
1485 static NodeRef getEntryNode(::clang::CFGBlock *BB) { return BB; }
1486 static ChildIteratorType child_begin(NodeRef N) { return N->succ_begin(); }
1487 static ChildIteratorType child_end(NodeRef N) { return N->succ_end(); }
1488 };
1489
1490 template <> struct GraphTraits< const ::clang::CFGBlock *> {
1491 using NodeRef = const ::clang::CFGBlock *;
1492 using ChildIteratorType = ::clang::CFGBlock::const_succ_iterator;
1493
1494 static NodeRef getEntryNode(const clang::CFGBlock *BB) { return BB; }
1495 static ChildIteratorType child_begin(NodeRef N) { return N->succ_begin(); }
1496 static ChildIteratorType child_end(NodeRef N) { return N->succ_end(); }
1497 };
1498
1499 template <> struct GraphTraits<Inverse< ::clang::CFGBlock *>> {
1500 using NodeRef = ::clang::CFGBlock *;
1501 using ChildIteratorType = ::clang::CFGBlock::const_pred_iterator;
1502
1503 static NodeRef getEntryNode(Inverse<::clang::CFGBlock *> G) {
1504 return G.Graph;
1505 }
1506
1507 static ChildIteratorType child_begin(NodeRef N) { return N->pred_begin(); }
1508 static ChildIteratorType child_end(NodeRef N) { return N->pred_end(); }
1509 };
1510
1511 template <> struct GraphTraits<Inverse<const ::clang::CFGBlock *>> {
1512 using NodeRef = const ::clang::CFGBlock *;
1513 using ChildIteratorType = ::clang::CFGBlock::const_pred_iterator;
1514
1515 static NodeRef getEntryNode(Inverse<const ::clang::CFGBlock *> G) {
1516 return G.Graph;
1517 }
1518
1519 static ChildIteratorType child_begin(NodeRef N) { return N->pred_begin(); }
1520 static ChildIteratorType child_end(NodeRef N) { return N->pred_end(); }
1521 };
1522
1523
1524
1525 template <> struct GraphTraits< ::clang::CFG* >
1526 : public GraphTraits< ::clang::CFGBlock *> {
1527 using nodes_iterator = ::clang::CFG::iterator;
1528
1529 static NodeRef getEntryNode(::clang::CFG *F) { return &F->getEntry(); }
1530 static nodes_iterator nodes_begin(::clang::CFG* F) { return F->nodes_begin();}
1531 static nodes_iterator nodes_end(::clang::CFG* F) { return F->nodes_end(); }
1532 static unsigned size(::clang::CFG* F) { return F->size(); }
1533 };
1534
1535 template <> struct GraphTraits<const ::clang::CFG* >
1536 : public GraphTraits<const ::clang::CFGBlock *> {
1537 using nodes_iterator = ::clang::CFG::const_iterator;
1538
1539 static NodeRef getEntryNode(const ::clang::CFG *F) { return &F->getEntry(); }
1540
1541 static nodes_iterator nodes_begin( const ::clang::CFG* F) {
1542 return F->nodes_begin();
1543 }
1544
1545 static nodes_iterator nodes_end( const ::clang::CFG* F) {
1546 return F->nodes_end();
1547 }
1548
1549 static unsigned size(const ::clang::CFG* F) {
1550 return F->size();
1551 }
1552 };
1553
1554 template <> struct GraphTraits<Inverse< ::clang::CFG *>>
1555 : public GraphTraits<Inverse< ::clang::CFGBlock *>> {
1556 using nodes_iterator = ::clang::CFG::iterator;
1557
1558 static NodeRef getEntryNode(::clang::CFG *F) { return &F->getExit(); }
1559 static nodes_iterator nodes_begin( ::clang::CFG* F) {return F->nodes_begin();}
1560 static nodes_iterator nodes_end( ::clang::CFG* F) { return F->nodes_end(); }
1561 };
1562
1563 template <> struct GraphTraits<Inverse<const ::clang::CFG *>>
1564 : public GraphTraits<Inverse<const ::clang::CFGBlock *>> {
1565 using nodes_iterator = ::clang::CFG::const_iterator;
1566
1567 static NodeRef getEntryNode(const ::clang::CFG *F) { return &F->getExit(); }
1568
1569 static nodes_iterator nodes_begin(const ::clang::CFG* F) {
1570 return F->nodes_begin();
1571 }
1572
1573 static nodes_iterator nodes_end(const ::clang::CFG* F) {
1574 return F->nodes_end();
1575 }
1576 };
1577
1578 }
1579
1580 #endif