Clover coverage report - PMD - 3.9 Coverage timestamp: Tue Dec 19 2006 09:38:44 EST FRAMES NO FRAMES |
file stats: | LOC: | 145 |  | Methods: | 4
| NCLOC: | 100 |  | Classes: | 1
Source file | Conditionals | Statements | Methods | TOTAL
CloseResource.java | 83.3% | 97.8% | 75% | 91.3% |

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.ASTBlock;
9 |  | import net.sourceforge.pmd.ast.ASTClassOrInterfaceType;
10 |  | import net.sourceforge.pmd.ast.ASTCompilationUnit;
11 |  | import net.sourceforge.pmd.ast.ASTLocalVariableDeclaration;
12 |  | import net.sourceforge.pmd.ast.ASTMethodDeclaration;
13 |  | import net.sourceforge.pmd.ast.ASTName;
14 |  | import net.sourceforge.pmd.ast.ASTReferenceType;
15 |  | import net.sourceforge.pmd.ast.ASTTryStatement;
16 |  | import net.sourceforge.pmd.ast.ASTType;
17 |  | import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
18 |  | import net.sourceforge.pmd.ast.Node;
19 |  | import net.sourceforge.pmd.properties.StringProperty;
20 |  |
21 |  | import java.util.ArrayList;
22 |  | import java.util.HashSet;
23 |  | import java.util.Iterator;
24 |  | import java.util.List;
25 |  | import java.util.Map;
26 |  | import java.util.Set;
27 |  | import java.util.StringTokenizer;
28 |  |
29 |  | /**
30 |  | * Makes sure you close your database connections. It does this by
31 |  | * looking for code patterned like this:
32 |  | * <pre>
33 |  | * Connection c = X;
34 |  | * try {
35 |  | * // do stuff, and maybe catch something
36 |  | * } finally {
37 |  | * c.close();
38 |  | * }
39 |  | * </pre>
40 |  | */
41 |  | public class CloseResource extends AbstractRule {
42 |  |
43 |  | private Set types = new HashSet();
44 |  |
45 |  |
46 |  | private Set closeTargets = new HashSet();
47 |  | private static final PropertyDescriptor closeTargetsDescriptor = new StringProperty("closeTargets",
48 |  | "Methods which may close this resource", "", 1.0f);
49 |  |
50 |  | private static final PropertyDescriptor typesDescriptor = new StringProperty("types",
51 |  | "Types that are affected by this rule", "", 2.0f);
52 |  |
53 |  | private static final Map propertyDescriptorsByName = asFixedMap(new PropertyDescriptor[] { typesDescriptor, closeTargetsDescriptor });
54 |  |
55 | 0 | protected Map propertiesByName() {
56 | 0 | return propertyDescriptorsByName;
57 |  | };
58 |  |
59 | 8 | public Object visit(ASTCompilationUnit node, Object data) {
60 | 8 | if (closeTargets.isEmpty() && getStringProperty(closeTargetsDescriptor) != null) {
61 | 8 | for (StringTokenizer st = new StringTokenizer(getStringProperty(closeTargetsDescriptor), ","); st.hasMoreTokens();) {
62 | 3 | closeTargets.add(st.nextToken());
63 |  | }
64 |  | }
65 | 8 | if (types.isEmpty() && getStringProperty(typesDescriptor) != null) {
66 | 4 | for (StringTokenizer st = new StringTokenizer(getStringProperty(typesDescriptor), ","); st.hasMoreTokens();) {
67 | 10 | types.add(st.nextToken());
68 |  | }
69 |  | }
70 | 8 | return super.visit(node, data);
71 |  | }
72 |  |
73 | 8 | public Object visit(ASTMethodDeclaration node, Object data) {
74 | 8 | List vars = node.findChildrenOfType(ASTLocalVariableDeclaration.class);
75 | 8 | List ids = new ArrayList();
76 |  |
77 |  | // find all variable references to Connection objects
78 | 8 | for (Iterator it = vars.iterator(); it.hasNext();) {
79 | 12 | ASTLocalVariableDeclaration var = (ASTLocalVariableDeclaration) it.next();
80 | 12 | ASTType type = var.getTypeNode();
81 |  |
82 | 12 | if (type.jjtGetChild(0) instanceof ASTReferenceType) {
83 | 12 | ASTReferenceType ref = (ASTReferenceType) type.jjtGetChild(0);
84 | 12 | if (ref.jjtGetChild(0) instanceof ASTClassOrInterfaceType) {
85 | 12 | ASTClassOrInterfaceType clazz = (ASTClassOrInterfaceType) ref.jjtGetChild(0);
86 | 12 | if (types.contains(clazz.getImage())) {
87 | 10 | ASTVariableDeclaratorId id = (ASTVariableDeclaratorId) var.jjtGetChild(1).jjtGetChild(0);
88 | 10 | ids.add(id);
89 |  | }
90 |  | }
91 |  | }
92 |  | }
93 |  |
94 |  | // if there are connections, ensure each is closed.
95 | 8 | for (int i = 0; i < ids.size(); i++) {
96 | 10 | ASTVariableDeclaratorId x = (ASTVariableDeclaratorId) ids.get(i);
97 | 10 | ensureClosed((ASTLocalVariableDeclaration) x.jjtGetParent().jjtGetParent(), x, data);
98 |  | }
99 | 8 | return data;
100 |  | }
101 |  |
102 | 10 | private void ensureClosed(ASTLocalVariableDeclaration var,
103 |  | ASTVariableDeclaratorId id, Object data) {
104 |  | // What are the chances of a Connection being instantiated in a
105 |  | // for-loop init block? Anyway, I'm lazy!
106 | 10 | String target = id.getImage() + ".close";
107 | 10 | Node n = var;
108 |  |
109 | ? | while (!((n = n.jjtGetParent()) instanceof ASTBlock)) ;
110 |  |
111 | 10 | ASTBlock top = (ASTBlock) n;
112 |  |
113 | 10 | List tryblocks = new ArrayList();
114 | 10 | top.findChildrenOfType(ASTTryStatement.class, tryblocks, true);
115 |  |
116 | 10 | boolean closed = false;
117 |  |
118 |  | // look for try blocks below the line the variable was
119 |  | // introduced and make sure there is a .close call in a finally
120 |  | // block.
121 | 10 | for (Iterator it = tryblocks.iterator(); it.hasNext();) {
122 | 9 | ASTTryStatement t = (ASTTryStatement) it.next();
123 |  |
124 | 9 | if ((t.getBeginLine() > id.getBeginLine()) && (t.hasFinally())) {
125 | 6 | ASTBlock f = (ASTBlock) t.getFinally().jjtGetChild(0);
126 | 6 | List names = new ArrayList();
127 | 6 | f.findChildrenOfType(ASTName.class, names, true);
128 | 6 | for (Iterator it2 = names.iterator(); it2.hasNext();) {
129 | 19 | String name = ((ASTName) it2.next()).getImage();
130 | 19 | if (name.equals(target) || closeTargets.contains(name)) {
131 | 4 | closed = true;
132 |  | }
133 |  | }
134 |  | }
135 |  | }
136 |  |
137 |  | // if all is not well, complain
138 | 10 | if (!closed) {
139 | 6 | ASTType type = (ASTType) var.jjtGetChild(0);
140 | 6 | ASTReferenceType ref = (ASTReferenceType) type.jjtGetChild(0);
141 | 6 | ASTClassOrInterfaceType clazz = (ASTClassOrInterfaceType) ref.jjtGetChild(0);
142 | 6 | addViolation(data, id, clazz.getImage());
143 |  | }
144 |  | }
145 |  | }