View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.plsql.rule.codesize;
5   
6   import java.util.logging.Logger;
7   
8   import net.sourceforge.pmd.lang.ast.Node;
9   import net.sourceforge.pmd.lang.java.ast.ASTStatement;
10  import net.sourceforge.pmd.lang.plsql.ast.ASTCaseStatement;
11  import net.sourceforge.pmd.lang.plsql.ast.ASTCaseWhenClause;
12  import net.sourceforge.pmd.lang.plsql.ast.ASTContinueStatement;
13  import net.sourceforge.pmd.lang.plsql.ast.ASTElseClause;
14  import net.sourceforge.pmd.lang.plsql.ast.ASTElsifClause;
15  import net.sourceforge.pmd.lang.plsql.ast.ASTExceptionHandler;
16  import net.sourceforge.pmd.lang.plsql.ast.ASTExitStatement;
17  import net.sourceforge.pmd.lang.plsql.ast.ASTExpression;
18  import net.sourceforge.pmd.lang.plsql.ast.ASTForStatement;
19  import net.sourceforge.pmd.lang.plsql.ast.ASTGotoStatement;
20  import net.sourceforge.pmd.lang.plsql.ast.ASTIfStatement;
21  import net.sourceforge.pmd.lang.plsql.ast.ASTLabelledStatement;
22  import net.sourceforge.pmd.lang.plsql.ast.ASTLoopStatement;
23  import net.sourceforge.pmd.lang.plsql.ast.ASTRaiseStatement;
24  import net.sourceforge.pmd.lang.plsql.ast.ASTReturnStatement;
25  import net.sourceforge.pmd.lang.plsql.ast.ASTWhileStatement;
26  import net.sourceforge.pmd.lang.plsql.ast.PLSQLNode;
27  import net.sourceforge.pmd.lang.plsql.rule.AbstractStatisticalPLSQLRule;
28  import net.sourceforge.pmd.stat.DataPoint;
29  import net.sourceforge.pmd.util.NumericConstants;
30  
31  /**
32   * Abstract superclass for NCSS counting methods. Analogous to and cribbed from {@link net.sourceforge.pmd.lang.java.rule.codesize.AbstractNcssCountRule}.
33   */
34  public abstract class AbstractNcssCountRule extends AbstractStatisticalPLSQLRule {
35      private final static Logger LOGGER = Logger.getLogger(AbstractNcssCountRule.class.getName()); 
36  
37      private Class<?> nodeClass;
38  
39      /**
40       * Count the nodes of the given type using NCSS rules.
41       * 
42       * @param nodeClass
43       *          class of node to count
44       */
45      protected AbstractNcssCountRule(Class<?> nodeClass) {
46  	this.nodeClass = nodeClass;
47          LOGGER.fine("Counting for " + nodeClass.getCanonicalName());
48      }
49  
50      @Override
51      public Object visit(PLSQLNode node, Object data) {
52  	int numNodes = 0;
53  
54  	for (int i = 0; i < node.jjtGetNumChildren(); i++) {
55  		PLSQLNode n = (PLSQLNode) node.jjtGetChild(i);
56  	    Integer treeSize = (Integer) n.jjtAccept(this, data);
57  	    numNodes += treeSize.intValue();
58  	}
59  
60          LOGGER.finer("Checking candidate " + node.getClass().getCanonicalName() 
61                      + " against target class " + nodeClass.getCanonicalName() 
62                      + " with " + numNodes + " nodes"
63                     );
64  
65  	if (this.nodeClass.isInstance(node)) {
66            LOGGER.fine("Matched candidate " + node.getClass().getCanonicalName() 
67                          + " against target class " + nodeClass.getCanonicalName() 
68                         );
69  	    // Add 1 to account for base node
70  	    numNodes++;
71  	    DataPoint point = new DataPoint();
72  	    point.setNode(node);
73  	    point.setScore(1.0 * numNodes);
74  	    point.setMessage(getMessage());
75  	    addDataPoint(point);
76              LOGGER.fine("Running score is " +  point.getScore());
77  	}
78  
79  	return Integer.valueOf(numNodes);
80      }
81  
82      /**
83       * Count the number of children of the given PLSQL node. Adds one to count the
84       * node itself.
85       * 
86       * @param node
87       *          PLSQL node having children counted
88       * @param data
89       *          node data
90       * @return count of the number of children of the node, plus one
91       */
92      protected Integer countNodeChildren(Node node, Object data) {
93  	Integer nodeCount = null;
94  	int lineCount = 0;
95  	for (int i = 0; i < node.jjtGetNumChildren(); i++) {
96  	    nodeCount = (Integer) ((PLSQLNode) node.jjtGetChild(i)).jjtAccept(this, data);
97  	    lineCount += nodeCount.intValue();
98  	}
99  	return ++lineCount;
100     }
101 
102     @Override
103     public Object visit(ASTForStatement node, Object data) {
104 	return countNodeChildren(node, data);
105     }
106 
107     @Override
108     public Object visit(ASTLoopStatement node, Object data) {
109 	return countNodeChildren(node, data);
110     }
111 
112     @Override
113     public Object visit(ASTIfStatement node, Object data) {
114 
115 	Integer lineCount = countNodeChildren(node, data);
116 
117 	return lineCount;
118     }
119 
120     @Override
121     public Object visit(ASTElsifClause node, Object data) {
122 
123 	Integer lineCount = countNodeChildren(node, data);
124 
125 	return lineCount;
126     }
127 
128     @Override
129     public Object visit(ASTElseClause node, Object data) {
130 
131 	Integer lineCount = countNodeChildren(node, data);
132 
133 	return lineCount;
134     }
135 
136     @Override
137     public Object visit(ASTWhileStatement node, Object data) {
138 	return countNodeChildren(node, data);
139     }
140 
141     @Override
142     public Object visit(ASTExitStatement node, Object data) {
143 	return NumericConstants.ONE;
144     }
145 
146     @Override
147     public Object visit(ASTExceptionHandler node, Object data) {
148 	return countNodeChildren(node, data);
149     }
150 
151     @Override
152     public Object visit(ASTContinueStatement node, Object data) {
153 	return NumericConstants.ONE;
154     }
155 
156     @Override
157     public Object visit(ASTGotoStatement node, Object data) {
158 	return NumericConstants.ONE;
159     }
160 
161     @Override
162     public Object visit(ASTReturnStatement node, Object data) {
163 	return countNodeChildren(node, data);
164     }
165 
166     @Override
167     public Object visit(ASTCaseStatement node, Object data) {
168 	return countNodeChildren(node, data);
169     }
170 
171     @Override
172     public Object visit(ASTRaiseStatement node, Object data) {
173 	return NumericConstants.ONE;
174     }
175 
176     @Override
177     public Object visit(ASTExpression node, Object data) {
178 
179 	// "For" update expressions do not count as separate lines of code
180 	if (node.jjtGetParent() instanceof ASTStatement) {
181 	    return NumericConstants.ZERO;
182 	}
183 
184 	return NumericConstants.ONE;
185     }
186 
187     @Override
188     public Object visit(ASTLabelledStatement node, Object data) {
189 	return countNodeChildren(node, data);
190     }
191 
192 
193 
194     @Override
195     public Object visit(ASTCaseWhenClause node, Object data) {
196 	return countNodeChildren(node, data);
197     }
198 
199     @Override
200     public Object[] getViolationParameters(DataPoint point) {
201         LOGGER.fine("Point score is " + point.getScore());
202 	return new String[] { String.valueOf((int) point.getScore()) };
203     }
204 }