idx::TranslationUnit *TU;
// AnalysisContext owns the following data.
- CFG *cfg;
- bool builtCFG;
+ CFG *cfg, *completeCFG;
+ bool builtCFG, builtCompleteCFG;
LiveVariables *liveness;
ParentMap *PM;
llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars;
public:
AnalysisContext(const Decl *d, idx::TranslationUnit *tu,
bool addehedges = false)
- : D(d), TU(tu), cfg(0), builtCFG(false), liveness(0), PM(0),
+ : D(d), TU(tu), cfg(0), completeCFG(0),
+ builtCFG(false), builtCompleteCFG(false),
+ liveness(0), PM(0),
ReferencedBlockVars(0), AddEHEdges(addehedges) {}
~AnalysisContext();
bool getAddEHEdges() const { return AddEHEdges; }
Stmt *getBody();
CFG *getCFG();
+
+ /// Return a version of the CFG without any edges pruned.
+ CFG *getUnoptimizedCFG();
+
ParentMap &getParentMap();
LiveVariables *getLiveVariables();
return D->getLocation();
}
-
+
class AddStmtChoice {
public:
enum Kind { NotAlwaysAdd = 0,
TryTerminatedBlock(NULL) {}
// buildCFG - Used by external clients to construct the CFG.
- CFG* buildCFG(const Decl *D, Stmt *Statement, ASTContext *C, bool AddEHEdges,
+ CFG* buildCFG(const Decl *D, Stmt *Statement, ASTContext *C,
+ bool pruneTriviallyFalseEdges, bool AddEHEdges,
bool AddScopes);
private:
CFGBlock *addStmt(Stmt *S) {
return Visit(S, AddStmtChoice::AlwaysAdd);
}
-
+
void AppendStmt(CFGBlock *B, Stmt *S,
AddStmtChoice asc = AddStmtChoice::AlwaysAdd) {
B->appendStmt(S, cfg->getBumpVectorContext(), asc.asLValue());
}
-
+
void AddSuccessor(CFGBlock *B, CFGBlock *S) {
B->addSuccessor(S, cfg->getBumpVectorContext());
}
/// TryEvaluateBool - Try and evaluate the Stmt and return 0 or 1
/// if we can evaluate to a known value, otherwise return -1.
TryResult TryEvaluateBool(Expr *S) {
+ if (!PruneTriviallyFalseEdges)
+ return TryResult();
+
Expr::EvalResult Result;
if (!S->isTypeDependent() && !S->isValueDependent() &&
S->Evaluate(Result, *Context) && Result.Val.isInt())
bool badCFG;
+ // True iff trivially false edges should be pruned from the CFG.
+ bool PruneTriviallyFalseEdges;
+
// True iff EH edges on CallExprs should be added to the CFG.
bool AddEHEdges;
/// transferred to the caller. If CFG construction fails, this method returns
/// NULL.
CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement, ASTContext* C,
+ bool pruneTriviallyFalseEdges,
bool addehedges, bool AddScopes) {
+
AddEHEdges = addehedges;
+ PruneTriviallyFalseEdges = pruneTriviallyFalseEdges;
+
Context = C;
assert(cfg.get());
if (!Statement)
case Stmt::CXXThrowExprClass:
return VisitCXXThrowExpr(cast<CXXThrowExpr>(S));
-
+
case Stmt::CXXTryStmtClass:
return VisitCXXTryStmt(cast<CXXTryStmt>(S));
-
+
case Stmt::DeclStmtClass:
return VisitDeclStmt(cast<DeclStmt>(S));
autoCreateBlock();
AppendStmt(Block, B, asc);
}
-
+
Visit(B->getRHS());
return Visit(B->getLHS(), AddStmtChoice::AsLValueNotAlwaysAdd);
}
Ty = Ty->getAs<PointerType>()->getPointeeType();
else if (Ty->isBlockPointerType())
Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
-
+
const FunctionType *FT = Ty->getAs<FunctionType>();
if (FT) {
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
// new blocks as the condition may contain control-flow. Any newly created
// blocks will be pointed to be "Block".
Block = addStmt(I->getCond());
-
+
// Finally, if the IfStmt contains a condition variable, add both the IfStmt
// and the condition variable initialization to the CFG.
if (VarDecl *VD = I->getConditionVariable()) {
addStmt(Init);
}
}
-
+
return Block;
}
assert(Block == EntryConditionBlock);
}
}
-
+
if (Block) {
if (!FinishBlock(EntryConditionBlock))
return 0;
Block = ExitConditionBlock;
EntryConditionBlock = addStmt(C);
assert(Block == EntryConditionBlock);
-
+
// If this block contains a condition variable, add both the condition
// variable and initializer to the CFG.
if (VarDecl *VD = W->getConditionVariable()) {
if (TryTerminatedBlock)
// The current try statement is the only successor.
AddSuccessor(Block, TryTerminatedBlock);
- else
+ else
// otherwise the Exit block is the only successor.
AddSuccessor(Block, &cfg->getExit());
assert(Terminator->getCond() && "switch condition must be non-NULL");
Block = SwitchTerminatedBlock;
Block = addStmt(Terminator->getCond());
-
+
// Finally, if the SwitchStmt contains a condition variable, add both the
// SwitchStmt and the condition variable initialization to the CFG.
if (VarDecl *VD = Terminator->getConditionVariable()) {
addStmt(Init);
}
}
-
+
return Block;
}
return CatchBlock;
}
-CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C,
+CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C,
AddStmtChoice asc) {
- AddStmtChoice::Kind K = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue
+ AddStmtChoice::Kind K = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue
: AddStmtChoice::AlwaysAdd;
autoCreateBlock();
AppendStmt(Block, C, AddStmtChoice(K));
/// buildCFG - Constructs a CFG from an AST. Ownership of the returned
/// CFG is returned to the caller.
CFG* CFG::buildCFG(const Decl *D, Stmt* Statement, ASTContext *C,
+ bool PruneTriviallyFalse,
bool AddEHEdges, bool AddScopes) {
CFGBuilder Builder;
- return Builder.buildCFG(D, Statement, C, AddEHEdges, AddScopes);
+ return Builder.buildCFG(D, Statement, C, PruneTriviallyFalse,
+ AddEHEdges, AddScopes);
}
//===----------------------------------------------------------------------===//
return;
for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I) {
- Stmt *child = *I;
+ Stmt *child = *I;
if (!child)
continue;
-
+
if (BinaryOperator* B = dyn_cast<BinaryOperator>(child))
if (B->isAssignmentOp()) Set.insert(B);