/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.rules.design; import net.sourceforge.pmd.ast.ASTStatement; import net.sourceforge.pmd.ast.ASTSwitchLabel; import net.sourceforge.pmd.ast.ASTSwitchStatement; import net.sourceforge.pmd.stat.DataPoint; import net.sourceforge.pmd.stat.StatisticalRule; /** * @author dpeugh * * Switch Density - This is the number of statements over the * number of cases within a switch. The higher the value, the * more work each case is doing. * * Its my theory, that when the Switch Density is high, you should * start looking at Subclasses or State Pattern to alleviate the * problem. */ public class SwitchDensityRule extends StatisticalRule { private class SwitchDensity { private int labels = 0; private int stmts = 0; public SwitchDensity() { } public void addSwitchLabel() { labels++; } public void addStatement() { stmts++; } public void addStatements(int stmtCount) { stmts += stmtCount; } public int getStatementCount() { return stmts; } public double getDensity() { if (labels == 0) { return 0; } return 1.0 * (stmts / labels); } } public SwitchDensityRule() { super(); } public Object visit(ASTSwitchStatement node, Object data) { SwitchDensity oldData = null; if (data instanceof SwitchDensity) { oldData = (SwitchDensity) data; } SwitchDensity density = new SwitchDensity(); node.childrenAccept(this, density); DataPoint point = new DataPoint(); point.setLineNumber(node.getBeginLine()); point.setScore(density.getDensity()); point.setRule(this); point.setMessage(getMessage()); addDataPoint(point); if (data instanceof SwitchDensity) { ((SwitchDensity) data).addStatements(density.getStatementCount()); } return oldData; } public Object visit(ASTStatement statement, Object data) { if (data instanceof SwitchDensity) { ((SwitchDensity) data).addStatement(); } statement.childrenAccept(this, data); return data; } public Object visit(ASTSwitchLabel switchLabel, Object data) { if (data instanceof SwitchDensity) { ((SwitchDensity) data).addSwitchLabel(); } switchLabel.childrenAccept(this, data); return data; } }