[Analysis] Fix some Clang-tidy modernize and Include What You Use warnings; other minor fixes (NFC).

llvm-svn: 320091
This commit is contained in:
Eugene Zelenko 2017-12-07 21:55:09 +00:00
parent 59948666fb
commit 38c70521ff
5 changed files with 441 additions and 373 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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