From: Ted Kremenek Date: Thu, 9 Sep 2010 00:06:04 +0000 (+0000) Subject: Add 'filtered_pred_iterator' and 'filtered_succ_iterator' to CFGBlock. This allows... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ee7f84d509c6382491673883598eb9ed2d3a6a8b;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@113449 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h index b7a8e11596..22f08cc3d5 100644 --- a/include/clang/Analysis/CFG.h +++ b/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 + 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 + filtered_pred_iterator; + + typedef FilteredCFGBlockIterator + 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/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index f0e48700d3..3dae83b564 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -1936,6 +1936,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(From->getTerminator())) { + if (S->isAllEnumCasesCovered()) { + const Stmt *L = To->getLabel(); + if (!L || !isa(L)) + return true; + } + } + } + + return false; +} + //===----------------------------------------------------------------------===// // Cleanup: CFG dstor. //===----------------------------------------------------------------------===//