forked from OSchip/llvm-project
[Analysis] Fix some Clang-tidy modernize and Include What You Use warnings; other minor fixes (NFC).
llvm-svn: 320091
This commit is contained in:
parent
59948666fb
commit
38c70521ff
|
@ -1,4 +1,4 @@
|
|||
//===--- CFG.h - Classes for representing and building CFGs------*- C++ -*-===//
|
||||
//===- CFG.h - Classes for representing and building CFGs -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -17,38 +17,38 @@
|
|||
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/Analysis/Support/BumpVector.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <bitset>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
class CXXDestructorDecl;
|
||||
class Decl;
|
||||
class Stmt;
|
||||
class Expr;
|
||||
class FieldDecl;
|
||||
class VarDecl;
|
||||
class CXXCtorInitializer;
|
||||
class CXXBaseSpecifier;
|
||||
class CXXBindTemporaryExpr;
|
||||
class CFG;
|
||||
class PrinterHelper;
|
||||
class LangOptions;
|
||||
class ASTContext;
|
||||
class CXXRecordDecl;
|
||||
class CXXDeleteExpr;
|
||||
class CXXNewExpr;
|
||||
class BinaryOperator;
|
||||
|
||||
class ASTContext;
|
||||
class BinaryOperator;
|
||||
class CFG;
|
||||
class CXXBaseSpecifier;
|
||||
class CXXBindTemporaryExpr;
|
||||
class CXXCtorInitializer;
|
||||
class CXXDeleteExpr;
|
||||
class CXXDestructorDecl;
|
||||
class CXXNewExpr;
|
||||
class CXXRecordDecl;
|
||||
class Decl;
|
||||
class FieldDecl;
|
||||
class LangOptions;
|
||||
class VarDecl;
|
||||
|
||||
/// CFGElement - Represents a top-level expression in a basic block.
|
||||
class CFGElement {
|
||||
|
@ -76,14 +76,14 @@ protected:
|
|||
llvm::PointerIntPair<void *, 2> Data2;
|
||||
|
||||
CFGElement(Kind kind, const void *Ptr1, const void *Ptr2 = nullptr)
|
||||
: Data1(const_cast<void*>(Ptr1), ((unsigned) kind) & 0x3),
|
||||
Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) {
|
||||
: Data1(const_cast<void*>(Ptr1), ((unsigned) kind) & 0x3),
|
||||
Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) {
|
||||
assert(getKind() == kind);
|
||||
}
|
||||
|
||||
CFGElement() {}
|
||||
public:
|
||||
CFGElement() = default;
|
||||
|
||||
public:
|
||||
/// \brief Convert to the specified CFGElement type, asserting that this
|
||||
/// CFGElement is of the desired type.
|
||||
template<typename T>
|
||||
|
@ -125,7 +125,9 @@ public:
|
|||
|
||||
private:
|
||||
friend class CFGElement;
|
||||
CFGStmt() {}
|
||||
|
||||
CFGStmt() = default;
|
||||
|
||||
static bool isKind(const CFGElement &E) {
|
||||
return E.getKind() == Statement;
|
||||
}
|
||||
|
@ -144,7 +146,9 @@ public:
|
|||
|
||||
private:
|
||||
friend class CFGElement;
|
||||
CFGInitializer() {}
|
||||
|
||||
CFGInitializer() = default;
|
||||
|
||||
static bool isKind(const CFGElement &E) {
|
||||
return E.getKind() == Initializer;
|
||||
}
|
||||
|
@ -163,7 +167,9 @@ public:
|
|||
|
||||
private:
|
||||
friend class CFGElement;
|
||||
CFGNewAllocator() {}
|
||||
|
||||
CFGNewAllocator() = default;
|
||||
|
||||
static bool isKind(const CFGElement &elem) {
|
||||
return elem.getKind() == NewAllocator;
|
||||
}
|
||||
|
@ -177,19 +183,20 @@ private:
|
|||
/// entered.
|
||||
class CFGLoopExit : public CFGElement {
|
||||
public:
|
||||
explicit CFGLoopExit(const Stmt *stmt)
|
||||
: CFGElement(LoopExit, stmt) {}
|
||||
explicit CFGLoopExit(const Stmt *stmt) : CFGElement(LoopExit, stmt) {}
|
||||
|
||||
const Stmt *getLoopStmt() const {
|
||||
return static_cast<Stmt *>(Data1.getPointer());
|
||||
}
|
||||
const Stmt *getLoopStmt() const {
|
||||
return static_cast<Stmt *>(Data1.getPointer());
|
||||
}
|
||||
|
||||
private:
|
||||
friend class CFGElement;
|
||||
CFGLoopExit() {}
|
||||
static bool isKind(const CFGElement &elem) {
|
||||
return elem.getKind() == LoopExit;
|
||||
}
|
||||
friend class CFGElement;
|
||||
|
||||
CFGLoopExit() = default;
|
||||
|
||||
static bool isKind(const CFGElement &elem) {
|
||||
return elem.getKind() == LoopExit;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents the point where the lifetime of an automatic object ends
|
||||
|
@ -208,7 +215,9 @@ public:
|
|||
|
||||
private:
|
||||
friend class CFGElement;
|
||||
CFGLifetimeEnds() {}
|
||||
|
||||
CFGLifetimeEnds() = default;
|
||||
|
||||
static bool isKind(const CFGElement &elem) {
|
||||
return elem.getKind() == LifetimeEnds;
|
||||
}
|
||||
|
@ -218,7 +227,8 @@ private:
|
|||
/// by compiler on various occasions.
|
||||
class CFGImplicitDtor : public CFGElement {
|
||||
protected:
|
||||
CFGImplicitDtor() {}
|
||||
CFGImplicitDtor() = default;
|
||||
|
||||
CFGImplicitDtor(Kind kind, const void *data1, const void *data2 = nullptr)
|
||||
: CFGElement(kind, data1, data2) {
|
||||
assert(kind >= DTOR_BEGIN && kind <= DTOR_END);
|
||||
|
@ -230,6 +240,7 @@ public:
|
|||
|
||||
private:
|
||||
friend class CFGElement;
|
||||
|
||||
static bool isKind(const CFGElement &E) {
|
||||
Kind kind = E.getKind();
|
||||
return kind >= DTOR_BEGIN && kind <= DTOR_END;
|
||||
|
@ -255,7 +266,9 @@ public:
|
|||
|
||||
private:
|
||||
friend class CFGElement;
|
||||
CFGAutomaticObjDtor() {}
|
||||
|
||||
CFGAutomaticObjDtor() = default;
|
||||
|
||||
static bool isKind(const CFGElement &elem) {
|
||||
return elem.getKind() == AutomaticObjectDtor;
|
||||
}
|
||||
|
@ -279,7 +292,9 @@ public:
|
|||
|
||||
private:
|
||||
friend class CFGElement;
|
||||
CFGDeleteDtor() {}
|
||||
|
||||
CFGDeleteDtor() = default;
|
||||
|
||||
static bool isKind(const CFGElement &elem) {
|
||||
return elem.getKind() == DeleteDtor;
|
||||
}
|
||||
|
@ -298,7 +313,9 @@ public:
|
|||
|
||||
private:
|
||||
friend class CFGElement;
|
||||
CFGBaseDtor() {}
|
||||
|
||||
CFGBaseDtor() = default;
|
||||
|
||||
static bool isKind(const CFGElement &E) {
|
||||
return E.getKind() == BaseDtor;
|
||||
}
|
||||
|
@ -317,7 +334,9 @@ public:
|
|||
|
||||
private:
|
||||
friend class CFGElement;
|
||||
CFGMemberDtor() {}
|
||||
|
||||
CFGMemberDtor() = default;
|
||||
|
||||
static bool isKind(const CFGElement &E) {
|
||||
return E.getKind() == MemberDtor;
|
||||
}
|
||||
|
@ -336,7 +355,9 @@ public:
|
|||
|
||||
private:
|
||||
friend class CFGElement;
|
||||
CFGTemporaryDtor() {}
|
||||
|
||||
CFGTemporaryDtor() = default;
|
||||
|
||||
static bool isKind(const CFGElement &E) {
|
||||
return E.getKind() == TemporaryDtor;
|
||||
}
|
||||
|
@ -350,8 +371,9 @@ private:
|
|||
/// of matching full expression.
|
||||
class CFGTerminator {
|
||||
llvm::PointerIntPair<Stmt *, 1> Data;
|
||||
|
||||
public:
|
||||
CFGTerminator() {}
|
||||
CFGTerminator() = default;
|
||||
CFGTerminator(Stmt *S, bool TemporaryDtorsBranch = false)
|
||||
: Data(S, TemporaryDtorsBranch) {}
|
||||
|
||||
|
@ -397,21 +419,23 @@ public:
|
|||
/// &&, || expression that uses result of && or ||, RHS
|
||||
///
|
||||
/// But note that any of that may be NULL in case of optimized-out edges.
|
||||
///
|
||||
class CFGBlock {
|
||||
class ElementList {
|
||||
typedef BumpVector<CFGElement> ImplTy;
|
||||
using ImplTy = BumpVector<CFGElement>;
|
||||
|
||||
ImplTy Impl;
|
||||
|
||||
public:
|
||||
ElementList(BumpVectorContext &C) : Impl(C, 4) {}
|
||||
|
||||
typedef std::reverse_iterator<ImplTy::iterator> iterator;
|
||||
typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator;
|
||||
typedef ImplTy::iterator reverse_iterator;
|
||||
typedef ImplTy::const_iterator const_reverse_iterator;
|
||||
typedef ImplTy::const_reference const_reference;
|
||||
using iterator = std::reverse_iterator<ImplTy::iterator>;
|
||||
using const_iterator = std::reverse_iterator<ImplTy::const_iterator>;
|
||||
using reverse_iterator = ImplTy::iterator;
|
||||
using const_reverse_iterator = ImplTy::const_iterator;
|
||||
using const_reference = ImplTy::const_reference;
|
||||
|
||||
void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); }
|
||||
|
||||
reverse_iterator insert(reverse_iterator I, size_t Cnt, CFGElement E,
|
||||
BumpVectorContext &C) {
|
||||
return Impl.insert(I, Cnt, E, C);
|
||||
|
@ -429,10 +453,10 @@ class CFGBlock {
|
|||
const_reverse_iterator rbegin() const { return Impl.begin(); }
|
||||
const_reverse_iterator rend() const { return Impl.end(); }
|
||||
|
||||
CFGElement operator[](size_t i) const {
|
||||
assert(i < Impl.size());
|
||||
return Impl[Impl.size() - 1 - i];
|
||||
}
|
||||
CFGElement operator[](size_t i) const {
|
||||
assert(i < Impl.size());
|
||||
return Impl[Impl.size() - 1 - i];
|
||||
}
|
||||
|
||||
size_t size() const { return Impl.size(); }
|
||||
bool empty() const { return Impl.empty(); }
|
||||
|
@ -444,7 +468,7 @@ class CFGBlock {
|
|||
/// Label - An (optional) label that prefixes the executable
|
||||
/// statements in the block. When this variable is non-NULL, it is
|
||||
/// either an instance of LabelStmt, SwitchCase or CXXCatchStmt.
|
||||
Stmt *Label;
|
||||
Stmt *Label = nullptr;
|
||||
|
||||
/// Terminator - The terminator for a basic block that
|
||||
/// indicates the type of control-flow that occurs between a block
|
||||
|
@ -454,7 +478,7 @@ class CFGBlock {
|
|||
/// LoopTarget - Some blocks are used to represent the "loop edge" to
|
||||
/// the start of a loop from within the loop body. This Stmt* will be
|
||||
/// refer to the loop statement for such blocks (and be null otherwise).
|
||||
const Stmt *LoopTarget;
|
||||
const Stmt *LoopTarget = nullptr;
|
||||
|
||||
/// BlockID - A numerical ID assigned to a CFGBlock during construction
|
||||
/// of the CFG.
|
||||
|
@ -474,7 +498,7 @@ public:
|
|||
};
|
||||
|
||||
CFGBlock *ReachableBlock;
|
||||
llvm::PointerIntPair<CFGBlock*, 2> UnreachableBlock;
|
||||
llvm::PointerIntPair<CFGBlock *, 2> UnreachableBlock;
|
||||
|
||||
public:
|
||||
/// Construct an AdjacentBlock with a possibly unreachable block.
|
||||
|
@ -517,7 +541,7 @@ public:
|
|||
private:
|
||||
/// Predecessors/Successors - Keep track of the predecessor / successor
|
||||
/// CFG blocks.
|
||||
typedef BumpVector<AdjacentBlock> AdjacentBlocks;
|
||||
using AdjacentBlocks = BumpVector<AdjacentBlock>;
|
||||
AdjacentBlocks Preds;
|
||||
AdjacentBlocks Succs;
|
||||
|
||||
|
@ -537,15 +561,14 @@ private:
|
|||
|
||||
public:
|
||||
explicit CFGBlock(unsigned blockid, BumpVectorContext &C, CFG *parent)
|
||||
: Elements(C), Label(nullptr), Terminator(nullptr), LoopTarget(nullptr),
|
||||
BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false),
|
||||
Parent(parent) {}
|
||||
: Elements(C), Terminator(nullptr), BlockID(blockid), Preds(C, 1),
|
||||
Succs(C, 1), HasNoReturnElement(false), Parent(parent) {}
|
||||
|
||||
// Statement iterators
|
||||
typedef ElementList::iterator iterator;
|
||||
typedef ElementList::const_iterator const_iterator;
|
||||
typedef ElementList::reverse_iterator reverse_iterator;
|
||||
typedef ElementList::const_reverse_iterator const_reverse_iterator;
|
||||
using iterator = ElementList::iterator;
|
||||
using const_iterator = ElementList::const_iterator;
|
||||
using reverse_iterator = ElementList::reverse_iterator;
|
||||
using const_reverse_iterator = ElementList::const_reverse_iterator;
|
||||
|
||||
CFGElement front() const { return Elements.front(); }
|
||||
CFGElement back() const { return Elements.back(); }
|
||||
|
@ -566,19 +589,19 @@ public:
|
|||
CFGElement operator[](size_t i) const { return Elements[i]; }
|
||||
|
||||
// CFG iterators
|
||||
typedef AdjacentBlocks::iterator pred_iterator;
|
||||
typedef AdjacentBlocks::const_iterator const_pred_iterator;
|
||||
typedef AdjacentBlocks::reverse_iterator pred_reverse_iterator;
|
||||
typedef AdjacentBlocks::const_reverse_iterator const_pred_reverse_iterator;
|
||||
typedef llvm::iterator_range<pred_iterator> pred_range;
|
||||
typedef llvm::iterator_range<const_pred_iterator> pred_const_range;
|
||||
using pred_iterator = AdjacentBlocks::iterator;
|
||||
using const_pred_iterator = AdjacentBlocks::const_iterator;
|
||||
using pred_reverse_iterator = AdjacentBlocks::reverse_iterator;
|
||||
using const_pred_reverse_iterator = AdjacentBlocks::const_reverse_iterator;
|
||||
using pred_range = llvm::iterator_range<pred_iterator>;
|
||||
using pred_const_range = llvm::iterator_range<const_pred_iterator>;
|
||||
|
||||
typedef AdjacentBlocks::iterator succ_iterator;
|
||||
typedef AdjacentBlocks::const_iterator const_succ_iterator;
|
||||
typedef AdjacentBlocks::reverse_iterator succ_reverse_iterator;
|
||||
typedef AdjacentBlocks::const_reverse_iterator const_succ_reverse_iterator;
|
||||
typedef llvm::iterator_range<succ_iterator> succ_range;
|
||||
typedef llvm::iterator_range<const_succ_iterator> succ_const_range;
|
||||
using succ_iterator = AdjacentBlocks::iterator;
|
||||
using const_succ_iterator = AdjacentBlocks::const_iterator;
|
||||
using succ_reverse_iterator = AdjacentBlocks::reverse_iterator;
|
||||
using const_succ_reverse_iterator = AdjacentBlocks::const_reverse_iterator;
|
||||
using succ_range = llvm::iterator_range<succ_iterator>;
|
||||
using succ_const_range = llvm::iterator_range<const_succ_iterator>;
|
||||
|
||||
pred_iterator pred_begin() { return Preds.begin(); }
|
||||
pred_iterator pred_end() { return Preds.end(); }
|
||||
|
@ -590,10 +613,11 @@ public:
|
|||
const_pred_reverse_iterator pred_rbegin() const { return Preds.rbegin(); }
|
||||
const_pred_reverse_iterator pred_rend() const { return Preds.rend(); }
|
||||
|
||||
pred_range preds() {
|
||||
pred_range preds() {
|
||||
return pred_range(pred_begin(), pred_end());
|
||||
}
|
||||
pred_const_range preds() const {
|
||||
|
||||
pred_const_range preds() const {
|
||||
return pred_const_range(pred_begin(), pred_end());
|
||||
}
|
||||
|
||||
|
@ -607,10 +631,11 @@ public:
|
|||
const_succ_reverse_iterator succ_rbegin() const { return Succs.rbegin(); }
|
||||
const_succ_reverse_iterator succ_rend() const { return Succs.rend(); }
|
||||
|
||||
succ_range succs() {
|
||||
succ_range succs() {
|
||||
return succ_range(succ_begin(), succ_end());
|
||||
}
|
||||
succ_const_range succs() const {
|
||||
|
||||
succ_const_range succs() const {
|
||||
return succ_const_range(succ_begin(), succ_end());
|
||||
}
|
||||
|
||||
|
@ -623,13 +648,11 @@ public:
|
|||
|
||||
class FilterOptions {
|
||||
public:
|
||||
FilterOptions() {
|
||||
IgnoreNullPredecessors = 1;
|
||||
IgnoreDefaultsWithCoveredEnums = 0;
|
||||
}
|
||||
|
||||
unsigned IgnoreNullPredecessors : 1;
|
||||
unsigned IgnoreDefaultsWithCoveredEnums : 1;
|
||||
|
||||
FilterOptions()
|
||||
: IgnoreNullPredecessors(1), IgnoreDefaultsWithCoveredEnums(0) {}
|
||||
};
|
||||
|
||||
static bool FilterEdge(const FilterOptions &F, const CFGBlock *Src,
|
||||
|
@ -641,6 +664,7 @@ public:
|
|||
IMPL I, E;
|
||||
const FilterOptions F;
|
||||
const CFGBlock *From;
|
||||
|
||||
public:
|
||||
explicit FilteredCFGBlockIterator(const IMPL &i, const IMPL &e,
|
||||
const CFGBlock *from,
|
||||
|
@ -658,17 +682,18 @@ public:
|
|||
}
|
||||
|
||||
const CFGBlock *operator*() const { return *I; }
|
||||
|
||||
private:
|
||||
bool Filter(const CFGBlock *To) {
|
||||
return IsPred ? FilterEdge(F, To, From) : FilterEdge(F, From, To);
|
||||
}
|
||||
};
|
||||
|
||||
typedef FilteredCFGBlockIterator<const_pred_iterator, true>
|
||||
filtered_pred_iterator;
|
||||
using filtered_pred_iterator =
|
||||
FilteredCFGBlockIterator<const_pred_iterator, true>;
|
||||
|
||||
typedef FilteredCFGBlockIterator<const_succ_iterator, false>
|
||||
filtered_succ_iterator;
|
||||
using filtered_succ_iterator =
|
||||
FilteredCFGBlockIterator<const_succ_iterator, false>;
|
||||
|
||||
filtered_pred_iterator filtered_pred_start_end(const FilterOptions &f) const {
|
||||
return filtered_pred_iterator(pred_begin(), pred_end(), this, f);
|
||||
|
@ -791,11 +816,12 @@ public:
|
|||
/// operator error is found when building the CFG.
|
||||
class CFGCallback {
|
||||
public:
|
||||
CFGCallback() {}
|
||||
CFGCallback() = default;
|
||||
virtual ~CFGCallback() = default;
|
||||
|
||||
virtual void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) {}
|
||||
virtual void compareBitwiseEquality(const BinaryOperator *B,
|
||||
bool isAlwaysTrue) {}
|
||||
virtual ~CFGCallback() {}
|
||||
};
|
||||
|
||||
/// CFG - Represents a source-level, intra-procedural CFG that represents the
|
||||
|
@ -813,20 +839,24 @@ public:
|
|||
|
||||
class BuildOptions {
|
||||
std::bitset<Stmt::lastStmtConstant> alwaysAddMask;
|
||||
|
||||
public:
|
||||
typedef llvm::DenseMap<const Stmt *, const CFGBlock*> ForcedBlkExprs;
|
||||
ForcedBlkExprs **forcedBlkExprs;
|
||||
CFGCallback *Observer;
|
||||
bool PruneTriviallyFalseEdges;
|
||||
bool AddEHEdges;
|
||||
bool AddInitializers;
|
||||
bool AddImplicitDtors;
|
||||
bool AddLifetime;
|
||||
bool AddLoopExit;
|
||||
bool AddTemporaryDtors;
|
||||
bool AddStaticInitBranches;
|
||||
bool AddCXXNewAllocator;
|
||||
bool AddCXXDefaultInitExprInCtors;
|
||||
using ForcedBlkExprs = llvm::DenseMap<const Stmt *, const CFGBlock *>;
|
||||
|
||||
ForcedBlkExprs **forcedBlkExprs = nullptr;
|
||||
CFGCallback *Observer = nullptr;
|
||||
bool PruneTriviallyFalseEdges = true;
|
||||
bool AddEHEdges = false;
|
||||
bool AddInitializers = false;
|
||||
bool AddImplicitDtors = false;
|
||||
bool AddLifetime = false;
|
||||
bool AddLoopExit = false;
|
||||
bool AddTemporaryDtors = false;
|
||||
bool AddStaticInitBranches = false;
|
||||
bool AddCXXNewAllocator = false;
|
||||
bool AddCXXDefaultInitExprInCtors = false;
|
||||
|
||||
BuildOptions() = default;
|
||||
|
||||
bool alwaysAdd(const Stmt *stmt) const {
|
||||
return alwaysAddMask[stmt->getStmtClass()];
|
||||
|
@ -841,15 +871,6 @@ public:
|
|||
alwaysAddMask.set();
|
||||
return *this;
|
||||
}
|
||||
|
||||
BuildOptions()
|
||||
: forcedBlkExprs(nullptr), Observer(nullptr),
|
||||
PruneTriviallyFalseEdges(true),
|
||||
AddEHEdges(false),
|
||||
AddInitializers(false), AddImplicitDtors(false),
|
||||
AddLifetime(false), AddLoopExit(false),
|
||||
AddTemporaryDtors(false), AddStaticInitBranches(false),
|
||||
AddCXXNewAllocator(false), AddCXXDefaultInitExprInCtors(false) {}
|
||||
};
|
||||
|
||||
/// buildCFG - Builds a CFG from an AST.
|
||||
|
@ -873,11 +894,11 @@ public:
|
|||
// Block Iterators
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
typedef BumpVector<CFGBlock*> CFGBlockListTy;
|
||||
typedef CFGBlockListTy::iterator iterator;
|
||||
typedef CFGBlockListTy::const_iterator const_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
using CFGBlockListTy = BumpVector<CFGBlock *>;
|
||||
using iterator = CFGBlockListTy::iterator;
|
||||
using const_iterator = CFGBlockListTy::const_iterator;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
CFGBlock & front() { return *Blocks.front(); }
|
||||
CFGBlock & back() { return *Blocks.back(); }
|
||||
|
@ -905,10 +926,12 @@ public:
|
|||
CFGBlock * getIndirectGotoBlock() { return IndirectGotoBlock; }
|
||||
const CFGBlock * getIndirectGotoBlock() const { return IndirectGotoBlock; }
|
||||
|
||||
typedef std::vector<const CFGBlock*>::const_iterator try_block_iterator;
|
||||
using try_block_iterator = std::vector<const CFGBlock *>::const_iterator;
|
||||
|
||||
try_block_iterator try_blocks_begin() const {
|
||||
return TryDispatchBlocks.begin();
|
||||
}
|
||||
|
||||
try_block_iterator try_blocks_end() const {
|
||||
return TryDispatchBlocks.end();
|
||||
}
|
||||
|
@ -929,9 +952,9 @@ public:
|
|||
SyntheticDeclStmts[Synthetic] = Source;
|
||||
}
|
||||
|
||||
typedef llvm::DenseMap<const DeclStmt *, const DeclStmt *>::const_iterator
|
||||
synthetic_stmt_iterator;
|
||||
typedef llvm::iterator_range<synthetic_stmt_iterator> synthetic_stmt_range;
|
||||
using synthetic_stmt_iterator =
|
||||
llvm::DenseMap<const DeclStmt *, const DeclStmt *>::const_iterator;
|
||||
using synthetic_stmt_range = llvm::iterator_range<synthetic_stmt_iterator>;
|
||||
|
||||
/// Iterates over synthetic DeclStmts in the CFG.
|
||||
///
|
||||
|
@ -991,9 +1014,7 @@ public:
|
|||
// Internal: constructors and data.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
CFG()
|
||||
: Entry(nullptr), Exit(nullptr), IndirectGotoBlock(nullptr), NumBlockIDs(0),
|
||||
Blocks(BlkBVC, 10) {}
|
||||
CFG() : Blocks(BlkBVC, 10) {}
|
||||
|
||||
llvm::BumpPtrAllocator& getAllocator() {
|
||||
return BlkBVC.getAllocator();
|
||||
|
@ -1004,11 +1025,13 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
CFGBlock *Entry;
|
||||
CFGBlock *Exit;
|
||||
CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch
|
||||
// for indirect gotos
|
||||
unsigned NumBlockIDs;
|
||||
CFGBlock *Entry = nullptr;
|
||||
CFGBlock *Exit = nullptr;
|
||||
|
||||
// Special block to contain collective dispatch for indirect gotos
|
||||
CFGBlock* IndirectGotoBlock = nullptr;
|
||||
|
||||
unsigned NumBlockIDs = 0;
|
||||
|
||||
BumpVectorContext BlkBVC;
|
||||
|
||||
|
@ -1022,7 +1045,8 @@ private:
|
|||
/// source DeclStmt.
|
||||
llvm::DenseMap<const DeclStmt *, const DeclStmt *> SyntheticDeclStmts;
|
||||
};
|
||||
} // end namespace clang
|
||||
|
||||
} // namespace clang
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GraphTraits specializations for CFG basic block graphs (source-level CFGs)
|
||||
|
@ -1033,7 +1057,8 @@ namespace llvm {
|
|||
/// Implement simplify_type for CFGTerminator, so that we can dyn_cast from
|
||||
/// CFGTerminator to a specific Stmt class.
|
||||
template <> struct simplify_type< ::clang::CFGTerminator> {
|
||||
typedef ::clang::Stmt *SimpleType;
|
||||
using SimpleType = ::clang::Stmt *;
|
||||
|
||||
static SimpleType getSimplifiedValue(::clang::CFGTerminator Val) {
|
||||
return Val.getStmt();
|
||||
}
|
||||
|
@ -1042,50 +1067,44 @@ template <> struct simplify_type< ::clang::CFGTerminator> {
|
|||
// Traits for: CFGBlock
|
||||
|
||||
template <> struct GraphTraits< ::clang::CFGBlock *> {
|
||||
typedef ::clang::CFGBlock *NodeRef;
|
||||
typedef ::clang::CFGBlock::succ_iterator ChildIteratorType;
|
||||
using NodeRef = ::clang::CFGBlock *;
|
||||
using ChildIteratorType = ::clang::CFGBlock::succ_iterator;
|
||||
|
||||
static NodeRef getEntryNode(::clang::CFGBlock *BB) { return BB; }
|
||||
|
||||
static ChildIteratorType child_begin(NodeRef N) { return N->succ_begin(); }
|
||||
|
||||
static ChildIteratorType child_end(NodeRef N) { return N->succ_end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits< const ::clang::CFGBlock *> {
|
||||
typedef const ::clang::CFGBlock *NodeRef;
|
||||
typedef ::clang::CFGBlock::const_succ_iterator ChildIteratorType;
|
||||
using NodeRef = const ::clang::CFGBlock *;
|
||||
using ChildIteratorType = ::clang::CFGBlock::const_succ_iterator;
|
||||
|
||||
static NodeRef getEntryNode(const clang::CFGBlock *BB) { return BB; }
|
||||
|
||||
static ChildIteratorType child_begin(NodeRef N) { return N->succ_begin(); }
|
||||
|
||||
static ChildIteratorType child_end(NodeRef N) { return N->succ_end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<Inverse< ::clang::CFGBlock*> > {
|
||||
typedef ::clang::CFGBlock *NodeRef;
|
||||
typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType;
|
||||
template <> struct GraphTraits<Inverse< ::clang::CFGBlock *>> {
|
||||
using NodeRef = ::clang::CFGBlock *;
|
||||
using ChildIteratorType = ::clang::CFGBlock::const_pred_iterator;
|
||||
|
||||
static NodeRef getEntryNode(Inverse<::clang::CFGBlock *> G) {
|
||||
return G.Graph;
|
||||
}
|
||||
|
||||
static ChildIteratorType child_begin(NodeRef N) { return N->pred_begin(); }
|
||||
|
||||
static ChildIteratorType child_end(NodeRef N) { return N->pred_end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > {
|
||||
typedef const ::clang::CFGBlock *NodeRef;
|
||||
typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType;
|
||||
template <> struct GraphTraits<Inverse<const ::clang::CFGBlock *>> {
|
||||
using NodeRef = const ::clang::CFGBlock *;
|
||||
using ChildIteratorType = ::clang::CFGBlock::const_pred_iterator;
|
||||
|
||||
static NodeRef getEntryNode(Inverse<const ::clang::CFGBlock *> G) {
|
||||
return G.Graph;
|
||||
}
|
||||
|
||||
static ChildIteratorType child_begin(NodeRef N) { return N->pred_begin(); }
|
||||
|
||||
static ChildIteratorType child_end(NodeRef N) { return N->pred_end(); }
|
||||
};
|
||||
|
||||
|
@ -1093,8 +1112,7 @@ template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > {
|
|||
|
||||
template <> struct GraphTraits< ::clang::CFG* >
|
||||
: public GraphTraits< ::clang::CFGBlock *> {
|
||||
|
||||
typedef ::clang::CFG::iterator nodes_iterator;
|
||||
using nodes_iterator = ::clang::CFG::iterator;
|
||||
|
||||
static NodeRef getEntryNode(::clang::CFG *F) { return &F->getEntry(); }
|
||||
static nodes_iterator nodes_begin(::clang::CFG* F) { return F->nodes_begin();}
|
||||
|
@ -1104,44 +1122,47 @@ template <> struct GraphTraits< ::clang::CFG* >
|
|||
|
||||
template <> struct GraphTraits<const ::clang::CFG* >
|
||||
: public GraphTraits<const ::clang::CFGBlock *> {
|
||||
|
||||
typedef ::clang::CFG::const_iterator nodes_iterator;
|
||||
using nodes_iterator = ::clang::CFG::const_iterator;
|
||||
|
||||
static NodeRef getEntryNode(const ::clang::CFG *F) { return &F->getEntry(); }
|
||||
|
||||
static nodes_iterator nodes_begin( const ::clang::CFG* F) {
|
||||
return F->nodes_begin();
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end( const ::clang::CFG* F) {
|
||||
return F->nodes_end();
|
||||
}
|
||||
|
||||
static unsigned size(const ::clang::CFG* F) {
|
||||
return F->size();
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<Inverse< ::clang::CFG*> >
|
||||
: public GraphTraits<Inverse< ::clang::CFGBlock*> > {
|
||||
|
||||
typedef ::clang::CFG::iterator nodes_iterator;
|
||||
template <> struct GraphTraits<Inverse< ::clang::CFG *>>
|
||||
: public GraphTraits<Inverse< ::clang::CFGBlock *>> {
|
||||
using nodes_iterator = ::clang::CFG::iterator;
|
||||
|
||||
static NodeRef getEntryNode(::clang::CFG *F) { return &F->getExit(); }
|
||||
static nodes_iterator nodes_begin( ::clang::CFG* F) {return F->nodes_begin();}
|
||||
static nodes_iterator nodes_end( ::clang::CFG* F) { return F->nodes_end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<Inverse<const ::clang::CFG*> >
|
||||
: public GraphTraits<Inverse<const ::clang::CFGBlock*> > {
|
||||
|
||||
typedef ::clang::CFG::const_iterator nodes_iterator;
|
||||
template <> struct GraphTraits<Inverse<const ::clang::CFG *>>
|
||||
: public GraphTraits<Inverse<const ::clang::CFGBlock *>> {
|
||||
using nodes_iterator = ::clang::CFG::const_iterator;
|
||||
|
||||
static NodeRef getEntryNode(const ::clang::CFG *F) { return &F->getExit(); }
|
||||
|
||||
static nodes_iterator nodes_begin(const ::clang::CFG* F) {
|
||||
return F->nodes_begin();
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end(const ::clang::CFG* F) {
|
||||
return F->nodes_end();
|
||||
}
|
||||
};
|
||||
} // end llvm namespace
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_CLANG_ANALYSIS_CFG_H
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//== CallGraph.h - AST-based Call graph ------------------------*- C++ -*--==//
|
||||
//===- CallGraph.h - AST-based Call graph -----------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -12,19 +12,27 @@
|
|||
// A call graph for functions whose definitions/bodies are available in the
|
||||
// current translation unit. The graph has a "virtual" root node that contains
|
||||
// edges to all externally available functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH_H
|
||||
#define LLVM_CLANG_ANALYSIS_CALLGRAPH_H
|
||||
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <memory>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class CallGraphNode;
|
||||
class Decl;
|
||||
class DeclContext;
|
||||
class Stmt;
|
||||
|
||||
/// \brief The AST-based call graph.
|
||||
///
|
||||
|
@ -34,8 +42,8 @@ class CallGraphNode;
|
|||
class CallGraph : public RecursiveASTVisitor<CallGraph> {
|
||||
friend class CallGraphNode;
|
||||
|
||||
typedef llvm::DenseMap<const Decl *, std::unique_ptr<CallGraphNode>>
|
||||
FunctionMapTy;
|
||||
using FunctionMapTy =
|
||||
llvm::DenseMap<const Decl *, std::unique_ptr<CallGraphNode>>;
|
||||
|
||||
/// FunctionMap owns all CallGraphNodes.
|
||||
FunctionMapTy FunctionMap;
|
||||
|
@ -65,10 +73,11 @@ public:
|
|||
/// one into the graph.
|
||||
CallGraphNode *getOrInsertNode(Decl *);
|
||||
|
||||
using iterator = FunctionMapTy::iterator;
|
||||
using const_iterator = FunctionMapTy::const_iterator;
|
||||
|
||||
/// Iterators through all the elements in the graph. Note, this gives
|
||||
/// non-deterministic order.
|
||||
typedef FunctionMapTy::iterator iterator;
|
||||
typedef FunctionMapTy::const_iterator const_iterator;
|
||||
iterator begin() { return FunctionMap.begin(); }
|
||||
iterator end() { return FunctionMap.end(); }
|
||||
const_iterator begin() const { return FunctionMap.begin(); }
|
||||
|
@ -84,8 +93,8 @@ public:
|
|||
/// Iterators through all the nodes of the graph that have no parent. These
|
||||
/// are the unreachable nodes, which are either unused or are due to us
|
||||
/// failing to add a call edge due to the analysis imprecision.
|
||||
typedef llvm::SetVector<CallGraphNode *>::iterator nodes_iterator;
|
||||
typedef llvm::SetVector<CallGraphNode *>::const_iterator const_nodes_iterator;
|
||||
using nodes_iterator = llvm::SetVector<CallGraphNode *>::iterator;
|
||||
using const_nodes_iterator = llvm::SetVector<CallGraphNode *>::const_iterator;
|
||||
|
||||
void print(raw_ostream &os) const;
|
||||
void dump() const;
|
||||
|
@ -133,7 +142,7 @@ private:
|
|||
|
||||
class CallGraphNode {
|
||||
public:
|
||||
typedef CallGraphNode* CallRecord;
|
||||
using CallRecord = CallGraphNode *;
|
||||
|
||||
private:
|
||||
/// \brief The function/method declaration.
|
||||
|
@ -145,17 +154,17 @@ private:
|
|||
public:
|
||||
CallGraphNode(Decl *D) : FD(D) {}
|
||||
|
||||
typedef SmallVectorImpl<CallRecord>::iterator iterator;
|
||||
typedef SmallVectorImpl<CallRecord>::const_iterator const_iterator;
|
||||
using iterator = SmallVectorImpl<CallRecord>::iterator;
|
||||
using const_iterator = SmallVectorImpl<CallRecord>::const_iterator;
|
||||
|
||||
/// Iterators through all the callees/children of the node.
|
||||
inline iterator begin() { return CalledFunctions.begin(); }
|
||||
inline iterator end() { return CalledFunctions.end(); }
|
||||
inline const_iterator begin() const { return CalledFunctions.begin(); }
|
||||
inline const_iterator end() const { return CalledFunctions.end(); }
|
||||
iterator begin() { return CalledFunctions.begin(); }
|
||||
iterator end() { return CalledFunctions.end(); }
|
||||
const_iterator begin() const { return CalledFunctions.begin(); }
|
||||
const_iterator end() const { return CalledFunctions.end(); }
|
||||
|
||||
inline bool empty() const {return CalledFunctions.empty(); }
|
||||
inline unsigned size() const {return CalledFunctions.size(); }
|
||||
bool empty() const { return CalledFunctions.empty(); }
|
||||
unsigned size() const { return CalledFunctions.size(); }
|
||||
|
||||
void addCallee(CallGraphNode *N) {
|
||||
CalledFunctions.push_back(N);
|
||||
|
@ -167,35 +176,33 @@ public:
|
|||
void dump() const;
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
} // namespace clang
|
||||
|
||||
// Graph traits for iteration, viewing.
|
||||
namespace llvm {
|
||||
|
||||
template <> struct GraphTraits<clang::CallGraphNode*> {
|
||||
typedef clang::CallGraphNode NodeType;
|
||||
typedef clang::CallGraphNode *NodeRef;
|
||||
typedef NodeType::iterator ChildIteratorType;
|
||||
using NodeType = clang::CallGraphNode;
|
||||
using NodeRef = clang::CallGraphNode *;
|
||||
using ChildIteratorType = NodeType::iterator;
|
||||
|
||||
static NodeType *getEntryNode(clang::CallGraphNode *CGN) { return CGN; }
|
||||
static inline ChildIteratorType child_begin(NodeType *N) {
|
||||
return N->begin();
|
||||
}
|
||||
static inline ChildIteratorType child_end(NodeType *N) { return N->end(); }
|
||||
static ChildIteratorType child_begin(NodeType *N) { return N->begin(); }
|
||||
static ChildIteratorType child_end(NodeType *N) { return N->end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<const clang::CallGraphNode*> {
|
||||
typedef const clang::CallGraphNode NodeType;
|
||||
typedef const clang::CallGraphNode *NodeRef;
|
||||
typedef NodeType::const_iterator ChildIteratorType;
|
||||
using NodeType = const clang::CallGraphNode;
|
||||
using NodeRef = const clang::CallGraphNode *;
|
||||
using ChildIteratorType = NodeType::const_iterator;
|
||||
|
||||
static NodeType *getEntryNode(const clang::CallGraphNode *CGN) { return CGN; }
|
||||
static inline ChildIteratorType child_begin(NodeType *N) { return N->begin();}
|
||||
static inline ChildIteratorType child_end(NodeType *N) { return N->end(); }
|
||||
static ChildIteratorType child_begin(NodeType *N) { return N->begin();}
|
||||
static ChildIteratorType child_end(NodeType *N) { return N->end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<clang::CallGraph*>
|
||||
: public GraphTraits<clang::CallGraphNode*> {
|
||||
|
||||
static NodeType *getEntryNode(clang::CallGraph *CGN) {
|
||||
return CGN->getRoot(); // Start at the external node!
|
||||
}
|
||||
|
@ -206,19 +213,18 @@ template <> struct GraphTraits<clang::CallGraph*>
|
|||
}
|
||||
|
||||
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
|
||||
typedef mapped_iterator<clang::CallGraph::iterator, decltype(&CGGetValue)>
|
||||
nodes_iterator;
|
||||
using nodes_iterator =
|
||||
mapped_iterator<clang::CallGraph::iterator, decltype(&CGGetValue)>;
|
||||
|
||||
static nodes_iterator nodes_begin(clang::CallGraph *CG) {
|
||||
return nodes_iterator(CG->begin(), &CGGetValue);
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end (clang::CallGraph *CG) {
|
||||
return nodes_iterator(CG->end(), &CGGetValue);
|
||||
}
|
||||
|
||||
static unsigned size(clang::CallGraph *CG) {
|
||||
return CG->size();
|
||||
}
|
||||
static unsigned size(clang::CallGraph *CG) { return CG->size(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<const clang::CallGraph*> :
|
||||
|
@ -233,21 +239,20 @@ template <> struct GraphTraits<const clang::CallGraph*> :
|
|||
}
|
||||
|
||||
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
|
||||
typedef mapped_iterator<clang::CallGraph::const_iterator,
|
||||
decltype(&CGGetValue)>
|
||||
nodes_iterator;
|
||||
using nodes_iterator =
|
||||
mapped_iterator<clang::CallGraph::const_iterator, decltype(&CGGetValue)>;
|
||||
|
||||
static nodes_iterator nodes_begin(const clang::CallGraph *CG) {
|
||||
return nodes_iterator(CG->begin(), &CGGetValue);
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end(const clang::CallGraph *CG) {
|
||||
return nodes_iterator(CG->end(), &CGGetValue);
|
||||
}
|
||||
static unsigned size(const clang::CallGraph *CG) {
|
||||
return CG->size();
|
||||
}
|
||||
|
||||
static unsigned size(const clang::CallGraph *CG) { return CG->size(); }
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CLANG_ANALYSIS_CALLGRAPH_H
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===-- BumpVector.h - Vector-like ADT that uses bump allocation --*- C++ -*-=//
|
||||
//===- BumpVector.h - Vector-like ADT that uses bump allocation -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -21,16 +21,18 @@
|
|||
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class BumpVectorContext {
|
||||
llvm::PointerIntPair<llvm::BumpPtrAllocator*, 1> Alloc;
|
||||
|
||||
public:
|
||||
/// Construct a new BumpVectorContext that creates a new BumpPtrAllocator
|
||||
/// and destroys it when the BumpVectorContext object is destroyed.
|
||||
|
@ -56,11 +58,13 @@ public:
|
|||
|
||||
template<typename T>
|
||||
class BumpVector {
|
||||
T *Begin, *End, *Capacity;
|
||||
T *Begin = nullptr;
|
||||
T *End = nullptr;
|
||||
T *Capacity = nullptr;
|
||||
|
||||
public:
|
||||
// Default ctor - Initialize to empty.
|
||||
explicit BumpVector(BumpVectorContext &C, unsigned N)
|
||||
: Begin(nullptr), End(nullptr), Capacity(nullptr) {
|
||||
explicit BumpVector(BumpVectorContext &C, unsigned N) {
|
||||
reserve(C, N);
|
||||
}
|
||||
|
||||
|
@ -71,19 +75,19 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef T value_type;
|
||||
typedef T* iterator;
|
||||
typedef const T* const_iterator;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using value_type = T;
|
||||
using iterator = T *;
|
||||
using const_iterator = const T *;
|
||||
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
using reference = T &;
|
||||
using const_reference = const T &;
|
||||
using pointer = T *;
|
||||
using const_pointer = const T *;
|
||||
|
||||
// forward iterator creation methods.
|
||||
iterator begin() { return Begin; }
|
||||
|
@ -92,10 +96,12 @@ public:
|
|||
const_iterator end() const { return End; }
|
||||
|
||||
// reverse iterator creation methods.
|
||||
reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||
reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||
const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
|
||||
reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||
const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
|
||||
reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||
const_reverse_iterator rend() const {
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
bool empty() const { return Begin == End; }
|
||||
size_type size() const { return End-Begin; }
|
||||
|
@ -166,7 +172,7 @@ public:
|
|||
/// iterator to position after last inserted copy.
|
||||
iterator insert(iterator I, size_t Cnt, const_reference E,
|
||||
BumpVectorContext &C) {
|
||||
assert (I >= Begin && I <= End && "Iterator out of bounds.");
|
||||
assert(I >= Begin && I <= End && "Iterator out of bounds.");
|
||||
if (End + Cnt <= Capacity) {
|
||||
Retry:
|
||||
move_range_right(I, End, Cnt);
|
||||
|
@ -246,5 +252,6 @@ void BumpVector<T>::grow(BumpVectorContext &C, size_t MinSize) {
|
|||
Capacity = Begin+NewCapacity;
|
||||
}
|
||||
|
||||
} // end: clang namespace
|
||||
#endif
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_ANALYSIS_SUPPORT_BUMPVECTOR_H
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===--- CFG.cpp - Classes for representing and building CFGs----*- C++ -*-===//
|
||||
//===- CFG.cpp - Classes for representing and building CFGs ---------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -15,23 +15,53 @@
|
|||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclGroup.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/OperationKinds.h"
|
||||
#include "clang/AST/PrettyPrinter.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/StmtObjC.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Analysis/Support/BumpVector.h"
|
||||
#include "clang/Basic/Builtins.h"
|
||||
#include "clang/Basic/ExceptionSpecificationType.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include <memory>
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/DOTGraphTraits.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/GraphWriter.h"
|
||||
#include "llvm/Support/SaveAndRestore.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
|
||||
static SourceLocation GetEndLoc(Decl *D) {
|
||||
if (VarDecl *VD = dyn_cast<VarDecl>(D))
|
||||
if (Expr *Ex = VD->getInit())
|
||||
|
@ -41,7 +71,7 @@ static SourceLocation GetEndLoc(Decl *D) {
|
|||
|
||||
/// Helper for tryNormalizeBinaryOperator. Attempts to extract an IntegerLiteral
|
||||
/// or EnumConstantDecl from the given Expr. If it fails, returns nullptr.
|
||||
const Expr *tryTransformToIntOrEnumConstant(const Expr *E) {
|
||||
static const Expr *tryTransformToIntOrEnumConstant(const Expr *E) {
|
||||
E = E->IgnoreParens();
|
||||
if (isa<IntegerLiteral>(E))
|
||||
return E;
|
||||
|
@ -111,6 +141,8 @@ static bool areExprTypesCompatible(const Expr *E1, const Expr *E2) {
|
|||
return DC1 == DC2;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class CFGBuilder;
|
||||
|
||||
/// The CFG builder uses a recursive algorithm to build the CFG. When
|
||||
|
@ -125,7 +157,6 @@ class CFGBuilder;
|
|||
/// contextual information. If AddStmtChoice is 'NotAlwaysAdd', then
|
||||
/// the builder has an option not to add a subexpression as a
|
||||
/// block-level expression.
|
||||
///
|
||||
class AddStmtChoice {
|
||||
public:
|
||||
enum Kind { NotAlwaysAdd = 0, AlwaysAdd = 1 };
|
||||
|
@ -168,23 +199,24 @@ private:
|
|||
///
|
||||
class LocalScope {
|
||||
public:
|
||||
typedef BumpVector<VarDecl*> AutomaticVarsTy;
|
||||
friend class const_iterator;
|
||||
|
||||
using AutomaticVarsTy = BumpVector<VarDecl *>;
|
||||
|
||||
/// const_iterator - Iterates local scope backwards and jumps to previous
|
||||
/// scope on reaching the beginning of currently iterated scope.
|
||||
class const_iterator {
|
||||
const LocalScope* Scope;
|
||||
const LocalScope* Scope = nullptr;
|
||||
|
||||
/// VarIter is guaranteed to be greater then 0 for every valid iterator.
|
||||
/// Invalid iterator (with null Scope) has VarIter equal to 0.
|
||||
unsigned VarIter;
|
||||
unsigned VarIter = 0;
|
||||
|
||||
public:
|
||||
/// Create invalid iterator. Dereferencing invalid iterator is not allowed.
|
||||
/// Incrementing invalid iterator is allowed and will result in invalid
|
||||
/// iterator.
|
||||
const_iterator()
|
||||
: Scope(nullptr), VarIter(0) {}
|
||||
const_iterator() = default;
|
||||
|
||||
/// Create valid iterator. In case when S.Prev is an invalid iterator and
|
||||
/// I is equal to 0, this will create invalid iterator.
|
||||
|
@ -197,8 +229,8 @@ public:
|
|||
}
|
||||
|
||||
VarDecl *const* operator->() const {
|
||||
assert (Scope && "Dereferencing invalid iterator is not allowed");
|
||||
assert (VarIter != 0 && "Iterator has invalid value of VarIter member");
|
||||
assert(Scope && "Dereferencing invalid iterator is not allowed");
|
||||
assert(VarIter != 0 && "Iterator has invalid value of VarIter member");
|
||||
return &Scope->Vars[VarIter - 1];
|
||||
}
|
||||
VarDecl *operator*() const {
|
||||
|
@ -209,7 +241,7 @@ public:
|
|||
if (!Scope)
|
||||
return *this;
|
||||
|
||||
assert (VarIter != 0 && "Iterator has invalid value of VarIter member");
|
||||
assert(VarIter != 0 && "Iterator has invalid value of VarIter member");
|
||||
--VarIter;
|
||||
if (VarIter == 0)
|
||||
*this = Scope->Prev;
|
||||
|
@ -236,13 +268,12 @@ public:
|
|||
const_iterator shared_parent(const_iterator L);
|
||||
};
|
||||
|
||||
friend class const_iterator;
|
||||
|
||||
private:
|
||||
BumpVectorContext ctx;
|
||||
|
||||
/// Automatic variables in order of declaration.
|
||||
AutomaticVarsTy Vars;
|
||||
|
||||
/// Iterator to variable in previous scope that was declared just before
|
||||
/// begin of this scope.
|
||||
const_iterator Prev;
|
||||
|
@ -260,6 +291,8 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
/// distance - Calculates distance from this to L. L must be reachable from this
|
||||
/// (with use of ++ operator). Cost of calculating the distance is linear w.r.t.
|
||||
/// number of scopes between this and L.
|
||||
|
@ -267,8 +300,8 @@ int LocalScope::const_iterator::distance(LocalScope::const_iterator L) {
|
|||
int D = 0;
|
||||
const_iterator F = *this;
|
||||
while (F.Scope != L.Scope) {
|
||||
assert (F != const_iterator()
|
||||
&& "L iterator is not reachable from F iterator.");
|
||||
assert(F != const_iterator() &&
|
||||
"L iterator is not reachable from F iterator.");
|
||||
D += F.VarIter;
|
||||
F = F.Scope->Prev;
|
||||
}
|
||||
|
@ -300,16 +333,18 @@ LocalScope::const_iterator::shared_parent(LocalScope::const_iterator L) {
|
|||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/// Structure for specifying position in CFG during its build process. It
|
||||
/// consists of CFGBlock that specifies position in CFG and
|
||||
/// LocalScope::const_iterator that specifies position in LocalScope graph.
|
||||
struct BlockScopePosPair {
|
||||
BlockScopePosPair() : block(nullptr) {}
|
||||
CFGBlock *block = nullptr;
|
||||
LocalScope::const_iterator scopePosition;
|
||||
|
||||
BlockScopePosPair() = default;
|
||||
BlockScopePosPair(CFGBlock *b, LocalScope::const_iterator scopePos)
|
||||
: block(b), scopePosition(scopePos) {}
|
||||
|
||||
CFGBlock *block;
|
||||
LocalScope::const_iterator scopePosition;
|
||||
};
|
||||
|
||||
/// TryResult - a class representing a variant over the values
|
||||
|
@ -317,37 +352,46 @@ struct BlockScopePosPair {
|
|||
/// and is used by the CFGBuilder to decide if a branch condition
|
||||
/// can be decided up front during CFG construction.
|
||||
class TryResult {
|
||||
int X;
|
||||
int X = -1;
|
||||
|
||||
public:
|
||||
TryResult() = default;
|
||||
TryResult(bool b) : X(b ? 1 : 0) {}
|
||||
TryResult() : X(-1) {}
|
||||
|
||||
bool isTrue() const { return X == 1; }
|
||||
bool isFalse() const { return X == 0; }
|
||||
bool isKnown() const { return X >= 0; }
|
||||
|
||||
void negate() {
|
||||
assert(isKnown());
|
||||
X ^= 0x1;
|
||||
}
|
||||
};
|
||||
|
||||
TryResult bothKnownTrue(TryResult R1, TryResult R2) {
|
||||
} // namespace
|
||||
|
||||
static TryResult bothKnownTrue(TryResult R1, TryResult R2) {
|
||||
if (!R1.isKnown() || !R2.isKnown())
|
||||
return TryResult();
|
||||
return TryResult(R1.isTrue() && R2.isTrue());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class reverse_children {
|
||||
llvm::SmallVector<Stmt *, 12> childrenBuf;
|
||||
ArrayRef<Stmt*> children;
|
||||
ArrayRef<Stmt *> children;
|
||||
|
||||
public:
|
||||
reverse_children(Stmt *S);
|
||||
|
||||
typedef ArrayRef<Stmt*>::reverse_iterator iterator;
|
||||
using iterator = ArrayRef<Stmt *>::reverse_iterator;
|
||||
|
||||
iterator begin() const { return children.rbegin(); }
|
||||
iterator end() const { return children.rend(); }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
reverse_children::reverse_children(Stmt *S) {
|
||||
if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
|
||||
|
@ -374,6 +418,8 @@ reverse_children::reverse_children(Stmt *S) {
|
|||
children = childrenBuf;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/// CFGBuilder - This class implements CFG construction from an AST.
|
||||
/// The builder is stateful: an instance of the builder should be used to only
|
||||
/// construct a single CFG.
|
||||
|
@ -387,65 +433,65 @@ reverse_children::reverse_children(Stmt *S) {
|
|||
/// the AST in reverse order so that the successor of a basic block is
|
||||
/// constructed prior to its predecessor. This allows us to nicely capture
|
||||
/// implicit fall-throughs without extra basic blocks.
|
||||
///
|
||||
class CFGBuilder {
|
||||
typedef BlockScopePosPair JumpTarget;
|
||||
typedef BlockScopePosPair JumpSource;
|
||||
using JumpTarget = BlockScopePosPair;
|
||||
using JumpSource = BlockScopePosPair;
|
||||
|
||||
ASTContext *Context;
|
||||
std::unique_ptr<CFG> cfg;
|
||||
|
||||
CFGBlock *Block; // Current block.
|
||||
CFGBlock *Succ; // Block after the current block.
|
||||
// Current block.
|
||||
CFGBlock *Block = nullptr;
|
||||
|
||||
// Block after the current block.
|
||||
CFGBlock *Succ = nullptr;
|
||||
|
||||
JumpTarget ContinueJumpTarget;
|
||||
JumpTarget BreakJumpTarget;
|
||||
JumpTarget SEHLeaveJumpTarget;
|
||||
CFGBlock *SwitchTerminatedBlock;
|
||||
CFGBlock *DefaultCaseBlock;
|
||||
CFGBlock *SwitchTerminatedBlock = nullptr;
|
||||
CFGBlock *DefaultCaseBlock = nullptr;
|
||||
|
||||
// This can point either to a try or a __try block. The frontend forbids
|
||||
// mixing both kinds in one function, so having one for both is enough.
|
||||
CFGBlock *TryTerminatedBlock;
|
||||
CFGBlock *TryTerminatedBlock = nullptr;
|
||||
|
||||
// Current position in local scope.
|
||||
LocalScope::const_iterator ScopePos;
|
||||
|
||||
// LabelMap records the mapping from Label expressions to their jump targets.
|
||||
typedef llvm::DenseMap<LabelDecl*, JumpTarget> LabelMapTy;
|
||||
using LabelMapTy = llvm::DenseMap<LabelDecl *, JumpTarget>;
|
||||
LabelMapTy LabelMap;
|
||||
|
||||
// A list of blocks that end with a "goto" that must be backpatched to their
|
||||
// resolved targets upon completion of CFG construction.
|
||||
typedef std::vector<JumpSource> BackpatchBlocksTy;
|
||||
using BackpatchBlocksTy = std::vector<JumpSource>;
|
||||
BackpatchBlocksTy BackpatchBlocks;
|
||||
|
||||
// A list of labels whose address has been taken (for indirect gotos).
|
||||
typedef llvm::SmallSetVector<LabelDecl*, 8> LabelSetTy;
|
||||
using LabelSetTy = llvm::SmallSetVector<LabelDecl *, 8>;
|
||||
LabelSetTy AddressTakenLabels;
|
||||
|
||||
bool badCFG;
|
||||
bool badCFG = false;
|
||||
const CFG::BuildOptions &BuildOpts;
|
||||
|
||||
// State to track for building switch statements.
|
||||
bool switchExclusivelyCovered;
|
||||
Expr::EvalResult *switchCond;
|
||||
bool switchExclusivelyCovered = false;
|
||||
Expr::EvalResult *switchCond = nullptr;
|
||||
|
||||
CFG::BuildOptions::ForcedBlkExprs::value_type *cachedEntry;
|
||||
const Stmt *lastLookup;
|
||||
CFG::BuildOptions::ForcedBlkExprs::value_type *cachedEntry = nullptr;
|
||||
const Stmt *lastLookup = nullptr;
|
||||
|
||||
// Caches boolean evaluations of expressions to avoid multiple re-evaluations
|
||||
// during construction of branches for chained logical operators.
|
||||
typedef llvm::DenseMap<Expr *, TryResult> CachedBoolEvalsTy;
|
||||
using CachedBoolEvalsTy = llvm::DenseMap<Expr *, TryResult>;
|
||||
CachedBoolEvalsTy CachedBoolEvals;
|
||||
|
||||
public:
|
||||
explicit CFGBuilder(ASTContext *astContext,
|
||||
const CFG::BuildOptions &buildOpts)
|
||||
: Context(astContext), cfg(new CFG()), // crew a new CFG
|
||||
Block(nullptr), Succ(nullptr), SwitchTerminatedBlock(nullptr),
|
||||
DefaultCaseBlock(nullptr), TryTerminatedBlock(nullptr), badCFG(false),
|
||||
BuildOpts(buildOpts), switchExclusivelyCovered(false),
|
||||
switchCond(nullptr), cachedEntry(nullptr), lastLookup(nullptr) {}
|
||||
BuildOpts(buildOpts) {}
|
||||
|
||||
// buildCFG - Used by external clients to construct the CFG.
|
||||
std::unique_ptr<CFG> buildCFG(const Decl *D, Stmt *Statement);
|
||||
|
@ -549,13 +595,9 @@ private:
|
|||
/// if the CXXBindTemporaryExpr was marked executed, and otherwise
|
||||
/// branches to the stored successor.
|
||||
struct TempDtorContext {
|
||||
TempDtorContext()
|
||||
: IsConditional(false), KnownExecuted(true), Succ(nullptr),
|
||||
TerminatorExpr(nullptr) {}
|
||||
|
||||
TempDtorContext() = default;
|
||||
TempDtorContext(TryResult KnownExecuted)
|
||||
: IsConditional(true), KnownExecuted(KnownExecuted), Succ(nullptr),
|
||||
TerminatorExpr(nullptr) {}
|
||||
: IsConditional(true), KnownExecuted(KnownExecuted) {}
|
||||
|
||||
/// Returns whether we need to start a new branch for a temporary destructor
|
||||
/// call. This is the case when the temporary destructor is
|
||||
|
@ -574,10 +616,10 @@ private:
|
|||
TerminatorExpr = E;
|
||||
}
|
||||
|
||||
const bool IsConditional;
|
||||
const TryResult KnownExecuted;
|
||||
CFGBlock *Succ;
|
||||
CXXBindTemporaryExpr *TerminatorExpr;
|
||||
const bool IsConditional = false;
|
||||
const TryResult KnownExecuted = true;
|
||||
CFGBlock *Succ = nullptr;
|
||||
CXXBindTemporaryExpr *TerminatorExpr = nullptr;
|
||||
};
|
||||
|
||||
// Visitors to walk an AST and generate destructors of temporaries in
|
||||
|
@ -608,6 +650,7 @@ private:
|
|||
CFGBlock *addStmt(Stmt *S) {
|
||||
return Visit(S, AddStmtChoice::AlwaysAdd);
|
||||
}
|
||||
|
||||
CFGBlock *addInitializer(CXXCtorInitializer *I);
|
||||
void addLoopExit(const Stmt *LoopStmt);
|
||||
void addAutomaticObjDtors(LocalScope::const_iterator B,
|
||||
|
@ -629,6 +672,7 @@ private:
|
|||
void addLocalScopeAndDtors(Stmt *S);
|
||||
|
||||
// Interface to CFGBlock - adding CFGElements.
|
||||
|
||||
void appendStmt(CFGBlock *B, const Stmt *S) {
|
||||
if (alwaysAdd(S) && cachedEntry)
|
||||
cachedEntry->second = B;
|
||||
|
@ -637,21 +681,27 @@ private:
|
|||
assert(!isa<Expr>(S) || cast<Expr>(S)->IgnoreParens() == S);
|
||||
B->appendStmt(const_cast<Stmt*>(S), cfg->getBumpVectorContext());
|
||||
}
|
||||
|
||||
void appendInitializer(CFGBlock *B, CXXCtorInitializer *I) {
|
||||
B->appendInitializer(I, cfg->getBumpVectorContext());
|
||||
}
|
||||
|
||||
void appendNewAllocator(CFGBlock *B, CXXNewExpr *NE) {
|
||||
B->appendNewAllocator(NE, cfg->getBumpVectorContext());
|
||||
}
|
||||
|
||||
void appendBaseDtor(CFGBlock *B, const CXXBaseSpecifier *BS) {
|
||||
B->appendBaseDtor(BS, cfg->getBumpVectorContext());
|
||||
}
|
||||
|
||||
void appendMemberDtor(CFGBlock *B, FieldDecl *FD) {
|
||||
B->appendMemberDtor(FD, cfg->getBumpVectorContext());
|
||||
}
|
||||
|
||||
void appendTemporaryDtor(CFGBlock *B, CXXBindTemporaryExpr *E) {
|
||||
B->appendTemporaryDtor(E, cfg->getBumpVectorContext());
|
||||
}
|
||||
|
||||
void appendAutomaticObjDtor(CFGBlock *B, VarDecl *VD, Stmt *S) {
|
||||
B->appendAutomaticObjDtor(VD, S, cfg->getBumpVectorContext());
|
||||
}
|
||||
|
@ -811,10 +861,10 @@ private:
|
|||
const BinaryOperator *RHS =
|
||||
dyn_cast<BinaryOperator>(B->getRHS()->IgnoreParens());
|
||||
if (!LHS || !RHS)
|
||||
return TryResult();
|
||||
return {};
|
||||
|
||||
if (!LHS->isComparisonOp() || !RHS->isComparisonOp())
|
||||
return TryResult();
|
||||
return {};
|
||||
|
||||
const DeclRefExpr *Decl1;
|
||||
const Expr *Expr1;
|
||||
|
@ -822,7 +872,7 @@ private:
|
|||
std::tie(Decl1, BO1, Expr1) = tryNormalizeBinaryOperator(LHS);
|
||||
|
||||
if (!Decl1 || !Expr1)
|
||||
return TryResult();
|
||||
return {};
|
||||
|
||||
const DeclRefExpr *Decl2;
|
||||
const Expr *Expr2;
|
||||
|
@ -830,26 +880,26 @@ private:
|
|||
std::tie(Decl2, BO2, Expr2) = tryNormalizeBinaryOperator(RHS);
|
||||
|
||||
if (!Decl2 || !Expr2)
|
||||
return TryResult();
|
||||
return {};
|
||||
|
||||
// Check that it is the same variable on both sides.
|
||||
if (Decl1->getDecl() != Decl2->getDecl())
|
||||
return TryResult();
|
||||
return {};
|
||||
|
||||
// Make sure the user's intent is clear (e.g. they're comparing against two
|
||||
// int literals, or two things from the same enum)
|
||||
if (!areExprTypesCompatible(Expr1, Expr2))
|
||||
return TryResult();
|
||||
return {};
|
||||
|
||||
llvm::APSInt L1, L2;
|
||||
|
||||
if (!Expr1->EvaluateAsInt(L1, *Context) ||
|
||||
!Expr2->EvaluateAsInt(L2, *Context))
|
||||
return TryResult();
|
||||
return {};
|
||||
|
||||
// Can't compare signed with unsigned or with different bit width.
|
||||
if (L1.isSigned() != L2.isSigned() || L1.getBitWidth() != L2.getBitWidth())
|
||||
return TryResult();
|
||||
return {};
|
||||
|
||||
// Values that will be used to determine if result of logical
|
||||
// operator is always true/false
|
||||
|
@ -880,7 +930,7 @@ private:
|
|||
Res2 = analyzeLogicOperatorCondition(BO2, Value, L2);
|
||||
|
||||
if (!Res1.isKnown() || !Res2.isKnown())
|
||||
return TryResult();
|
||||
return {};
|
||||
|
||||
if (B->getOpcode() == BO_LAnd) {
|
||||
AlwaysTrue &= (Res1.isTrue() && Res2.isTrue());
|
||||
|
@ -896,7 +946,7 @@ private:
|
|||
BuildOpts.Observer->compareAlwaysTrue(B, AlwaysTrue);
|
||||
return TryResult(AlwaysTrue);
|
||||
}
|
||||
return TryResult();
|
||||
return {};
|
||||
}
|
||||
|
||||
/// Try and evaluate an expression to an integer constant.
|
||||
|
@ -913,7 +963,7 @@ private:
|
|||
TryResult tryEvaluateBool(Expr *S) {
|
||||
if (!BuildOpts.PruneTriviallyFalseEdges ||
|
||||
S->isTypeDependent() || S->isValueDependent())
|
||||
return TryResult();
|
||||
return {};
|
||||
|
||||
if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) {
|
||||
if (Bop->isLogicalOp()) {
|
||||
|
@ -988,7 +1038,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
return TryResult();
|
||||
return {};
|
||||
} else if (Bop->isEqualityOp()) {
|
||||
TryResult BopRes = checkIncorrectEqualityOperator(Bop);
|
||||
if (BopRes.isKnown())
|
||||
|
@ -1004,12 +1054,14 @@ private:
|
|||
if (E->EvaluateAsBooleanCondition(Result, *Context))
|
||||
return Result;
|
||||
|
||||
return TryResult();
|
||||
return {};
|
||||
}
|
||||
|
||||
bool hasTrivialDestructor(VarDecl *VD);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder,
|
||||
const Stmt *stmt) const {
|
||||
return builder.alwaysAdd(stmt) || kind == AlwaysAdd;
|
||||
|
@ -1131,7 +1183,6 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
|
|||
if (CFGBlock *B = cfg->getIndirectGotoBlock())
|
||||
for (LabelSetTy::iterator I = AddressTakenLabels.begin(),
|
||||
E = AddressTakenLabels.end(); I != E; ++I ) {
|
||||
|
||||
// Lookup the target block.
|
||||
LabelMapTy::iterator LI = LabelMap.find(*I);
|
||||
|
||||
|
@ -1265,7 +1316,6 @@ static QualType getReferenceInitTemporaryType(ASTContext &Context,
|
|||
return Init->getType();
|
||||
}
|
||||
|
||||
|
||||
// TODO: Support adding LoopExit element to the CFG in case where the loop is
|
||||
// ended by ReturnStmt, GotoStmt or ThrowExpr.
|
||||
void CFGBuilder::addLoopExit(const Stmt *LoopStmt){
|
||||
|
@ -1373,8 +1423,8 @@ void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B,
|
|||
/// addImplicitDtorsForDestructor - Add implicit destructors generated for
|
||||
/// base and member objects in destructor.
|
||||
void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) {
|
||||
assert (BuildOpts.AddImplicitDtors
|
||||
&& "Can be called only when dtors should be added");
|
||||
assert(BuildOpts.AddImplicitDtors &&
|
||||
"Can be called only when dtors should be added");
|
||||
const CXXRecordDecl *RD = DD->getParent();
|
||||
|
||||
// At the end destroy virtual base objects.
|
||||
|
@ -1577,6 +1627,7 @@ void CFGBuilder::prependAutomaticObjLifetimeWithTerminator(
|
|||
for (LocalScope::const_iterator I = B; I != E; ++I)
|
||||
InsertPos = Blk->insertLifetimeEnds(InsertPos, *I, Blk->getTerminator());
|
||||
}
|
||||
|
||||
/// Visit - Walk the subtree of a statement and add extra
|
||||
/// blocks for ternary operators, &&, and ||. We also process "," and
|
||||
/// DeclStmts (which may contain nested control-flow).
|
||||
|
@ -1831,7 +1882,6 @@ CFGBuilder::VisitLogicalOperator(BinaryOperator *B,
|
|||
Stmt *Term,
|
||||
CFGBlock *TrueBlock,
|
||||
CFGBlock *FalseBlock) {
|
||||
|
||||
// Introspect the RHS. If it is a nested logical operation, we recursively
|
||||
// build the CFG using this function. Otherwise, resort to default
|
||||
// CFG construction behavior.
|
||||
|
@ -1920,7 +1970,6 @@ CFGBuilder::VisitLogicalOperator(BinaryOperator *B,
|
|||
return std::make_pair(EntryLHSBlock, ExitBlock);
|
||||
}
|
||||
|
||||
|
||||
CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
|
||||
AddStmtChoice asc) {
|
||||
// && or ||
|
||||
|
@ -1982,7 +2031,6 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
|
|||
} else
|
||||
badCFG = true;
|
||||
|
||||
|
||||
return Block;
|
||||
}
|
||||
|
||||
|
@ -2106,7 +2154,6 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
|
|||
return addStmt(C->getCond());
|
||||
}
|
||||
|
||||
|
||||
CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) {
|
||||
LocalScope::const_iterator scopeBeginPos = ScopePos;
|
||||
addLocalScopeForStmt(C);
|
||||
|
@ -2457,7 +2504,6 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
|
|||
return LastBlock;
|
||||
}
|
||||
|
||||
|
||||
CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) {
|
||||
// If we were in the middle of a block we stop processing that block.
|
||||
//
|
||||
|
@ -2815,7 +2861,6 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
|
|||
// false branch).
|
||||
addSuccessor(ExitConditionBlock,
|
||||
KnownVal.isTrue() ? nullptr : LoopSuccessor);
|
||||
|
||||
} while (false);
|
||||
|
||||
// Link up the loop-back block to the entry condition block.
|
||||
|
@ -2877,7 +2922,6 @@ CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
|
|||
// the same with newVariable replaced with existingItem; the binding works
|
||||
// the same except that for one ObjCForCollectionStmt::getElement() returns
|
||||
// a DeclStmt and the other returns a DeclRefExpr.
|
||||
//
|
||||
|
||||
CFGBlock *LoopSuccessor = nullptr;
|
||||
|
||||
|
@ -3129,7 +3173,6 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
|
|||
// false branch).
|
||||
addSuccessor(ExitConditionBlock,
|
||||
KnownVal.isTrue() ? nullptr : LoopSuccessor);
|
||||
|
||||
} while(false);
|
||||
|
||||
// Link up the loop-back block to the entry condition block.
|
||||
|
@ -3144,7 +3187,6 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
|
|||
return EntryConditionBlock;
|
||||
}
|
||||
|
||||
|
||||
CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
|
||||
// FIXME: For now we pretend that @catch and the code it contains does not
|
||||
// exit.
|
||||
|
@ -3317,7 +3359,6 @@ CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *C) {
|
|||
|
||||
CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
|
||||
AddStmtChoice asc) {
|
||||
|
||||
if (asc.alwaysAdd(*this, E)) {
|
||||
autoCreateBlock();
|
||||
appendStmt(Block, E);
|
||||
|
@ -3838,7 +3879,6 @@ CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *C,
|
|||
|
||||
CFGBlock *CFGBuilder::VisitCXXNewExpr(CXXNewExpr *NE,
|
||||
AddStmtChoice asc) {
|
||||
|
||||
autoCreateBlock();
|
||||
appendStmt(Block, NE);
|
||||
|
||||
|
@ -4141,8 +4181,6 @@ CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
|
|||
return Block;
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
/// createBlock - Constructs and adds a new CFGBlock to the CFG. The block has
|
||||
/// no successors or predecessors. If this is the first block created in the
|
||||
/// CFG, it is automatically set to be the Entry and Exit of the CFG.
|
||||
|
@ -4217,7 +4255,6 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
|
|||
}
|
||||
case CFGElement::BaseDtor:
|
||||
case CFGElement::MemberDtor:
|
||||
|
||||
// Not yet supported.
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -4235,14 +4272,14 @@ bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const {
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
CFGBlock::AdjacentBlock::AdjacentBlock(CFGBlock *B, bool IsReachable)
|
||||
: ReachableBlock(IsReachable ? B : nullptr),
|
||||
UnreachableBlock(!IsReachable ? B : nullptr,
|
||||
B && IsReachable ? AB_Normal : AB_Unreachable) {}
|
||||
: ReachableBlock(IsReachable ? B : nullptr),
|
||||
UnreachableBlock(!IsReachable ? B : nullptr,
|
||||
B && IsReachable ? AB_Normal : AB_Unreachable) {}
|
||||
|
||||
CFGBlock::AdjacentBlock::AdjacentBlock(CFGBlock *B, CFGBlock *AlternateBlock)
|
||||
: ReachableBlock(B),
|
||||
UnreachableBlock(B == AlternateBlock ? nullptr : AlternateBlock,
|
||||
B == AlternateBlock ? AB_Alternate : AB_Normal) {}
|
||||
: ReachableBlock(B),
|
||||
UnreachableBlock(B == AlternateBlock ? nullptr : AlternateBlock,
|
||||
B == AlternateBlock ? AB_Alternate : AB_Normal) {}
|
||||
|
||||
void CFGBlock::addSuccessor(AdjacentBlock Succ,
|
||||
BumpVectorContext &C) {
|
||||
|
@ -4257,7 +4294,6 @@ void CFGBlock::addSuccessor(AdjacentBlock Succ,
|
|||
|
||||
bool CFGBlock::FilterEdge(const CFGBlock::FilterOptions &F,
|
||||
const CFGBlock *From, const CFGBlock *To) {
|
||||
|
||||
if (F.IgnoreNullPredecessors && !From)
|
||||
return true;
|
||||
|
||||
|
@ -4284,18 +4320,18 @@ bool CFGBlock::FilterEdge(const CFGBlock::FilterOptions &F,
|
|||
namespace {
|
||||
|
||||
class StmtPrinterHelper : public PrinterHelper {
|
||||
typedef llvm::DenseMap<const Stmt*,std::pair<unsigned,unsigned> > StmtMapTy;
|
||||
typedef llvm::DenseMap<const Decl*,std::pair<unsigned,unsigned> > DeclMapTy;
|
||||
using StmtMapTy = llvm::DenseMap<const Stmt *, std::pair<unsigned, unsigned>>;
|
||||
using DeclMapTy = llvm::DenseMap<const Decl *, std::pair<unsigned, unsigned>>;
|
||||
|
||||
StmtMapTy StmtMap;
|
||||
DeclMapTy DeclMap;
|
||||
signed currentBlock;
|
||||
unsigned currStmt;
|
||||
signed currentBlock = 0;
|
||||
unsigned currStmt = 0;
|
||||
const LangOptions &LangOpts;
|
||||
public:
|
||||
|
||||
public:
|
||||
StmtPrinterHelper(const CFG* cfg, const LangOptions &LO)
|
||||
: currentBlock(0), currStmt(0), LangOpts(LO)
|
||||
{
|
||||
: LangOpts(LO) {
|
||||
for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) {
|
||||
unsigned j = 1;
|
||||
for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ;
|
||||
|
@ -4350,7 +4386,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
~StmtPrinterHelper() override {}
|
||||
~StmtPrinterHelper() override = default;
|
||||
|
||||
const LangOptions &getLangOpts() const { return LangOpts; }
|
||||
void setBlockID(signed i) { currentBlock = i; }
|
||||
|
@ -4386,20 +4422,17 @@ public:
|
|||
return true;
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
namespace {
|
||||
class CFGBlockTerminatorPrint
|
||||
: public StmtVisitor<CFGBlockTerminatorPrint,void> {
|
||||
|
||||
: public StmtVisitor<CFGBlockTerminatorPrint,void> {
|
||||
raw_ostream &OS;
|
||||
StmtPrinterHelper* Helper;
|
||||
PrintingPolicy Policy;
|
||||
|
||||
public:
|
||||
CFGBlockTerminatorPrint(raw_ostream &os, StmtPrinterHelper* helper,
|
||||
const PrintingPolicy &Policy)
|
||||
: OS(os), Helper(helper), Policy(Policy) {
|
||||
: OS(os), Helper(helper), Policy(Policy) {
|
||||
this->Policy.IncludeNewlines = false;
|
||||
}
|
||||
|
||||
|
@ -4508,7 +4541,8 @@ public:
|
|||
Visit(T.getStmt());
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
} // namespace
|
||||
|
||||
static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
|
||||
const CFGElement &E) {
|
||||
|
@ -4558,7 +4592,6 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
|
|||
// Expressions need a newline.
|
||||
if (isa<Expr>(S))
|
||||
OS << '\n';
|
||||
|
||||
} else if (Optional<CFGInitializer> IE = E.getAs<CFGInitializer>()) {
|
||||
const CXXCtorInitializer *I = IE->getInitializer();
|
||||
if (I->isBaseInitializer())
|
||||
|
@ -4577,7 +4610,6 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
|
|||
else if (I->isDelegatingInitializer())
|
||||
OS << " (Delegating initializer)\n";
|
||||
else OS << " (Member initializer)\n";
|
||||
|
||||
} else if (Optional<CFGAutomaticObjDtor> DE =
|
||||
E.getAs<CFGAutomaticObjDtor>()) {
|
||||
const VarDecl *VD = DE->getVarDecl();
|
||||
|
@ -4590,13 +4622,11 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
|
|||
|
||||
OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()";
|
||||
OS << " (Implicit destructor)\n";
|
||||
|
||||
} else if (Optional<CFGLifetimeEnds> DE = E.getAs<CFGLifetimeEnds>()) {
|
||||
const VarDecl *VD = DE->getVarDecl();
|
||||
Helper.handleDecl(VD, OS);
|
||||
|
||||
OS << " (Lifetime ends)\n";
|
||||
|
||||
} else if (Optional<CFGLoopExit> LE = E.getAs<CFGLoopExit>()) {
|
||||
const Stmt *LoopStmt = LE->getLoopStmt();
|
||||
OS << LoopStmt->getStmtClassName() << " (LoopExit)\n";
|
||||
|
@ -4618,14 +4648,12 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
|
|||
const CXXBaseSpecifier *BS = BE->getBaseSpecifier();
|
||||
OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()";
|
||||
OS << " (Base object destructor)\n";
|
||||
|
||||
} else if (Optional<CFGMemberDtor> ME = E.getAs<CFGMemberDtor>()) {
|
||||
const FieldDecl *FD = ME->getFieldDecl();
|
||||
const Type *T = FD->getType()->getBaseElementTypeUnsafe();
|
||||
OS << "this->" << FD->getName();
|
||||
OS << ".~" << T->getAsCXXRecordDecl()->getName() << "()";
|
||||
OS << " (Member object destructor)\n";
|
||||
|
||||
} else if (Optional<CFGTemporaryDtor> TE = E.getAs<CFGTemporaryDtor>()) {
|
||||
const CXXBindTemporaryExpr *BT = TE->getBindTemporaryExpr();
|
||||
OS << "~";
|
||||
|
@ -4638,7 +4666,6 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
|
|||
const CFGBlock &B,
|
||||
StmtPrinterHelper &Helper, bool print_edges,
|
||||
bool ShowColors) {
|
||||
|
||||
Helper.setBlockID(B.getBlockID());
|
||||
|
||||
// Print the header.
|
||||
|
@ -4663,7 +4690,6 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
|
|||
|
||||
// Print the label of this block.
|
||||
if (Stmt *Label = const_cast<Stmt*>(B.getLabel())) {
|
||||
|
||||
if (print_edges)
|
||||
OS << " ";
|
||||
|
||||
|
@ -4705,7 +4731,6 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
|
|||
|
||||
for (CFGBlock::const_iterator I = B.begin(), E = B.end() ;
|
||||
I != E ; ++I, ++j ) {
|
||||
|
||||
// Print the statement # in the basic block and the statement itself.
|
||||
if (print_edges)
|
||||
OS << " ";
|
||||
|
@ -4752,7 +4777,6 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
|
|||
|
||||
for (CFGBlock::const_pred_iterator I = B.pred_begin(), E = B.pred_end();
|
||||
I != E; ++I, ++i) {
|
||||
|
||||
if (i % 10 == 8)
|
||||
OS << "\n ";
|
||||
|
||||
|
@ -4790,7 +4814,6 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
|
|||
|
||||
for (CFGBlock::const_succ_iterator I = B.succ_begin(), E = B.succ_end();
|
||||
I != E; ++I, ++i) {
|
||||
|
||||
if (i % 10 == 8)
|
||||
OS << "\n ";
|
||||
|
||||
|
@ -4819,7 +4842,6 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// dump - A simple pretty printer of a CFG that outputs to stderr.
|
||||
void CFG::dump(const LangOptions &LO, bool ShowColors) const {
|
||||
print(llvm::errs(), LO, ShowColors);
|
||||
|
@ -4942,7 +4964,6 @@ Stmt *CFGBlock::getTerminatorCondition(bool StripParens) {
|
|||
// CFG Graphviz Visualization
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
static StmtPrinterHelper* GraphHelper;
|
||||
#endif
|
||||
|
@ -4957,13 +4978,12 @@ void CFG::viewCFG(const LangOptions &LO) const {
|
|||
}
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template<>
|
||||
struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits {
|
||||
|
||||
DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
|
||||
DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
|
||||
|
||||
static std::string getNodeLabel(const CFGBlock *Node, const CFG* Graph) {
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::string OutSStr;
|
||||
llvm::raw_string_ostream Out(OutSStr);
|
||||
|
@ -4981,8 +5001,9 @@ struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits {
|
|||
|
||||
return OutStr;
|
||||
#else
|
||||
return "";
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
} // namespace llvm
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//== CallGraph.cpp - AST-based Call graph ----------------------*- C++ -*--==//
|
||||
//===- CallGraph.cpp - AST-based Call graph -------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -10,13 +10,28 @@
|
|||
// This file defines the AST-based CallGraph.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/CallGraph.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/DOTGraphTraits.h"
|
||||
#include "llvm/Support/GraphWriter.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
|
@ -26,6 +41,7 @@ STATISTIC(NumObjCCallEdges, "Number of Objective-C method call edges");
|
|||
STATISTIC(NumBlockCallEdges, "Number of block call edges");
|
||||
|
||||
namespace {
|
||||
|
||||
/// A helper class, which walks the AST and locates all the call sites in the
|
||||
/// given function body.
|
||||
class CGBuilder : public StmtVisitor<CGBuilder> {
|
||||
|
@ -33,8 +49,7 @@ class CGBuilder : public StmtVisitor<CGBuilder> {
|
|||
CallGraphNode *CallerNode;
|
||||
|
||||
public:
|
||||
CGBuilder(CallGraph *g, CallGraphNode *N)
|
||||
: G(g), CallerNode(N) {}
|
||||
CGBuilder(CallGraph *g, CallGraphNode *N) : G(g), CallerNode(N) {}
|
||||
|
||||
void VisitStmt(Stmt *S) { VisitChildren(S); }
|
||||
|
||||
|
@ -90,7 +105,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
} // namespace
|
||||
|
||||
void CallGraph::addNodesForBlocks(DeclContext *D) {
|
||||
if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
|
||||
|
@ -105,7 +120,7 @@ CallGraph::CallGraph() {
|
|||
Root = getOrInsertNode(nullptr);
|
||||
}
|
||||
|
||||
CallGraph::~CallGraph() {}
|
||||
CallGraph::~CallGraph() = default;
|
||||
|
||||
bool CallGraph::includeInGraph(const Decl *D) {
|
||||
assert(D);
|
||||
|
@ -164,8 +179,8 @@ void CallGraph::print(raw_ostream &OS) const {
|
|||
|
||||
// We are going to print the graph in reverse post order, partially, to make
|
||||
// sure the output is deterministic.
|
||||
llvm::ReversePostOrderTraversal<const clang::CallGraph*> RPOT(this);
|
||||
for (llvm::ReversePostOrderTraversal<const clang::CallGraph*>::rpo_iterator
|
||||
llvm::ReversePostOrderTraversal<const CallGraph *> RPOT(this);
|
||||
for (llvm::ReversePostOrderTraversal<const CallGraph *>::rpo_iterator
|
||||
I = RPOT.begin(), E = RPOT.end(); I != E; ++I) {
|
||||
const CallGraphNode *N = *I;
|
||||
|
||||
|
@ -209,8 +224,7 @@ namespace llvm {
|
|||
|
||||
template <>
|
||||
struct DOTGraphTraits<const CallGraph*> : public DefaultDOTGraphTraits {
|
||||
|
||||
DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
|
||||
DOTGraphTraits (bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
|
||||
|
||||
static std::string getNodeLabel(const CallGraphNode *Node,
|
||||
const CallGraph *CG) {
|
||||
|
@ -222,6 +236,6 @@ struct DOTGraphTraits<const CallGraph*> : public DefaultDOTGraphTraits {
|
|||
else
|
||||
return "< >";
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace llvm
|
||||
|
|
Loading…
Reference in New Issue