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

This page was automatically generated by Maven