View Javadoc
1 package net.sourceforge.pmd.rules; 2 3 import net.sourceforge.pmd.AbstractRule; 4 import net.sourceforge.pmd.RuleContext; 5 import net.sourceforge.pmd.RuleViolation; 6 import net.sourceforge.pmd.ast.ASTBlockStatement; 7 import net.sourceforge.pmd.ast.ASTConstructorDeclaration; 8 import net.sourceforge.pmd.ast.ASTForStatement; 9 import net.sourceforge.pmd.ast.ASTIfStatement; 10 import net.sourceforge.pmd.ast.ASTInterfaceDeclaration; 11 import net.sourceforge.pmd.ast.ASTMethodDeclaration; 12 import net.sourceforge.pmd.ast.ASTMethodDeclarator; 13 import net.sourceforge.pmd.ast.ASTSwitchLabel; 14 import net.sourceforge.pmd.ast.ASTSwitchStatement; 15 import net.sourceforge.pmd.ast.ASTUnmodifiedClassDeclaration; 16 import net.sourceforge.pmd.ast.ASTWhileStatement; 17 import net.sourceforge.pmd.ast.Node; 18 import net.sourceforge.pmd.ast.SimpleNode; 19 20 import java.text.MessageFormat; 21 import java.util.Stack; 22 23 /*** 24 * 25 * @author Donald A. Leckie 26 * @since January 14, 2003 27 * @version $Revision: 1.9 $, $Date: 2003/03/14 19:03:56 $ 28 */ 29 public class CyclomaticComplexityRule extends AbstractRule { 30 private Stack m_entryStack = new Stack(); 31 32 /*** 33 ************************************************************************** 34 * 35 * @param node 36 * @param data 37 * 38 * @return 39 */ 40 public Object visit(ASTIfStatement node, Object data) { 41 Entry entry = (Entry) m_entryStack.peek(); 42 entry.m_decisionPoints++; 43 super.visit(node, data); 44 45 return data; 46 } 47 48 /*** 49 ************************************************************************** 50 * 51 * @param node 52 * @param data 53 * 54 * @return 55 */ 56 public Object visit(ASTForStatement node, Object data) { 57 Entry entry = (Entry) m_entryStack.peek(); 58 entry.m_decisionPoints++; 59 super.visit(node, data); 60 61 return data; 62 } 63 64 /*** 65 ************************************************************************** 66 * 67 * @param node 68 * @param data 69 * 70 * @return 71 */ 72 public Object visit(ASTSwitchStatement node, Object data) { 73 Entry entry = (Entry) m_entryStack.peek(); 74 75 int childCount = node.jjtGetNumChildren(); 76 int lastIndex = childCount - 1; 77 78 for (int n = 0; n < lastIndex; n++) { 79 Node childNode = node.jjtGetChild(n); 80 81 if (childNode instanceof ASTSwitchLabel) { 82 childNode = node.jjtGetChild(n + 1); 83 84 if (childNode instanceof ASTBlockStatement) { 85 entry.m_decisionPoints++; 86 } 87 } 88 } 89 90 super.visit(node, data); 91 92 return data; 93 } 94 95 /*** 96 ************************************************************************** 97 * 98 * @param node 99 * @param data 100 * 101 * @return 102 */ 103 public Object visit(ASTWhileStatement node, Object data) { 104 Entry entry = (Entry) m_entryStack.peek(); 105 entry.m_decisionPoints++; 106 super.visit(node, data); 107 108 return data; 109 } 110 111 /*** 112 ************************************************************************** 113 * 114 * @param node 115 * @param data 116 * 117 * @return 118 */ 119 public Object visit(ASTUnmodifiedClassDeclaration node, Object data) { 120 m_entryStack.push(new Entry(node)); 121 super.visit(node, data); 122 Entry classEntry = (Entry) m_entryStack.pop(); 123 double decisionPoints = (double) classEntry.m_decisionPoints; 124 double methodCount = (double) classEntry.m_methodCount; 125 int complexityAverage = (methodCount == 0) ? 1 : (int) (Math.rint(decisionPoints / methodCount)); 126 127 if ((complexityAverage >= getIntProperty("reportLevel")) || (classEntry.m_highestDecisionPoints >= getIntProperty("reportLevel"))) { 128 // The {0} "{1}" has a cyclomatic complexity of {2}. 129 RuleContext ruleContext = (RuleContext) data; 130 String template = getMessage(); 131 String className = node.getImage(); 132 String complexityHighest = String.valueOf(classEntry.m_highestDecisionPoints); 133 String complexity = String.valueOf(complexityAverage) + " (Highest = " + complexityHighest + ")"; 134 String[] args = {"class", className, complexity}; 135 String message = MessageFormat.format(template, args); 136 int lineNumber = node.getBeginLine(); 137 RuleViolation ruleViolation = createRuleViolation(ruleContext, lineNumber, message); 138 ruleContext.getReport().addRuleViolation(ruleViolation); 139 } 140 141 return data; 142 } 143 144 /*** 145 ************************************************************************** 146 * 147 * @param node 148 * @param data 149 * 150 * @return 151 */ 152 public Object visit(ASTMethodDeclaration node, Object data) { 153 Node parentNode = node.jjtGetParent(); 154 155 while (parentNode != null) { 156 if (parentNode instanceof ASTInterfaceDeclaration) { 157 return data; 158 } 159 160 parentNode = parentNode.jjtGetParent(); 161 } 162 163 m_entryStack.push(new Entry(node)); 164 super.visit(node, data); 165 Entry methodEntry = (Entry) m_entryStack.pop(); 166 int methodDecisionPoints = methodEntry.m_decisionPoints; 167 Entry classEntry = (Entry) m_entryStack.peek(); 168 classEntry.m_methodCount++; 169 classEntry.m_decisionPoints += methodDecisionPoints; 170 171 if (methodDecisionPoints > classEntry.m_highestDecisionPoints) { 172 classEntry.m_highestDecisionPoints = methodDecisionPoints; 173 } 174 175 ASTMethodDeclarator methodDeclarator = null; 176 177 for (int n = 0; n < node.jjtGetNumChildren(); n++) { 178 Node childNode = node.jjtGetChild(n); 179 180 if (childNode instanceof ASTMethodDeclarator) { 181 methodDeclarator = (ASTMethodDeclarator) childNode; 182 break; 183 } 184 } 185 186 if (methodEntry.m_decisionPoints >= getIntProperty("reportLevel")) { 187 // The {0} "{1}" has a cyclomatic complexity of {2}. 188 RuleContext ruleContext = (RuleContext) data; 189 String template = getMessage(); 190 String methodName = (methodDeclarator == null) ? "" : methodDeclarator.getImage(); 191 String complexity = String.valueOf(methodEntry.m_decisionPoints); 192 String[] args = {"method", methodName, complexity}; 193 String message = MessageFormat.format(template, args); 194 int lineNumber = node.getBeginLine(); 195 RuleViolation ruleViolation = createRuleViolation(ruleContext, lineNumber, message); 196 ruleContext.getReport().addRuleViolation(ruleViolation); 197 } 198 199 return data; 200 } 201 202 /*** 203 ************************************************************************** 204 * 205 * @param node 206 * @param data 207 * 208 * @return 209 */ 210 public Object visit(ASTConstructorDeclaration node, Object data) { 211 m_entryStack.push(new Entry(node)); 212 super.visit(node, data); 213 Entry constructorEntry = (Entry) m_entryStack.pop(); 214 int constructorDecisionPointCount = constructorEntry.m_decisionPoints; 215 Entry classEntry = (Entry) m_entryStack.peek(); 216 classEntry.m_methodCount++; 217 classEntry.m_decisionPoints += constructorDecisionPointCount; 218 219 if (constructorDecisionPointCount > classEntry.m_highestDecisionPoints) { 220 classEntry.m_highestDecisionPoints = constructorDecisionPointCount; 221 } 222 223 if (constructorEntry.m_decisionPoints >= getIntProperty("reportLevel")) { 224 // The {0} "{1}" has a cyclomatic complexity of {2}. 225 RuleContext ruleContext = (RuleContext) data; 226 String template = getMessage(); 227 String constructorName = classEntry.m_node.getImage(); 228 String complexity = String.valueOf(constructorDecisionPointCount); 229 String[] args = {"constructor", constructorName, complexity}; 230 String message = MessageFormat.format(template, args); 231 int lineNumber = node.getBeginLine(); 232 RuleViolation ruleViolation = createRuleViolation(ruleContext, lineNumber, message); 233 ruleContext.getReport().addRuleViolation(ruleViolation); 234 } 235 236 return data; 237 } 238 239 /*** 240 *************************************************************************** 241 *************************************************************************** 242 *************************************************************************** 243 */ 244 private class Entry { 245 // ASTUnmodifedClassDeclaration or ASTMethodDeclarator or ASTConstructorDeclaration 246 private SimpleNode m_node; 247 public int m_decisionPoints = 1; 248 public int m_highestDecisionPoints; 249 public int m_methodCount; 250 251 /*** 252 *********************************************************************** 253 * 254 * @param node 255 */ 256 private Entry(SimpleNode node) { 257 m_node = node; 258 } 259 } 260 }

This page was automatically generated by Maven