Clover coverage report - PMD - 3.9 Coverage timestamp: Tue Dec 19 2006 09:38:44 EST FRAMES NO FRAMES |
file stats: | LOC: | 237 |  | Methods: | 16
| NCLOC: | 188 |  | Classes: | 2
Source file | Conditionals | Statements | Methods | TOTAL
CyclomaticComplexity.java | 62.5% | 77.9% | 75% | 74.1% |

1 |  | /**
2 |  | * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 |  | */
4 |  | package net.sourceforge.pmd.rules;
5 |  |
6 |  | import java.util.Stack;
7 |  |
8 |  | import net.sourceforge.pmd.AbstractRule;
9 |  | import net.sourceforge.pmd.ast.ASTBlockStatement;
10 |  | import net.sourceforge.pmd.ast.ASTCatchStatement;
11 |  | import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
12 |  | import net.sourceforge.pmd.ast.ASTCompilationUnit;
13 |  | import net.sourceforge.pmd.ast.ASTConditionalExpression;
14 |  | import net.sourceforge.pmd.ast.ASTConstructorDeclaration;
15 |  | import net.sourceforge.pmd.ast.ASTDoStatement;
16 |  | import net.sourceforge.pmd.ast.ASTEnumDeclaration;
17 |  | import net.sourceforge.pmd.ast.ASTExpression;
18 |  | import net.sourceforge.pmd.ast.ASTForStatement;
19 |  | import net.sourceforge.pmd.ast.ASTIfStatement;
20 |  | import net.sourceforge.pmd.ast.ASTMethodDeclaration;
21 |  | import net.sourceforge.pmd.ast.ASTMethodDeclarator;
22 |  | import net.sourceforge.pmd.ast.ASTSwitchLabel;
23 |  | import net.sourceforge.pmd.ast.ASTSwitchStatement;
24 |  | import net.sourceforge.pmd.ast.ASTWhileStatement;
25 |  | import net.sourceforge.pmd.ast.Node;
26 |  | import net.sourceforge.pmd.ast.SimpleNode;
27 |  | import net.sourceforge.pmd.rules.design.NpathComplexity;
28 |  |
29 |  | /**
30 |  | * @author Donald A. Leckie
31 |  | * @version $Revision: 1.18 $, $Date: 2006/10/16 13:25:23 $
32 |  | * @since January 14, 2003
33 |  | */
34 |  | public class CyclomaticComplexity extends AbstractRule {
35 |  |
36 |  | private int reportLevel;
37 |  |
38 |  | private static class Entry {
39 |  | private SimpleNode node;
40 |  | private int decisionPoints = 1;
41 |  | public int highestDecisionPoints;
42 |  | public int methodCount;
43 |  |
44 | 8 | private Entry(SimpleNode node) {
45 | 8 | this.node = node;
46 |  | }
47 |  |
48 | 3 | public void bumpDecisionPoints() {
49 | 3 | decisionPoints++;
50 |  | }
51 |  |
52 | 11 | public void bumpDecisionPoints(int size) {
53 | 11 | decisionPoints += size;
54 |  | }
55 |  |
56 | 7 | public int getComplexityAverage() {
57 | 7 | return ( (double) methodCount == 0 ) ? 1
58 |  | : (int) ( Math.rint( (double) decisionPoints / (double) methodCount ) );
59 |  | }
60 |  | }
61 |  |
62 |  | private Stack entryStack = new Stack();
63 |  |
64 | 4 | public Object visit(ASTCompilationUnit node, Object data) {
65 | 4 | reportLevel = getIntProperty( "reportLevel" );
66 | 4 | super.visit( node, data );
67 | 4 | return data;
68 |  | }
69 |  |
70 | 5 | public Object visit(ASTIfStatement node, Object data) {
71 | 5 | int boolCompIf = NpathComplexity.sumExpressionComplexity( (ASTExpression) node.getFirstChildOfType( ASTExpression.class ) );
72 |  | // If statement always has a complexity of at least 1
73 | 5 | boolCompIf++;
74 |  |
75 | 5 | ( (Entry) entryStack.peek() ).bumpDecisionPoints( boolCompIf );
76 | 5 | super.visit( node, data );
77 | 5 | return data;
78 |  | }
79 |  |
80 | 0 | public Object visit(ASTCatchStatement node, Object data) {
81 | 0 | ( (Entry) entryStack.peek() ).bumpDecisionPoints();
82 | 0 | super.visit( node, data );
83 | 0 | return data;
84 |  | }
85 |  |
86 | 1 | public Object visit(ASTForStatement node, Object data) {
87 | 1 | int boolCompFor = NpathComplexity.sumExpressionComplexity( (ASTExpression) node.getFirstChildOfType( ASTExpression.class ) );
88 |  | // For statement always has a complexity of at least 1
89 | 1 | boolCompFor++;
90 |  |
91 | 1 | ( (Entry) entryStack.peek() ).bumpDecisionPoints( boolCompFor );
92 | 1 | super.visit( node, data );
93 | 1 | return data;
94 |  | }
95 |  |
96 | 0 | public Object visit(ASTDoStatement node, Object data) {
97 | 0 | int boolCompDo = NpathComplexity.sumExpressionComplexity( (ASTExpression) node.getFirstChildOfType( ASTExpression.class ) );
98 |  | // Do statement always has a complexity of at least 1
99 | 0 | boolCompDo++;
100 |  |
101 | 0 | ( (Entry) entryStack.peek() ).bumpDecisionPoints( boolCompDo );
102 | 0 | super.visit( node, data );
103 | 0 | return data;
104 |  | }
105 |  |
106 | 1 | public Object visit(ASTSwitchStatement node, Object data) {
107 | 1 | Entry entry = (Entry) entryStack.peek();
108 |  |
109 | 1 | int boolCompSwitch = NpathComplexity.sumExpressionComplexity( (ASTExpression) node.getFirstChildOfType( ASTExpression.class ) );
110 | 1 | entry.bumpDecisionPoints( boolCompSwitch );
111 |  |
112 | 1 | int childCount = node.jjtGetNumChildren();
113 | 1 | int lastIndex = childCount - 1;
114 | 1 | for ( int n = 0; n < lastIndex; n++ ) {
115 | 12 | Node childNode = node.jjtGetChild( n );
116 | 12 | if ( childNode instanceof ASTSwitchLabel ) {
117 |  | // default is generally not considered a decision (same as "else")
118 | 4 | ASTSwitchLabel sl = (ASTSwitchLabel) childNode;
119 | 4 | if ( !sl.isDefault() ) {
120 | 3 | childNode = node.jjtGetChild( n + 1 );
121 | 3 | if ( childNode instanceof ASTBlockStatement ) {
122 | 3 | entry.bumpDecisionPoints();
123 |  | }
124 |  | }
125 |  | }
126 |  | }
127 | 1 | super.visit( node, data );
128 | 1 | return data;
129 |  | }
130 |  |
131 | 1 | public Object visit(ASTWhileStatement node, Object data) {
132 | 1 | int boolCompWhile = NpathComplexity.sumExpressionComplexity( (ASTExpression) node.getFirstChildOfType( ASTExpression.class ) );
133 |  | // While statement always has a complexity of at least 1
134 | 1 | boolCompWhile++;
135 |  |
136 | 1 | ( (Entry) entryStack.peek() ).bumpDecisionPoints( boolCompWhile );
137 | 1 | super.visit( node, data );
138 | 1 | return data;
139 |  | }
140 |  |
141 | 0 | public Object visit(ASTConditionalExpression node, Object data) {
142 | 0 | if ( node.isTernary() ) {
143 | 0 | int boolCompTern = NpathComplexity.sumExpressionComplexity( (ASTExpression) node.getFirstChildOfType( ASTExpression.class ) );
144 |  | // Ternary statement always has a complexity of at least 1
145 | 0 | boolCompTern++;
146 |  |
147 | 0 | ( (Entry) entryStack.peek() ).bumpDecisionPoints( boolCompTern );
148 | 0 | super.visit( node, data );
149 |  | }
150 | 0 | return data;
151 |  | }
152 |  |
153 | 4 | public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
154 | 4 | if ( node.isInterface() ) {
155 | 0 | return data;
156 |  | }
157 |  |
158 | 4 | entryStack.push( new Entry( node ) );
159 | 4 | super.visit( node, data );
160 | 4 | Entry classEntry = (Entry) entryStack.pop();
161 | 4 | if ( ( classEntry.getComplexityAverage() >= reportLevel )
162 |  | || ( classEntry.highestDecisionPoints >= reportLevel ) ) {
163 | 3 | addViolation( data, node, new String[] {
164 |  | "class",
165 |  | node.getImage(),
166 |  | classEntry.getComplexityAverage() + " (Highest = "
167 |  | + classEntry.highestDecisionPoints + ')' } );
168 |  | }
169 | 4 | return data;
170 |  | }
171 |  |
172 | 3 | public Object visit(ASTMethodDeclaration node, Object data) {
173 | 3 | entryStack.push( new Entry( node ) );
174 | 3 | super.visit( node, data );
175 | 3 | Entry methodEntry = (Entry) entryStack.pop();
176 | 3 | int methodDecisionPoints = methodEntry.decisionPoints;
177 | 3 | Entry classEntry = (Entry) entryStack.peek();
178 | 3 | classEntry.methodCount++;
179 | 3 | classEntry.bumpDecisionPoints( methodDecisionPoints );
180 |  |
181 | 3 | if ( methodDecisionPoints > classEntry.highestDecisionPoints ) {
182 | 3 | classEntry.highestDecisionPoints = methodDecisionPoints;
183 |  | }
184 |  |
185 | 3 | ASTMethodDeclarator methodDeclarator = null;
186 | 6 | for ( int n = 0; n < node.jjtGetNumChildren(); n++ ) {
187 | 6 | Node childNode = node.jjtGetChild( n );
188 | 6 | if ( childNode instanceof ASTMethodDeclarator ) {
189 | 3 | methodDeclarator = (ASTMethodDeclarator) childNode;
190 | 3 | break;
191 |  | }
192 |  | }
193 |  |
194 | 3 | if ( methodEntry.decisionPoints >= reportLevel ) {
195 | 2 | addViolation( data, node, new String[] { "method",
196 | 2 | ( methodDeclarator == null ) ? "" : methodDeclarator.getImage(),
197 |  | String.valueOf( methodEntry.decisionPoints ) } );
198 |  | }
199 |  |
200 | 3 | return data;
201 |  | }
202 |  |
203 | 0 | public Object visit(ASTEnumDeclaration node, Object data) {
204 | 0 | entryStack.push( new Entry( node ) );
205 | 0 | super.visit( node, data );
206 | 0 | Entry classEntry = (Entry) entryStack.pop();
207 | 0 | if ( ( classEntry.getComplexityAverage() >= reportLevel )
208 |  | || ( classEntry.highestDecisionPoints >= reportLevel ) ) {
209 | 0 | addViolation( data, node, new String[] {
210 |  | "class",
211 |  | node.getImage(),
212 |  | classEntry.getComplexityAverage() + "(Highest = "
213 |  | + classEntry.highestDecisionPoints + ')' } );
214 |  | }
215 | 0 | return data;
216 |  | }
217 |  |
218 | 1 | public Object visit(ASTConstructorDeclaration node, Object data) {
219 | 1 | entryStack.push( new Entry( node ) );
220 | 1 | super.visit( node, data );
221 | 1 | Entry constructorEntry = (Entry) entryStack.pop();
222 | 1 | int constructorDecisionPointCount = constructorEntry.decisionPoints;
223 | 1 | Entry classEntry = (Entry) entryStack.peek();
224 | 1 | classEntry.methodCount++;
225 | 1 | classEntry.decisionPoints += constructorDecisionPointCount;
226 | 1 | if ( constructorDecisionPointCount > classEntry.highestDecisionPoints ) {
227 | 1 | classEntry.highestDecisionPoints = constructorDecisionPointCount;
228 |  | }
229 | 1 | if ( constructorEntry.decisionPoints >= reportLevel ) {
230 | 1 | addViolation( data, node, new String[] { "constructor",
231 |  | classEntry.node.getImage(),
232 |  | String.valueOf( constructorDecisionPointCount ) } );
233 |  | }
234 | 1 | return data;
235 |  | }
236 |  |
237 |  | }