Clover coverage report - PMD - 3.9
Coverage timestamp: Tue Dec 19 2006 09:38:44 EST
file stats: LOC: 166   Methods: 11
NCLOC: 104   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
CouplingBetweenObjects.java 45.8% 59.1% 54.5% 54.4%
coverage coverage
 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.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    /**
 27    * CouplingBetweenObjects attempts to capture all unique Class attributes,
 28    * local variables, and return types to determine how many objects a class is
 29    * coupled to. This is only a guage and isn't a hard and fast rule. The threshold
 30    * value is configurable and should be determined accordingly
 31    *
 32    * @author aglover
 33    * @since Feb 20, 2003
 34    */
 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  3 public Object visit(ASTCompilationUnit cu, Object data) {
 48  3 typesFoundSoFar = new HashSet();
 49  3 couplingCount = 0;
 50   
 51  3 Object returnObj = cu.childrenAccept(this, data);
 52   
 53  3 if (couplingCount > getIntProperty(thresholdDescriptor)) {
 54  1 addViolation(data, cu, "A value of " + couplingCount + " may denote a high amount of coupling within the class");
 55    }
 56   
 57  3 return returnObj;
 58    }
 59   
 60  3 public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
 61  3 if (node.isInterface()) {
 62  1 return data;
 63    }
 64  2 return super.visit(node, data);
 65    }
 66   
 67  3 public Object visit(ASTResultType node, Object data) {
 68  3 for (int x = 0; x < node.jjtGetNumChildren(); x++) {
 69  3 SimpleNode tNode = (SimpleNode) node.jjtGetChild(x);
 70  3 if (tNode instanceof ASTType) {
 71  3 SimpleNode reftypeNode = (SimpleNode) tNode.jjtGetChild(0);
 72  3 if (reftypeNode instanceof ASTReferenceType) {
 73  3 SimpleNode classOrIntType = (SimpleNode) reftypeNode.jjtGetChild(0);
 74  3 if (classOrIntType instanceof ASTClassOrInterfaceType) {
 75  3 SimpleNode nameNode = classOrIntType;
 76  3 this.checkVariableType(nameNode, nameNode.getImage());
 77    }
 78    }
 79    }
 80    }
 81  3 return super.visit(node, data);
 82    }
 83   
 84  0 public Object visit(ASTLocalVariableDeclaration node, Object data) {
 85  0 handleASTTypeChildren(node);
 86  0 return super.visit(node, data);
 87    }
 88   
 89  0 public Object visit(ASTFormalParameter node, Object data) {
 90  0 handleASTTypeChildren(node);
 91  0 return super.visit(node, data);
 92    }
 93   
 94  0 public Object visit(ASTFieldDeclaration node, Object data) {
 95  0 for (int x = 0; x < node.jjtGetNumChildren(); ++x) {
 96  0 SimpleNode firstStmt = (SimpleNode) node.jjtGetChild(x);
 97  0 if (firstStmt instanceof ASTType) {
 98  0 ASTType tp = (ASTType) firstStmt;
 99  0 SimpleNode nd = (SimpleNode) tp.jjtGetChild(0);
 100  0 checkVariableType(nd, nd.getImage());
 101    }
 102    }
 103   
 104  0 return super.visit(node, data);
 105    }
 106   
 107    /**
 108    * convience method to handle hierarchy. This is probably too much
 109    * work and will go away once I figure out the framework
 110    */
 111  0 private void handleASTTypeChildren(SimpleNode node) {
 112  0 for (int x = 0; x < node.jjtGetNumChildren(); x++) {
 113  0 SimpleNode sNode = (SimpleNode) node.jjtGetChild(x);
 114  0 if (sNode instanceof ASTType) {
 115  0 SimpleNode nameNode = (SimpleNode) sNode.jjtGetChild(0);
 116  0 checkVariableType(nameNode, nameNode.getImage());
 117    }
 118    }
 119    }
 120   
 121    /**
 122    * performs a check on the variable and updates the counter. Counter is
 123    * instance for a class and is reset upon new class scan.
 124    *
 125    * @param String variableType
 126    */
 127  3 private void checkVariableType(SimpleNode nameNode, String variableType) {
 128    // TODO - move this into the symbol table somehow?
 129  3 if (nameNode.getParentsOfType(ASTClassOrInterfaceDeclaration.class).isEmpty()) {
 130  0 return;
 131    }
 132    //if the field is of any type other than the class type
 133    //increment the count
 134  3 ClassScope clzScope = nameNode.getScope().getEnclosingClassScope();
 135  3 if (!clzScope.getClassName().equals(variableType) && (!this.filterTypes(variableType)) && !this.typesFoundSoFar.contains(variableType)) {
 136  3 couplingCount++;
 137  3 typesFoundSoFar.add(variableType);
 138    }
 139    }
 140   
 141    /**
 142    * Filters variable type - we don't want primatives, wrappers, strings, etc.
 143    * This needs more work. I'd like to filter out super types and perhaps interfaces
 144    *
 145    * @param String variableType
 146    * @return boolean true if variableType is not what we care about
 147    */
 148  3 private boolean filterTypes(String variableType) {
 149  3 return variableType != null && (variableType.startsWith("java.lang.") || (variableType.equals("String")) || filterPrimitivesAndWrappers(variableType));
 150    }
 151   
 152    /**
 153    * @param String variableType
 154    * @return boolean true if variableType is a primative or wrapper
 155    */
 156  3 private boolean filterPrimitivesAndWrappers(String variableType) {
 157  3 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    /**
 161    * @return Map
 162    */
 163  0 protected Map propertiesByName() {
 164  0 return propertyDescriptorsByName;
 165    }
 166    }