View Javadoc

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