Clover coverage report - PMD - 3.9 Coverage timestamp: Tue Dec 19 2006 09:38:44 EST FRAMES NO FRAMES |
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% |

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 |  | }