summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2010-09-09 00:06:04 +0000
committerTed Kremenek <kremenek@apple.com>2010-09-09 00:06:04 +0000
commitb037185b52556e011023dcdb622b46a4f1284e9a (patch)
treeb15ed6f81ff50f7c2fa2eb33d8af9b25910d7f44
parentfd525ef338f4001f2515e865952cbbe6c4105aa3 (diff)
downloadbcm5719-llvm-b037185b52556e011023dcdb622b46a4f1284e9a.tar.gz
bcm5719-llvm-b037185b52556e011023dcdb622b46a4f1284e9a.zip
Add 'filtered_pred_iterator' and 'filtered_succ_iterator' to CFGBlock. This allows a client
to selectively walk successors/predecessors based on commonly used filters. For starters, add a filter to ignore 'default:' cases for SwitchStmts when all enum values are covered by CaseStmts. llvm-svn: 113449
-rw-r--r--clang/include/clang/Analysis/CFG.h53
-rw-r--r--clang/lib/Analysis/CFG.cpp23
2 files changed, 76 insertions, 0 deletions
diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h
index b7a8e115969..22f08cc3d55 100644
--- a/clang/include/clang/Analysis/CFG.h
+++ b/clang/include/clang/Analysis/CFG.h
@@ -205,6 +205,59 @@ public:
unsigned pred_size() const { return Preds.size(); }
bool pred_empty() const { return Preds.empty(); }
+
+ class FilterOptions {
+ public:
+ FilterOptions() {
+ IgnoreDefaultsWithCoveredEnums = 0;
+ };
+
+ unsigned IgnoreDefaultsWithCoveredEnums : 1;
+ };
+
+ static bool FilterEdge(const FilterOptions &F, const CFGBlock *Src,
+ const CFGBlock *Dst);
+
+ template <typename IMPL, bool IsPred>
+ class FilteredCFGBlockIterator {
+ private:
+ IMPL I, E;
+ const FilterOptions F;
+ const CFGBlock *From;
+ public:
+ explicit FilteredCFGBlockIterator(const IMPL &i, const IMPL &e,
+ const CFGBlock *from,
+ const FilterOptions &f)
+ : I(i), E(e), F(f), From(from) {}
+
+ bool hasMore() const { return I != E; }
+
+ FilteredCFGBlockIterator &operator++() {
+ do { ++I; } while (hasMore() && Filter(*I));
+ return *this;
+ }
+
+ 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;
+
+ typedef FilteredCFGBlockIterator<const_succ_iterator, false>
+ filtered_succ_iterator;
+
+ filtered_pred_iterator filtered_pred_start_end(const FilterOptions &f) const {
+ return filtered_pred_iterator(pred_begin(), pred_end(), this, f);
+ }
+
+ filtered_succ_iterator filtered_succ_start_end(const FilterOptions &f) const {
+ return filtered_succ_iterator(succ_begin(), succ_end(), this, f);
+ }
+
// Manipulation of block contents
void setTerminator(Stmt* Statement) { Terminator = Statement; }
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index f0e48700d3b..3dae83b564f 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -1937,6 +1937,29 @@ unsigned CFG::getNumBlkExprs() {
}
//===----------------------------------------------------------------------===//
+// Filtered walking of the CFG.
+//===----------------------------------------------------------------------===//
+
+bool CFGBlock::FilterEdge(const CFGBlock::FilterOptions &F,
+ const CFGBlock *From, const CFGBlock *To) {
+
+ if (F.IgnoreDefaultsWithCoveredEnums) {
+ // If the 'To' has no label or is labeled but the label isn't a
+ // CaseStmt then filter this edge.
+ if (const SwitchStmt *S =
+ dyn_cast_or_null<SwitchStmt>(From->getTerminator())) {
+ if (S->isAllEnumCasesCovered()) {
+ const Stmt *L = To->getLabel();
+ if (!L || !isa<CaseStmt>(L))
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
// Cleanup: CFG dstor.
//===----------------------------------------------------------------------===//
OpenPOWER on IntegriCloud