Changeset View
Changeset View
Standalone View
Standalone View
include/clang/Analysis/CFG.h
Show First 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | |||||
/// CFGElement - Represents a top-level expression in a basic block. | /// CFGElement - Represents a top-level expression in a basic block. | ||||
class CFGElement { | class CFGElement { | ||||
public: | public: | ||||
enum Kind { | enum Kind { | ||||
// main kind | // main kind | ||||
Statement, | Statement, | ||||
Initializer, | Initializer, | ||||
ScopeBegin, | |||||
ScopeEnd, | |||||
NewAllocator, | NewAllocator, | ||||
LifetimeEnds, | LifetimeEnds, | ||||
// dtor kind | // dtor kind | ||||
AutomaticObjectDtor, | AutomaticObjectDtor, | ||||
DeleteDtor, | DeleteDtor, | ||||
BaseDtor, | BaseDtor, | ||||
MemberDtor, | MemberDtor, | ||||
TemporaryDtor, | TemporaryDtor, | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | public: | ||||
} | } | ||||
private: | private: | ||||
friend class CFGElement; | friend class CFGElement; | ||||
CFGNewAllocator() {} | CFGNewAllocator() {} | ||||
static bool isKind(const CFGElement &elem) { | static bool isKind(const CFGElement &elem) { | ||||
return elem.getKind() == NewAllocator; | return elem.getKind() == NewAllocator; | ||||
} | } | ||||
}; | }; | ||||
dcoughlin: Even though a lot of code doesn't follow the guidelines, LLVM style discourages duplicating the… | |||||
/// Represents the point where the lifetime of an automatic object ends | /// Represents the point where the lifetime of an automatic object ends | ||||
class CFGLifetimeEnds : public CFGElement { | class CFGLifetimeEnds : public CFGElement { | ||||
public: | public: | ||||
explicit CFGLifetimeEnds(const VarDecl *var, const Stmt *stmt) | explicit CFGLifetimeEnds(const VarDecl *var, const Stmt *stmt) | ||||
: CFGElement(LifetimeEnds, var, stmt) {} | : CFGElement(LifetimeEnds, var, stmt) {} | ||||
const VarDecl *getVarDecl() const { | const VarDecl *getVarDecl() const { | ||||
return static_cast<VarDecl *>(Data1.getPointer()); | return static_cast<VarDecl *>(Data1.getPointer()); | ||||
} | } | ||||
const Stmt *getTriggerStmt() const { | const Stmt *getTriggerStmt() const { | ||||
return static_cast<Stmt *>(Data2.getPointer()); | return static_cast<Stmt *>(Data2.getPointer()); | ||||
} | } | ||||
private: | private: | ||||
friend class CFGElement; | friend class CFGElement; | ||||
CFGLifetimeEnds() {} | CFGLifetimeEnds() {} | ||||
static bool isKind(const CFGElement &elem) { | static bool isKind(const CFGElement &elem) { | ||||
return elem.getKind() == LifetimeEnds; | return elem.getKind() == LifetimeEnds; | ||||
} | } | ||||
Same doc comment style issue here. dcoughlin: Same doc comment style issue here. | |||||
}; | }; | ||||
/// Represents beginning of a scope implicitly generated | |||||
/// by the compiler on encountering a CompoundStmt | |||||
class CFGScopeBegin : public CFGElement { | |||||
public: | |||||
CFGScopeBegin() {} | |||||
CFGScopeBegin(const Stmt *S) | |||||
: CFGElement(ScopeBegin, S) {} | |||||
// Get statement that triggered a new scope. | |||||
const Stmt *getTriggerStmt() const { | |||||
return static_cast<Stmt*>(Data1.getPointer()); | |||||
} | |||||
private: | |||||
friend class CFGElement; | |||||
static bool isKind(const CFGElement &E) { | |||||
Kind kind = E.getKind(); | |||||
return kind == ScopeBegin; | |||||
} | |||||
}; | |||||
/// Represents end of a scope implicitly generated by | |||||
/// the compiler after the last Stmt in a CompoundStmt's body | |||||
class CFGScopeEnd : public CFGElement { | |||||
public: | |||||
CFGScopeEnd() {} | |||||
CFGScopeEnd(const Stmt *TriggerStmt, const Stmt *TerminatedStmt) | |||||
: CFGElement(ScopeEnd, TriggerStmt), TerminatedStmt(TerminatedStmt) {} | |||||
// Get statement that triggered end of previously created scope. | |||||
const Stmt *getTriggerStmt() const { | |||||
return static_cast<Stmt*>(Data1.getPointer()); | |||||
} | |||||
const Stmt *getTerminatedStmt() const { | |||||
return TerminatedStmt; | |||||
} | |||||
private: | |||||
friend class CFGElement; | |||||
static bool isKind(const CFGElement &E) { | |||||
Kind kind = E.getKind(); | |||||
return kind == ScopeEnd; | |||||
} | |||||
const Stmt *TerminatedStmt; | |||||
}; | |||||
/// CFGImplicitDtor - Represents C++ object destructor implicitly generated | /// CFGImplicitDtor - Represents C++ object destructor implicitly generated | ||||
/// by compiler on various occasions. | /// by compiler on various occasions. | ||||
class CFGImplicitDtor : public CFGElement { | class CFGImplicitDtor : public CFGElement { | ||||
protected: | protected: | ||||
CFGImplicitDtor() {} | CFGImplicitDtor() {} | ||||
CFGImplicitDtor(Kind kind, const void *data1, const void *data2 = nullptr) | CFGImplicitDtor(Kind kind, const void *data1, const void *data2 = nullptr) | ||||
: CFGElement(kind, data1, data2) { | : CFGElement(kind, data1, data2) { | ||||
assert(kind >= DTOR_BEGIN && kind <= DTOR_END); | assert(kind >= DTOR_BEGIN && kind <= DTOR_END); | ||||
▲ Show 20 Lines • Show All 502 Lines • ▼ Show 20 Lines | void appendInitializer(CXXCtorInitializer *initializer, | ||||
Elements.push_back(CFGInitializer(initializer), C); | Elements.push_back(CFGInitializer(initializer), C); | ||||
} | } | ||||
void appendNewAllocator(CXXNewExpr *NE, | void appendNewAllocator(CXXNewExpr *NE, | ||||
BumpVectorContext &C) { | BumpVectorContext &C) { | ||||
Elements.push_back(CFGNewAllocator(NE), C); | Elements.push_back(CFGNewAllocator(NE), C); | ||||
} | } | ||||
void appendScopeBegin(const Stmt *S, BumpVectorContext &C) { | |||||
Elements.push_back(CFGScopeBegin(S), C); | |||||
} | |||||
void appendScopeEnd(const Stmt *TriggerStmt, const Stmt *TerminatedStmt, | |||||
BumpVectorContext &C) { | |||||
Elements.push_back(CFGScopeEnd(TriggerStmt, TerminatedStmt), C); | |||||
} | |||||
void prependScopeEnd(const Stmt *TriggerStmt, const Stmt *TerminatedStmt, | |||||
BumpVectorContext &C) { | |||||
Elements.insert(Elements.rbegin(), 1, | |||||
CFGScopeEnd(TriggerStmt, TerminatedStmt), C); | |||||
} | |||||
void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C) { | void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C) { | ||||
Elements.push_back(CFGBaseDtor(BS), C); | Elements.push_back(CFGBaseDtor(BS), C); | ||||
} | } | ||||
void appendMemberDtor(FieldDecl *FD, BumpVectorContext &C) { | void appendMemberDtor(FieldDecl *FD, BumpVectorContext &C) { | ||||
Elements.push_back(CFGMemberDtor(FD), C); | Elements.push_back(CFGMemberDtor(FD), C); | ||||
} | } | ||||
void appendTemporaryDtor(CXXBindTemporaryExpr *E, BumpVectorContext &C) { | void appendTemporaryDtor(CXXBindTemporaryExpr *E, BumpVectorContext &C) { | ||||
Elements.push_back(CFGTemporaryDtor(E), C); | Elements.push_back(CFGTemporaryDtor(E), C); | ||||
} | } | ||||
void appendAutomaticObjDtor(VarDecl *VD, Stmt *S, BumpVectorContext &C) { | void appendAutomaticObjDtor(VarDecl *VD, Stmt *S, BumpVectorContext &C) { | ||||
Elements.push_back(CFGAutomaticObjDtor(VD, S), C); | Elements.push_back(CFGAutomaticObjDtor(VD, S), C); | ||||
} | } | ||||
void appendLifetimeEnds(VarDecl *VD, Stmt *S, BumpVectorContext &C) { | void appendLifetimeEnds(VarDecl *VD, Stmt *S, BumpVectorContext &C) { | ||||
I would suggest calling this "AddScopes" to match the pluralization of the other options and propagate that name throughout the rest of the patch (e.g. "IncludeScopesInCFG", etc.). dcoughlin: I would suggest calling this "AddScopes" to match the pluralization of the other options and… | |||||
Elements.push_back(CFGLifetimeEnds(VD, S), C); | Elements.push_back(CFGLifetimeEnds(VD, S), C); | ||||
} | } | ||||
void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) { | void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) { | ||||
Elements.push_back(CFGDeleteDtor(RD, DE), C); | Elements.push_back(CFGDeleteDtor(RD, DE), C); | ||||
} | } | ||||
void removeAllSuccessors() { Succs.clear(); } | |||||
// Destructors must be inserted in reversed order. So insertion is in two | // Destructors must be inserted in reversed order. So insertion is in two | ||||
// steps. First we prepare space for some number of elements, then we insert | // steps. First we prepare space for some number of elements, then we insert | ||||
// the elements beginning at the last position in prepared space. | // the elements beginning at the last position in prepared space. | ||||
iterator beginAutomaticObjDtorsInsert(iterator I, size_t Cnt, | iterator beginAutomaticObjDtorsInsert(iterator I, size_t Cnt, | ||||
BumpVectorContext &C) { | BumpVectorContext &C) { | ||||
return iterator(Elements.insert(I.base(), Cnt, | return iterator(Elements.insert(I.base(), Cnt, | ||||
CFGAutomaticObjDtor(nullptr, nullptr), C)); | CFGAutomaticObjDtor(nullptr, nullptr), C)); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | public: | ||||
ForcedBlkExprs **forcedBlkExprs; | ForcedBlkExprs **forcedBlkExprs; | ||||
CFGCallback *Observer; | CFGCallback *Observer; | ||||
bool PruneTriviallyFalseEdges; | bool PruneTriviallyFalseEdges; | ||||
bool AddEHEdges; | bool AddEHEdges; | ||||
bool AddInitializers; | bool AddInitializers; | ||||
bool AddImplicitDtors; | bool AddImplicitDtors; | ||||
bool AddLifetime; | bool AddLifetime; | ||||
bool AddTemporaryDtors; | bool AddTemporaryDtors; | ||||
bool AddScopes; | |||||
bool AddStaticInitBranches; | bool AddStaticInitBranches; | ||||
bool AddCXXNewAllocator; | bool AddCXXNewAllocator; | ||||
bool AddCXXDefaultInitExprInCtors; | bool AddCXXDefaultInitExprInCtors; | ||||
bool alwaysAdd(const Stmt *stmt) const { | bool alwaysAdd(const Stmt *stmt) const { | ||||
return alwaysAddMask[stmt->getStmtClass()]; | return alwaysAddMask[stmt->getStmtClass()]; | ||||
} | } | ||||
BuildOptions &setAlwaysAdd(Stmt::StmtClass stmtClass, bool val = true) { | BuildOptions &setAlwaysAdd(Stmt::StmtClass stmtClass, bool val = true) { | ||||
alwaysAddMask[stmtClass] = val; | alwaysAddMask[stmtClass] = val; | ||||
return *this; | return *this; | ||||
} | } | ||||
BuildOptions &setAllAlwaysAdd() { | BuildOptions &setAllAlwaysAdd() { | ||||
alwaysAddMask.set(); | alwaysAddMask.set(); | ||||
return *this; | return *this; | ||||
} | } | ||||
BuildOptions() | BuildOptions() | ||||
: forcedBlkExprs(nullptr), Observer(nullptr), | : forcedBlkExprs(nullptr), Observer(nullptr), | ||||
PruneTriviallyFalseEdges(true), | PruneTriviallyFalseEdges(true), | ||||
AddEHEdges(false), | AddEHEdges(false), | ||||
AddInitializers(false), AddImplicitDtors(false), | AddInitializers(false), AddImplicitDtors(false), | ||||
AddLifetime(false), | AddLifetime(false), | ||||
AddTemporaryDtors(false), AddStaticInitBranches(false), | AddTemporaryDtors(false), AddScopes(false), | ||||
AddStaticInitBranches(false), | |||||
AddCXXNewAllocator(false), AddCXXDefaultInitExprInCtors(false) {} | AddCXXNewAllocator(false), AddCXXDefaultInitExprInCtors(false) {} | ||||
}; | }; | ||||
/// buildCFG - Builds a CFG from an AST. | /// buildCFG - Builds a CFG from an AST. | ||||
static std::unique_ptr<CFG> buildCFG(const Decl *D, Stmt *AST, ASTContext *C, | static std::unique_ptr<CFG> buildCFG(const Decl *D, Stmt *AST, ASTContext *C, | ||||
const BuildOptions &BO); | const BuildOptions &BO); | ||||
/// createBlock - Create a new block in the CFG. The CFG owns the block; | /// createBlock - Create a new block in the CFG. The CFG owns the block; | ||||
▲ Show 20 Lines • Show All 288 Lines • Show Last 20 Lines |
Even though a lot of code doesn't follow the guidelines, LLVM style discourages duplicating the function or class name at the beginning of the comment. (See http://llvm.org/docs/CodingStandards.html#doxygen-use-in-documentation-comments)