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 }