View Javadoc

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