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