summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2007-09-12 19:09:12 +0000
committerTed Kremenek <kremenek@apple.com>2007-09-12 19:09:12 +0000
commitd1600343308d37749791038baef6b71052de3a09 (patch)
treee390b012fde16f4480fdfdaea68b47415a892125
parent909ef0973b0b5119060dcf01f930434bf42c6ac4 (diff)
downloadllvm-d1600343308d37749791038baef6b71052de3a09.tar.gz
Added extensions (subclasses) to the StmtVisitor class that
are useful for dataflow analysis: CFGStmtVisitor and DataflowStmtVisitor. CFGStmtVisitor is the same as StmtVisitor is that it has separate visitors for "root" statements in a CFGBlock (statements that have a designated slot int the list of statements in a CFGBlock). It also recognizes statements that have implicit control-flow, and calls special visitor methods for those. DataflowStmtVisitor extends CFGStmtVisitor to serve as a template for implementing transfer functions. It does a pre-/post-order traversal of substatements depending on whether we are doing a forward/backward analysis. It also has special handling for implicit-control-flow statements so that they are visited only once. llvm-svn: 41884
-rw-r--r--clang/include/clang/Analysis/CFGStmtVisitor.h99
-rw-r--r--clang/include/clang/Analysis/DataflowStmtVisitor.h130
2 files changed, 229 insertions, 0 deletions
diff --git a/clang/include/clang/Analysis/CFGStmtVisitor.h b/clang/include/clang/Analysis/CFGStmtVisitor.h
new file mode 100644
index 000000000000..3e72598767dc
--- /dev/null
+++ b/clang/include/clang/Analysis/CFGStmtVisitor.h
@@ -0,0 +1,99 @@
+//===--- CFGStmtVisitor.h - Visitor for Stmts in a CFG ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Ted Kremenek and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the CFGStmtVisitor interface, which extends
+// StmtVisitor. This interface is useful for visiting statements in a CFG
+// where some statements have implicit control-flow and thus should
+// be treated specially.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H
+#define LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H
+
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/CFG.h"
+
+namespace clang {
+
+#define DISPATCH_CASE(CLASS) \
+case Stmt::CLASS ## Class: return \
+static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S));
+
+#define DEFAULT_BLOCKSTMT_VISIT(CLASS) RetTy BlockStmt_Visit ## CLASS(CLASS *S)\
+{ return\
+ static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowStmt(S); }
+
+template <typename ImplClass, typename RetTy=void>
+class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
+public:
+ /// BlockVisit_XXX - Visitor methods for visiting the "root" statements in
+ /// CFGBlocks. Root statements are the statements that appear explicitly in
+ /// the list of statements in a CFGBlock. For substatements, or when there
+ /// is no implementation provided for a BlockStmt_XXX method, we default
+ /// to using StmtVisitor's Visit method.
+ RetTy BlockStmt_Visit(Stmt* S) {
+ switch (S->getStmtClass()) {
+ DISPATCH_CASE(CallExpr)
+ DISPATCH_CASE(StmtExpr)
+ DISPATCH_CASE(ConditionalOperator)
+
+ case Stmt::BinaryOperatorClass: {
+ BinaryOperator* B = cast<BinaryOperator>(S);
+ if (B->isLogicalOp())
+ return static_cast<ImplClass*>(this)->BlockStmt_VisitLogicalOp(B);
+ else if (B->getOpcode() == BinaryOperator::Comma)
+ return static_cast<ImplClass*>(this)->BlockStmt_VisitComma(B);
+ // Fall through.
+ }
+
+ default:
+ return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
+ }
+ }
+
+ DEFAULT_BLOCKSTMT_VISIT(CallExpr)
+ DEFAULT_BLOCKSTMT_VISIT(StmtExpr)
+ DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator)
+
+ RetTy BlockStmt_VisitImplicitControlFlowStmt(Stmt* S) {
+ return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
+ }
+
+ RetTy BlockStmt_VisitStmt(Stmt* S) {
+ return static_cast<ImplClass*>(this)->Visit(S);
+ }
+
+ RetTy BlockStmt_VisitLogicalOp(BinaryOperator* B) {
+ return
+ static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowStmt(B);
+ }
+
+ RetTy BlockStmt_VisitComma(BinaryOperator* B) {
+ return
+ static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowStmt(B);
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Utility methods. Not called by default (but subclasses may use them).
+ //===--------------------------------------------------------------------===//
+
+ /// VisitChildren: Call "Visit" on each child of S.
+ void VisitChildren(Stmt* S) {
+ for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I)
+ static_cast<ImplClass*>(this)->Visit(*I);
+ }
+};
+
+#undef DEFAULT_BLOCKSTMT_VISIT
+#undef DISPATCH_CASE
+
+} // end namespace clang
+
+#endif
diff --git a/clang/include/clang/Analysis/DataflowStmtVisitor.h b/clang/include/clang/Analysis/DataflowStmtVisitor.h
new file mode 100644
index 000000000000..67c4a75c73ac
--- /dev/null
+++ b/clang/include/clang/Analysis/DataflowStmtVisitor.h
@@ -0,0 +1,130 @@
+//===--- DataFlowStmtVisitor.h - StmtVisitor for Dataflow -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Ted Kremenek and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the DataflowStmtVisitor interface, which extends
+// CFGStmtVisitor. This interface is useful for visiting statements in a CFG
+// with the understanding that statements are walked in order of the analysis
+// traversal.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_DATAFLOW_STMTVISITOR_H
+#define LLVM_CLANG_ANALYSIS_DATAFLOW_STMTVISITOR_H
+
+#include "clang/Analysis/CFGStmtVisitor.h"
+
+namespace clang {
+
+// Tag classes describing what direction the dataflow analysis goes.
+namespace dataflow {
+ struct forward_analysis_tag {};
+ struct backward_analysis_tag {};
+}
+
+template < typename ImplClass,
+ typename AnalysisTag=dataflow::forward_analysis_tag >
+class DataflowStmtVisitor : public CFGStmtVisitor<ImplClass,void> {
+public:
+ //===--------------------------------------------------------------------===//
+ // Observer methods. These are called before a statement is visited, and
+ // there is no special dispatch on statement type. This allows subclasses
+ // to inject extra functionality (e.g. monitoring) that applies to all
+ // visited statements.
+ //===--------------------------------------------------------------------===//
+
+ void ObserveStmt(Stmt* S) {}
+
+ void ObserveBlockStmt(Stmt* S) {
+ static_cast<ImplClass*>(this)->ObserveStmt(S);
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Statment visitor methods. These modify the behavior of CFGVisitor::Visit
+ // and CFGVisitor::BlockStmt_Visit by performing a traversal of substatements
+ // depending on the direction of the dataflow analysis. For forward
+ // analyses, the traversal is postorder (representing evaluation order)
+ // and for backward analysis it is preorder (reverse-evaluation order).
+ //===--------------------------------------------------------------------===//
+
+ void BlockStmt_Visit(Stmt* S) { BlockStmt_Visit(S,AnalysisTag()); }
+
+ void BlockStmt_Visit(Stmt* S, dataflow::forward_analysis_tag) {
+ // Process statements in a postorder traversal of the AST.
+ if (!CFG::hasImplicitControlFlow(S) &&
+ S->getStmtClass() != Stmt::CallExprClass)
+ static_cast<ImplClass*>(this)->VisitChildren(S);
+
+ static_cast<ImplClass*>(this)->ObserveBlockStmt(S);
+ static_cast<CFGStmtVisitor<ImplClass,void>*>(this)->BlockStmt_Visit(S);
+ }
+
+ void BlockStmt_Visit(Stmt* S, dataflow::backward_analysis_tag) {
+ // Process statements in a preorder traversal of the AST.
+ static_cast<ImplClass*>(this)->ObserveBlockStmt(S);
+ static_cast<CFGStmtVisitor<ImplClass,void>*>(this)->BlockStmt_Visit(S);
+
+ if (!CFG::hasImplicitControlFlow(S) &&
+ S->getStmtClass() != Stmt::CallExprClass)
+ static_cast<ImplClass*>(this)->VisitChildren(S);
+ }
+
+ void Visit(Stmt* S) { Visit(S,AnalysisTag()); }
+
+ void Visit(Stmt* S, dataflow::forward_analysis_tag) {
+ if (CFG::hasImplicitControlFlow(S))
+ return;
+
+ // Process statements in a postorder traversal of the AST.
+ static_cast<ImplClass*>(this)->VisitChildren(S);
+ static_cast<ImplClass*>(this)->ObserveStmt(S);
+ static_cast<CFGStmtVisitor<ImplClass,void>*>(this)->Visit(S);
+ }
+
+ void Visit(Stmt* S, dataflow::backward_analysis_tag) {
+ if (CFG::hasImplicitControlFlow(S))
+ return;
+
+ // Process statements in a preorder traversal of the AST.
+ static_cast<ImplClass*>(this)->ObserveStmt(S);
+ static_cast<CFGStmtVisitor<ImplClass,void>*>(this)->Visit(S);
+ static_cast<ImplClass*>(this)->VisitChildren(S);
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Methods for visiting entire CFGBlocks.
+ //===--------------------------------------------------------------------===//
+
+ void VisitBlockEntry(const CFGBlock* B) {}
+ void VisitBlockExit(const CFGBlock* B) {}
+
+ void VisitBlock(const CFGBlock* B) { VisitBlock(B,AnalysisTag()); }
+
+ void VisitBlock(const CFGBlock* B, dataflow::forward_analysis_tag ) {
+ static_cast<ImplClass*>(this)->VisitBlockEntry(B);
+
+ for (CFGBlock::const_iterator I=B->begin(), E=B->end(); I!=E; ++I)
+ static_cast<ImplClass*>(this)->BlockStmt_Visit(const_cast<Stmt*>(*I));
+
+ static_cast<ImplClass*>(this)->VisitBlockExit(B);
+ }
+
+ void VisitBlock(const CFGBlock* B, dataflow::backward_analysis_tag ) {
+ static_cast<ImplClass*>(this)->VisitBlockExit(B);
+
+ for (CFGBlock::const_reverse_iterator I=B->rbegin(), E=B->rend(); I!=E; ++I)
+ static_cast<ImplClass*>(this)->BlockStmt_Visit(const_cast<Stmt*>(*I));
+
+ static_cast<ImplClass*>(this)->VisitBlockEntry(B);
+ }
+
+};
+
+} // end namespace clang
+
+#endif