001: package net.sourceforge.pmd.rules.codesize;
002:
003: import net.sourceforge.pmd.ast.ASTBreakStatement;
004: import net.sourceforge.pmd.ast.ASTCatchStatement;
005: import net.sourceforge.pmd.ast.ASTContinueStatement;
006: import net.sourceforge.pmd.ast.ASTDoStatement;
007: import net.sourceforge.pmd.ast.ASTFinallyStatement;
008: import net.sourceforge.pmd.ast.ASTForInit;
009: import net.sourceforge.pmd.ast.ASTForStatement;
010: import net.sourceforge.pmd.ast.ASTIfStatement;
011: import net.sourceforge.pmd.ast.ASTLabeledStatement;
012: import net.sourceforge.pmd.ast.ASTLocalVariableDeclaration;
013: import net.sourceforge.pmd.ast.ASTReturnStatement;
014: import net.sourceforge.pmd.ast.ASTStatementExpression;
015: import net.sourceforge.pmd.ast.ASTStatementExpressionList;
016: import net.sourceforge.pmd.ast.ASTSwitchLabel;
017: import net.sourceforge.pmd.ast.ASTSwitchStatement;
018: import net.sourceforge.pmd.ast.ASTSynchronizedStatement;
019: import net.sourceforge.pmd.ast.ASTThrowStatement;
020: import net.sourceforge.pmd.ast.ASTWhileStatement;
021: import net.sourceforge.pmd.ast.SimpleJavaNode;
022: import net.sourceforge.pmd.stat.DataPoint;
023: import net.sourceforge.pmd.stat.StatisticalRule;
024: import net.sourceforge.pmd.util.NumericConstants;
025:
026: /**
027: * Abstract superclass for NCSS counting methods. Counts tokens according to <a
028: * href="http://www.kclee.de/clemens/java/javancss/">JavaNCSS rules</a>.
029: *
030: * @author Jason Bennett
031: */
032: public abstract class AbstractNcssCount extends StatisticalRule {
033:
034: private Class nodeClass;
035:
036: /**
037: * Count the nodes of the given type using NCSS rules.
038: *
039: * @param nodeClass
040: * class of node to count
041: */
042: protected AbstractNcssCount(Class nodeClass) {
043: this .nodeClass = nodeClass;
044: }
045:
046: public Object visit(SimpleJavaNode node, Object data) {
047: int numNodes = 0;
048:
049: for (int i = 0; i < node.jjtGetNumChildren(); i++) {
050: SimpleJavaNode simpleNode = (SimpleJavaNode) node
051: .jjtGetChild(i);
052: Integer treeSize = (Integer) simpleNode.jjtAccept(this ,
053: data);
054: numNodes += treeSize.intValue();
055: }
056:
057: if (this .nodeClass.isInstance(node)) {
058: // Add 1 to account for base node
059: numNodes++;
060: DataPoint point = new DataPoint();
061: point.setNode(node);
062: point.setScore(1.0 * numNodes);
063: point.setMessage(getMessage());
064: addDataPoint(point);
065: }
066:
067: return Integer.valueOf(numNodes);
068: }
069:
070: /**
071: * Count the number of children of the given Java node. Adds one to count the
072: * node itself.
073: *
074: * @param node
075: * java node having children counted
076: * @param data
077: * node data
078: * @return count of the number of children of the node, plus one
079: */
080: protected Integer countNodeChildren(SimpleJavaNode node, Object data) {
081: Integer nodeCount = null;
082: int lineCount = 0;
083: for (int i = 0; i < node.jjtGetNumChildren(); i++) {
084: nodeCount = (Integer) ((SimpleJavaNode) node.jjtGetChild(i))
085: .jjtAccept(this , data);
086: lineCount += nodeCount.intValue();
087: }
088: return ++lineCount;
089: }
090:
091: public Object visit(ASTForStatement node, Object data) {
092: return countNodeChildren(node, data);
093: }
094:
095: public Object visit(ASTDoStatement node, Object data) {
096: return countNodeChildren(node, data);
097: }
098:
099: public Object visit(ASTIfStatement node, Object data) {
100:
101: Integer lineCount = countNodeChildren(node, data);
102:
103: if (node.hasElse()) {
104: lineCount++;
105: }
106:
107: return lineCount;
108: }
109:
110: public Object visit(ASTWhileStatement node, Object data) {
111: return countNodeChildren(node, data);
112: }
113:
114: public Object visit(ASTBreakStatement node, Object data) {
115: return NumericConstants.ONE;
116: }
117:
118: public Object visit(ASTCatchStatement node, Object data) {
119: return countNodeChildren(node, data);
120: }
121:
122: public Object visit(ASTContinueStatement node, Object data) {
123: return NumericConstants.ONE;
124: }
125:
126: public Object visit(ASTFinallyStatement node, Object data) {
127: return countNodeChildren(node, data);
128: }
129:
130: public Object visit(ASTReturnStatement node, Object data) {
131: return countNodeChildren(node, data);
132: }
133:
134: public Object visit(ASTSwitchStatement node, Object data) {
135: return countNodeChildren(node, data);
136: }
137:
138: public Object visit(ASTSynchronizedStatement node, Object data) {
139: return countNodeChildren(node, data);
140: }
141:
142: public Object visit(ASTThrowStatement node, Object data) {
143: return NumericConstants.ONE;
144: }
145:
146: public Object visit(ASTStatementExpression node, Object data) {
147:
148: // "For" update expressions do not count as separate lines of code
149: if (node.jjtGetParent() instanceof ASTStatementExpressionList) {
150: return NumericConstants.ZERO;
151: }
152:
153: return NumericConstants.ONE;
154: }
155:
156: public Object visit(ASTLabeledStatement node, Object data) {
157: return countNodeChildren(node, data);
158: }
159:
160: public Object visit(ASTLocalVariableDeclaration node, Object data) {
161:
162: // "For" init declarations do not count as separate lines of code
163: if (node.jjtGetParent() instanceof ASTForInit) {
164: return NumericConstants.ZERO;
165: }
166:
167: /*
168: * This will count variables declared on the same line as separate NCSS
169: * counts. This violates JavaNCSS standards, but I'm not convinced that's a
170: * bad thing here.
171: */
172:
173: return countNodeChildren(node, data);
174: }
175:
176: public Object visit(ASTSwitchLabel node, Object data) {
177: return countNodeChildren(node, data);
178: }
179:
180: }
|