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 Integer.valueOf( 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 ++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       lineCount++;
    103     }
    104
    105     return lineCount;
    106   }
    107
    108   public Object visit(ASTWhileStatement node, Object data) {
    109     return countNodeChildren( node, data );
    110   }
    111
    112   public Object visit(ASTBreakStatement node, Object data) {
    113     return NumericConstants.ONE;
    114   }
    115
    116   public Object visit(ASTCatchStatement node, Object data) {
    117     return countNodeChildren( node, data );
    118   }
    119
    120   public Object visit(ASTContinueStatement node, Object data) {
    121     return NumericConstants.ONE;
    122   }
    123
    124   public Object visit(ASTFinallyStatement node, Object data) {
    125     return countNodeChildren( node, data );
    126   }
    127
    128   public Object visit(ASTReturnStatement node, Object data) {
    129     return countNodeChildren( node, data );
    130   }
    131
    132   public Object visit(ASTSwitchStatement node, Object data) {
    133     return countNodeChildren( node, data );
    134   }
    135
    136   public Object visit(ASTSynchronizedStatement node, Object data) {
    137     return countNodeChildren( node, data );
    138   }
    139
    140   public Object visit(ASTThrowStatement node, Object data) {
    141     return NumericConstants.ONE;
    142   }
    143
    144   public Object visit(ASTStatementExpression node, Object data) {
    145
    146     // "For" update expressions do not count as separate lines of code
    147     if ( node.jjtGetParent() instanceof ASTStatementExpressionList ) {
    148       return NumericConstants.ZERO;
    149     }
    150
    151     return NumericConstants.ONE;
    152   }
    153
    154   public Object visit(ASTLabeledStatement node, Object data) {
    155     return countNodeChildren( node, data );
    156   }
    157
    158   public Object visit(ASTLocalVariableDeclaration node, Object data) {
    159
    160     // "For" init declarations do not count as separate lines of code
    161     if ( node.jjtGetParent() instanceof ASTForInit ) {
    162       return NumericConstants.ZERO;
    163     }
    164
    165     /*
    166      * This will count variables declared on the same line as separate NCSS
    167      * counts. This violates JavaNCSS standards, but I'm not convinced that's a
    168      * bad thing here.
    169      */
    170
    171     return countNodeChildren( node, data );
    172   }
    173
    174   public Object visit(ASTSwitchLabel node, Object data) {
    175     return countNodeChildren( node, data );
    176   }
    177
    178 }