Skip to content

Commit b037185

Browse files
committed
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
1 parent fd525ef commit b037185

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

clang/include/clang/Analysis/CFG.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,59 @@ class CFGBlock {
205205
unsigned pred_size() const { return Preds.size(); }
206206
bool pred_empty() const { return Preds.empty(); }
207207

208+
209+
class FilterOptions {
210+
public:
211+
FilterOptions() {
212+
IgnoreDefaultsWithCoveredEnums = 0;
213+
};
214+
215+
unsigned IgnoreDefaultsWithCoveredEnums : 1;
216+
};
217+
218+
static bool FilterEdge(const FilterOptions &F, const CFGBlock *Src,
219+
const CFGBlock *Dst);
220+
221+
template <typename IMPL, bool IsPred>
222+
class FilteredCFGBlockIterator {
223+
private:
224+
IMPL I, E;
225+
const FilterOptions F;
226+
const CFGBlock *From;
227+
public:
228+
explicit FilteredCFGBlockIterator(const IMPL &i, const IMPL &e,
229+
const CFGBlock *from,
230+
const FilterOptions &f)
231+
: I(i), E(e), F(f), From(from) {}
232+
233+
bool hasMore() const { return I != E; }
234+
235+
FilteredCFGBlockIterator &operator++() {
236+
do { ++I; } while (hasMore() && Filter(*I));
237+
return *this;
238+
}
239+
240+
const CFGBlock *operator*() const { return *I; }
241+
private:
242+
bool Filter(const CFGBlock *To) {
243+
return IsPred ? FilterEdge(F, To, From) : FilterEdge(F, From, To);
244+
}
245+
};
246+
247+
typedef FilteredCFGBlockIterator<const_pred_iterator, true>
248+
filtered_pred_iterator;
249+
250+
typedef FilteredCFGBlockIterator<const_succ_iterator, false>
251+
filtered_succ_iterator;
252+
253+
filtered_pred_iterator filtered_pred_start_end(const FilterOptions &f) const {
254+
return filtered_pred_iterator(pred_begin(), pred_end(), this, f);
255+
}
256+
257+
filtered_succ_iterator filtered_succ_start_end(const FilterOptions &f) const {
258+
return filtered_succ_iterator(succ_begin(), succ_end(), this, f);
259+
}
260+
208261
// Manipulation of block contents
209262

210263
void setTerminator(Stmt* Statement) { Terminator = Statement; }

clang/lib/Analysis/CFG.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1936,6 +1936,29 @@ unsigned CFG::getNumBlkExprs() {
19361936
}
19371937
}
19381938

1939+
//===----------------------------------------------------------------------===//
1940+
// Filtered walking of the CFG.
1941+
//===----------------------------------------------------------------------===//
1942+
1943+
bool CFGBlock::FilterEdge(const CFGBlock::FilterOptions &F,
1944+
const CFGBlock *From, const CFGBlock *To) {
1945+
1946+
if (F.IgnoreDefaultsWithCoveredEnums) {
1947+
// If the 'To' has no label or is labeled but the label isn't a
1948+
// CaseStmt then filter this edge.
1949+
if (const SwitchStmt *S =
1950+
dyn_cast_or_null<SwitchStmt>(From->getTerminator())) {
1951+
if (S->isAllEnumCasesCovered()) {
1952+
const Stmt *L = To->getLabel();
1953+
if (!L || !isa<CaseStmt>(L))
1954+
return true;
1955+
}
1956+
}
1957+
}
1958+
1959+
return false;
1960+
}
1961+
19391962
//===----------------------------------------------------------------------===//
19401963
// Cleanup: CFG dstor.
19411964
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)