001 package net.sourceforge.pmd.lang.java.rule.codesize;
002
003 import net.sourceforge.pmd.lang.ast.Node;
004 import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement;
005 import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement;
006 import net.sourceforge.pmd.lang.java.ast.ASTContinueStatement;
007 import net.sourceforge.pmd.lang.java.ast.ASTDoStatement;
008 import net.sourceforge.pmd.lang.java.ast.ASTFinallyStatement;
009 import net.sourceforge.pmd.lang.java.ast.ASTForInit;
010 import net.sourceforge.pmd.lang.java.ast.ASTForStatement;
011 import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
012 import net.sourceforge.pmd.lang.java.ast.ASTLabeledStatement;
013 import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
014 import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
015 import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
016 import net.sourceforge.pmd.lang.java.ast.ASTStatementExpressionList;
017 import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel;
018 import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement;
019 import net.sourceforge.pmd.lang.java.ast.ASTSynchronizedStatement;
020 import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement;
021 import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;
022 import net.sourceforge.pmd.lang.java.ast.JavaNode;
023 import net.sourceforge.pmd.lang.java.rule.AbstractStatisticalJavaRule;
024 import net.sourceforge.pmd.stat.DataPoint;
025 import net.sourceforge.pmd.util.NumericConstants;
026
027 /**
028 * Abstract superclass for NCSS counting methods. Counts tokens according to <a
029 * href="http://www.kclee.de/clemens/java/javancss/">JavaNCSS rules</a>.
030 *
031 * @author Jason Bennett
032 */
033 public abstract class AbstractNcssCountRule extends AbstractStatisticalJavaRule {
034
035 private Class<?> nodeClass;
036
037 /**
038 * Count the nodes of the given type using NCSS rules.
039 *
040 * @param nodeClass
041 * class of node to count
042 */
043 protected AbstractNcssCountRule(Class<?> nodeClass) {
044 this.nodeClass = nodeClass;
045 }
046
047 @Override
048 public Object visit(JavaNode node, Object data) {
049 int numNodes = 0;
050
051 for (int i = 0; i < node.jjtGetNumChildren(); i++) {
052 JavaNode n = (JavaNode) node.jjtGetChild(i);
053 Integer treeSize = (Integer) n.jjtAccept(this, 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(Node node, Object data) {
081 Integer nodeCount = null;
082 int lineCount = 0;
083 for (int i = 0; i < node.jjtGetNumChildren(); i++) {
084 nodeCount = (Integer) ((JavaNode) node.jjtGetChild(i)).jjtAccept(this, data);
085 lineCount += nodeCount.intValue();
086 }
087 return ++lineCount;
088 }
089
090 @Override
091 public Object visit(ASTForStatement node, Object data) {
092 return countNodeChildren(node, data);
093 }
094
095 @Override
096 public Object visit(ASTDoStatement node, Object data) {
097 return countNodeChildren(node, data);
098 }
099
100 @Override
101 public Object visit(ASTIfStatement node, Object data) {
102
103 Integer lineCount = countNodeChildren(node, data);
104
105 if (node.hasElse()) {
106 lineCount++;
107 }
108
109 return lineCount;
110 }
111
112 @Override
113 public Object visit(ASTWhileStatement node, Object data) {
114 return countNodeChildren(node, data);
115 }
116
117 @Override
118 public Object visit(ASTBreakStatement node, Object data) {
119 return NumericConstants.ONE;
120 }
121
122 @Override
123 public Object visit(ASTCatchStatement node, Object data) {
124 return countNodeChildren(node, data);
125 }
126
127 @Override
128 public Object visit(ASTContinueStatement node, Object data) {
129 return NumericConstants.ONE;
130 }
131
132 @Override
133 public Object visit(ASTFinallyStatement node, Object data) {
134 return countNodeChildren(node, data);
135 }
136
137 @Override
138 public Object visit(ASTReturnStatement node, Object data) {
139 return countNodeChildren(node, data);
140 }
141
142 @Override
143 public Object visit(ASTSwitchStatement node, Object data) {
144 return countNodeChildren(node, data);
145 }
146
147 @Override
148 public Object visit(ASTSynchronizedStatement node, Object data) {
149 return countNodeChildren(node, data);
150 }
151
152 @Override
153 public Object visit(ASTThrowStatement node, Object data) {
154 return NumericConstants.ONE;
155 }
156
157 @Override
158 public Object visit(ASTStatementExpression node, Object data) {
159
160 // "For" update expressions do not count as separate lines of code
161 if (node.jjtGetParent() instanceof ASTStatementExpressionList) {
162 return NumericConstants.ZERO;
163 }
164
165 return NumericConstants.ONE;
166 }
167
168 @Override
169 public Object visit(ASTLabeledStatement node, Object data) {
170 return countNodeChildren(node, data);
171 }
172
173 @Override
174 public Object visit(ASTLocalVariableDeclaration node, Object data) {
175
176 // "For" init declarations do not count as separate lines of code
177 if (node.jjtGetParent() instanceof ASTForInit) {
178 return NumericConstants.ZERO;
179 }
180
181 /*
182 * This will count variables declared on the same line as separate NCSS
183 * counts. This violates JavaNCSS standards, but I'm not convinced that's a
184 * bad thing here.
185 */
186
187 return countNodeChildren(node, data);
188 }
189
190 @Override
191 public Object visit(ASTSwitchLabel node, Object data) {
192 return countNodeChildren(node, data);
193 }
194
195 }
|