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.ast.ASTClassDeclaration; 6 import net.sourceforge.pmd.ast.ASTCompilationUnit; 7 import net.sourceforge.pmd.ast.ASTFieldDeclaration; 8 import net.sourceforge.pmd.ast.ASTFormalParameter; 9 import net.sourceforge.pmd.ast.ASTLocalVariableDeclaration; 10 import net.sourceforge.pmd.ast.ASTName; 11 import net.sourceforge.pmd.ast.ASTResultType; 12 import net.sourceforge.pmd.ast.ASTType; 13 import net.sourceforge.pmd.ast.SimpleNode; 14 15 import java.util.HashSet; 16 import java.util.Set; 17 18 19 /*** 20 * CouplingBetweenObjectsRule attempts to capture all unique Class attributes, 21 * local variables, and return types to determine how many objects a class is 22 * coupled to. This is only a guage and isn't a hard and fast rule. The threshold 23 * value is configurable and should be determined accordingly 24 * 25 * @since Feb 20, 2003 26 * @author aglover 27 * 28 */ 29 public class CouplingBetweenObjectsRule extends AbstractRule { 30 31 private String className; 32 private int couplingCount; 33 private Set typesFoundSoFar; 34 35 /*** 36 * handles the source file 37 * 38 * @return Object 39 * @param ASTCompilationUnit cu 40 * @param Object data 41 */ 42 public Object visit(ASTCompilationUnit cu, Object data) { 43 this.typesFoundSoFar = new HashSet(); 44 this.couplingCount = 0; 45 46 Object returnObj = cu.childrenAccept(this, data); 47 48 if (this.couplingCount > getIntProperty("threshold")) { 49 RuleContext ctx = (RuleContext) data; 50 ctx.getReport().addRuleViolation(createRuleViolation(ctx, cu.getBeginLine(), "A value of " + this.couplingCount + " may denote a high amount of coupling within the class")); 51 } 52 53 return returnObj; 54 } 55 56 /*** 57 * handles class declaration. I need this to capture class name. I think 58 * there is probably a better way to capture it; however, I don't know the 59 * framework well enough yet... 60 * 61 * @return Object 62 * @param ASTClassDeclaration node 63 * @param Object data 64 */ 65 public Object visit(ASTClassDeclaration node, Object data) { 66 SimpleNode firstStmt = (SimpleNode) node.jjtGetChild(0); 67 this.className = firstStmt.getImage(); 68 return super.visit(node, data); 69 } 70 71 /*** 72 * handles a return type of a method 73 * 74 * @return Object 75 * @param ASTResultType node 76 * @param Object data 77 */ 78 public Object visit(ASTResultType node, Object data) { 79 for (int x = 0; x < node.jjtGetNumChildren(); x++) { 80 SimpleNode tNode = (SimpleNode) node.jjtGetChild(x); 81 if (tNode instanceof ASTType) { 82 SimpleNode nameNode = (SimpleNode) tNode.jjtGetChild(0); 83 if (nameNode instanceof ASTName) { 84 this.checkVariableType(nameNode.getImage()); 85 } 86 } 87 } 88 return super.visit(node, data); 89 } 90 91 /*** 92 * handles a local variable found in a method block 93 * 94 * @return Object 95 * @param ASTLocalVariableDeclaration node 96 * @param Object data 97 */ 98 public Object visit(ASTLocalVariableDeclaration node, Object data) { 99 this.handleASTTypeChildren(node); 100 return super.visit(node, data); 101 } 102 103 /*** 104 * handles a method parameter 105 * 106 * @return Object 107 * @param ASTFormalParameter node 108 * @param Object data 109 */ 110 public Object visit(ASTFormalParameter node, Object data) { 111 this.handleASTTypeChildren(node); 112 return super.visit(node, data); 113 } 114 115 /*** 116 * handles a field declaration - i.e. an instance variable. Method doesn't care if variable 117 * is public/private/etc 118 * 119 * @return Object 120 * @param ASTFieldDeclaration node 121 * @param Object data 122 */ 123 public Object visit(ASTFieldDeclaration node, Object data) { 124 for (int x = 0; x < node.jjtGetNumChildren(); ++x) { 125 SimpleNode firstStmt = (SimpleNode) node.jjtGetChild(x); 126 if (firstStmt instanceof ASTType) { 127 ASTType tp = (ASTType) firstStmt; 128 SimpleNode nd = (SimpleNode) tp.jjtGetChild(0); 129 this.checkVariableType(nd.getImage()); 130 } 131 } 132 133 return super.visit(node, data); 134 } 135 136 /*** 137 * convience method to handle hiearchy. This is probably too much 138 * work and will go away once I figure out the framework 139 * 140 */ 141 private void handleASTTypeChildren(SimpleNode node) { 142 for (int x = 0; x < node.jjtGetNumChildren(); x++) { 143 SimpleNode sNode = (SimpleNode) node.jjtGetChild(x); 144 if (sNode instanceof ASTType) { 145 SimpleNode nameNode = (SimpleNode) sNode.jjtGetChild(0); 146 this.checkVariableType(nameNode.getImage()); 147 } 148 } 149 } 150 151 /*** 152 * performs a check on the variable and updates the couter. Counter is 153 * instance for a class and is reset upon new class scan. 154 * 155 * @param String variableType 156 */ 157 private void checkVariableType(String variableType) { 158 //if the field is of any type other than the class type 159 //increment the count 160 if (!this.className.equals(variableType) && (!this.filterTypes(variableType)) && !this.typesFoundSoFar.contains(variableType)) { 161 this.couplingCount++; 162 this.typesFoundSoFar.add(variableType); 163 } 164 } 165 166 /*** 167 * Filters variable type - we don't want primatives, wrappers, strings, etc. 168 * This needs more work. I'd like to filter out super types and perhaps interfaces 169 * 170 * @param String variableType 171 * @return boolean true if variableType is not what we care about 172 */ 173 private boolean filterTypes(String variableType) { 174 return variableType.startsWith("java.lang.") || (variableType.equals("String")) || filterPrimativesAndWrappers(variableType); 175 } 176 177 /*** 178 * @param String variableType 179 * @return boolean true if variableType is a primative or wrapper 180 */ 181 private boolean filterPrimativesAndWrappers(String variableType) { 182 return (variableType.equals("int") || variableType.equals("Integer") || variableType.equals("char") || variableType.equals("Character") || variableType.equalsIgnoreCase("double") || variableType.equalsIgnoreCase("long") || variableType.equalsIgnoreCase("short") || variableType.equalsIgnoreCase("float") || variableType.equalsIgnoreCase("byte") || variableType.equalsIgnoreCase("boolean")); 183 } 184 }

This page was automatically generated by Maven