Clover coverage report - PMD - 3.7
Coverage timestamp: Wed May 31 2006 09:25:59 EDT

file stats: | LOC: | 149 |  | Methods: | 10
| NCLOC: | 94 |  | Classes: | 1

Source file | Conditionals | Statements | Methods | TOTAL

CouplingBetweenObjects.java

45.8%

60.5%

60%

55.8%

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