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

This page was automatically generated by Maven