View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.rule.codesize;
5   
6   import net.sourceforge.pmd.lang.ast.Node;
7   import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement;
8   import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement;
9   import net.sourceforge.pmd.lang.java.ast.ASTContinueStatement;
10  import net.sourceforge.pmd.lang.java.ast.ASTDoStatement;
11  import net.sourceforge.pmd.lang.java.ast.ASTFinallyStatement;
12  import net.sourceforge.pmd.lang.java.ast.ASTForInit;
13  import net.sourceforge.pmd.lang.java.ast.ASTForStatement;
14  import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
15  import net.sourceforge.pmd.lang.java.ast.ASTLabeledStatement;
16  import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
17  import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
18  import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
19  import net.sourceforge.pmd.lang.java.ast.ASTStatementExpressionList;
20  import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel;
21  import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement;
22  import net.sourceforge.pmd.lang.java.ast.ASTSynchronizedStatement;
23  import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement;
24  import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;
25  import net.sourceforge.pmd.lang.java.ast.JavaNode;
26  import net.sourceforge.pmd.lang.java.rule.AbstractStatisticalJavaRule;
27  import net.sourceforge.pmd.stat.DataPoint;
28  import net.sourceforge.pmd.util.NumericConstants;
29  
30  /**
31   * Abstract superclass for NCSS counting methods. Counts tokens according to <a
32   * href="http://www.kclee.de/clemens/java/javancss/">JavaNCSS rules</a>.
33   * 
34   * @author Jason Bennett
35   */
36  public abstract class AbstractNcssCountRule extends AbstractStatisticalJavaRule {
37  
38      private Class<?> nodeClass;
39  
40      /**
41       * Count the nodes of the given type using NCSS rules.
42       * 
43       * @param nodeClass class of node to count
44       */
45      protected AbstractNcssCountRule(Class<?> nodeClass) {
46          this.nodeClass = nodeClass;
47      }
48  
49      @Override
50      public Object visit(JavaNode node, Object data) {
51          int numNodes = 0;
52  
53          for (int i = 0; i < node.jjtGetNumChildren(); i++) {
54              JavaNode n = (JavaNode) node.jjtGetChild(i);
55              Integer treeSize = (Integer) n.jjtAccept(this, data);
56              numNodes += treeSize.intValue();
57          }
58  
59          if (this.nodeClass.isInstance(node)) {
60              // Add 1 to account for base node
61              numNodes++;
62              DataPoint point = new DataPoint();
63              point.setNode(node);
64              point.setScore(1.0 * numNodes);
65              point.setMessage(getMessage());
66              addDataPoint(point);
67          }
68  
69          return Integer.valueOf(numNodes);
70      }
71  
72      /**
73       * Count the number of children of the given Java node. Adds one to count
74       * the node itself.
75       * 
76       * @param node java node having children counted
77       * @param data node data
78       * @return count of the number of children of the node, plus one
79       */
80      protected Integer countNodeChildren(Node node, Object data) {
81          Integer nodeCount = null;
82          int lineCount = 0;
83          for (int i = 0; i < node.jjtGetNumChildren(); i++) {
84              nodeCount = (Integer) ((JavaNode) node.jjtGetChild(i)).jjtAccept(this, data);
85              lineCount += nodeCount.intValue();
86          }
87          return ++lineCount;
88      }
89  
90      @Override
91      public Object visit(ASTForStatement node, Object data) {
92          return countNodeChildren(node, data);
93      }
94  
95      @Override
96      public Object visit(ASTDoStatement node, Object data) {
97          return countNodeChildren(node, data);
98      }
99  
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
184          * that's a 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 }