]> granicus.if.org Git - clang/commitdiff
Add 'filtered_pred_iterator' and 'filtered_succ_iterator' to CFGBlock. This allows...
authorTed Kremenek <kremenek@apple.com>
Thu, 9 Sep 2010 00:06:04 +0000 (00:06 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 9 Sep 2010 00:06:04 +0000 (00:06 +0000)
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

include/clang/Analysis/CFG.h
lib/Analysis/CFG.cpp

index b7a8e1159693a6e13dea2af57e11fa2fdee0a75b..22f08cc3d5569e7a9fde9b396c127a35d1f3027f 100644 (file)
@@ -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; }
index f0e48700d3b9ef32084e6a67ed687bc29c37b0d7..3dae83b564f908b1cbc589d5849819308f5f7b64 100644 (file)
@@ -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<SwitchStmt>(From->getTerminator())) {
+      if (S->isAllEnumCasesCovered()) {
+       const Stmt *L = To->getLabel();
+       if (!L || !isa<CaseStmt>(L))
+         return true;
+      }
+    }
+  }
+
+  return false;
+}
+
 //===----------------------------------------------------------------------===//
 // Cleanup: CFG dstor.
 //===----------------------------------------------------------------------===//