1 4 package net.sourceforge.pmd.rules; 5 6 import net.sourceforge.pmd.AbstractRule; 7 import net.sourceforge.pmd.PropertyDescriptor; 8 import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration; 9 import net.sourceforge.pmd.ast.ASTClassOrInterfaceType; 10 import net.sourceforge.pmd.ast.ASTCompilationUnit; 11 import net.sourceforge.pmd.ast.ASTFieldDeclaration; 12 import net.sourceforge.pmd.ast.ASTFormalParameter; 13 import net.sourceforge.pmd.ast.ASTLocalVariableDeclaration; 14 import net.sourceforge.pmd.ast.ASTReferenceType; 15 import net.sourceforge.pmd.ast.ASTResultType; 16 import net.sourceforge.pmd.ast.ASTType; 17 import net.sourceforge.pmd.ast.SimpleNode; 18 import net.sourceforge.pmd.properties.IntegerProperty; 19 import net.sourceforge.pmd.symboltable.ClassScope; 20 21 import java.util.HashSet ; 22 import java.util.Map ; 23 import java.util.Set ; 24 25 26 35 public class CouplingBetweenObjects extends AbstractRule { 36 37 private int couplingCount; 38 private Set typesFoundSoFar; 39 40 private static final PropertyDescriptor thresholdDescriptor = new IntegerProperty( 41 "threshold", "Coupling threshold value", 2, 1.0f 42 ); 43 44 private static final Map propertyDescriptorsByName = asFixedMap(thresholdDescriptor); 45 46 47 public Object visit(ASTCompilationUnit cu, Object data) { 48 typesFoundSoFar = new HashSet (); 49 couplingCount = 0; 50 51 Object returnObj = cu.childrenAccept(this, data); 52 53 if (couplingCount > getIntProperty(thresholdDescriptor)) { 54 addViolation(data, cu, "A value of " + couplingCount + " may denote a high amount of coupling within the class"); 55 } 56 57 return returnObj; 58 } 59 60 public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { 61 if (node.isInterface()) { 62 return data; 63 } 64 return super.visit(node, data); 65 } 66 67 public Object visit(ASTResultType node, Object data) { 68 for (int x = 0; x < node.jjtGetNumChildren(); x++) { 69 SimpleNode tNode = (SimpleNode) node.jjtGetChild(x); 70 if (tNode instanceof ASTType) { 71 SimpleNode reftypeNode = (SimpleNode) tNode.jjtGetChild(0); 72 if (reftypeNode instanceof ASTReferenceType) { 73 SimpleNode classOrIntType = (SimpleNode) reftypeNode.jjtGetChild(0); 74 if (classOrIntType instanceof ASTClassOrInterfaceType) { 75 SimpleNode nameNode = classOrIntType; 76 this.checkVariableType(nameNode, nameNode.getImage()); 77 } 78 } 79 } 80 } 81 return super.visit(node, data); 82 } 83 84 public Object visit(ASTLocalVariableDeclaration node, Object data) { 85 handleASTTypeChildren(node); 86 return super.visit(node, data); 87 } 88 89 public Object visit(ASTFormalParameter node, Object data) { 90 handleASTTypeChildren(node); 91 return super.visit(node, data); 92 } 93 94 public Object visit(ASTFieldDeclaration node, Object data) { 95 for (int x = 0; x < node.jjtGetNumChildren(); ++x) { 96 SimpleNode firstStmt = (SimpleNode) node.jjtGetChild(x); 97 if (firstStmt instanceof ASTType) { 98 ASTType tp = (ASTType) firstStmt; 99 SimpleNode nd = (SimpleNode) tp.jjtGetChild(0); 100 checkVariableType(nd, nd.getImage()); 101 } 102 } 103 104 return super.visit(node, data); 105 } 106 107 111 private void handleASTTypeChildren(SimpleNode node) { 112 for (int x = 0; x < node.jjtGetNumChildren(); x++) { 113 SimpleNode sNode = (SimpleNode) node.jjtGetChild(x); 114 if (sNode instanceof ASTType) { 115 SimpleNode nameNode = (SimpleNode) sNode.jjtGetChild(0); 116 checkVariableType(nameNode, nameNode.getImage()); 117 } 118 } 119 } 120 121 127 private void checkVariableType(SimpleNode nameNode, String variableType) { 128 if (nameNode.getParentsOfType(ASTClassOrInterfaceDeclaration.class).isEmpty()) { 130 return; 131 } 132 ClassScope clzScope = nameNode.getScope().getEnclosingClassScope(); 135 if (!clzScope.getClassName().equals(variableType) && (!this.filterTypes(variableType)) && !this.typesFoundSoFar.contains(variableType)) { 136 couplingCount++; 137 typesFoundSoFar.add(variableType); 138 } 139 } 140 141 148 private boolean filterTypes(String variableType) { 149 return variableType != null && (variableType.startsWith("java.lang.") || (variableType.equals("String")) || filterPrimitivesAndWrappers(variableType)); 150 } 151 152 156 private boolean filterPrimitivesAndWrappers(String variableType) { 157 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")); 158 } 159 160 163 protected Map propertiesByName() { 164 return propertyDescriptorsByName; 165 } 166 } 167 | Popular Tags |