package sharpen.core; import sharpen.core.csharp.ast.*; public final class FlowAnalysis { private FlowAnalysis() { ; } public static boolean isReachable(CSBlock block) { return Visitor.run(block); } public static class Visitor extends CSVisitor { private boolean _reachable = true; public static boolean run(CSStatement node) { Visitor visitor = new Visitor(); node.accept(visitor); return visitor._reachable; } private void setUnreachable() { _reachable = false; } private boolean isUnreachable() { return !_reachable; } @Override public void visit(CSBlock node) { for (CSStatement statement : node.statements()) { if (!run(statement)) { setUnreachable(); break; } } } @Override public void visit(CSBreakStatement node) { setUnreachable(); } @Override public void visit(CSContinueStatement node) { setUnreachable(); } @Override public void visit(CSReturnStatement node) { setUnreachable(); } @Override public void visit(CSThrowStatement node) { setUnreachable(); } @Override public void visit(CSIfStatement node) { boolean reachable = false; if (node.trueBlock() != null) reachable |= run(node.trueBlock()); if (node.falseBlock() != null) reachable |= run(node.falseBlock()); if (!reachable) setUnreachable(); } @Override public void visit(CSSwitchStatement node) { if (isUnreachable()) return; boolean hasDefault = false; boolean reachable = false; for (CSCaseClause clause : node.caseClauses()) { if (clause.isDefault()) hasDefault = true; reachable |= run(clause.body()); } if (!reachable && hasDefault) setUnreachable(); } } }