AbstractNcssCountRule.java
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 = (JavaNodenode.jjtGetChild(i);
053       Integer treeSize = (Integern.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) ((JavaNodenode.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 }