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.RuleContext;
8 import net.sourceforge.pmd.ast.ASTBlock;
9 import net.sourceforge.pmd.ast.ASTLocalVariableDeclaration;
10 import net.sourceforge.pmd.ast.ASTMethodDeclaration;
11 import net.sourceforge.pmd.ast.ASTName;
12 import net.sourceforge.pmd.ast.ASTTryStatement;
13 import net.sourceforge.pmd.ast.ASTType;
14 import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
15 import net.sourceforge.pmd.ast.Node;
16
17 import java.util.ArrayList;
18 import java.util.Iterator;
19 import java.util.List;
20 import java.util.Vector;
21
22
23 /***
24 * Makes sure you close your database connections. It does this by
25 * looking for code patterned like this:
26 * <pre>
27 * Connection c = X;
28 * try {
29 * // do stuff, and maybe catch something
30 * } finally {
31 * c.close();
32 * }
33 * </pre>
34 */
35 public class CloseConnectionRule extends AbstractRule {
36 public Object visit(ASTMethodDeclaration node, Object data) {
37 List vars = node.findChildrenOfType(ASTLocalVariableDeclaration.class);
38 List ids = new Vector();
39
40 // find all variable references to Connection objects
41 for (Iterator it = vars.iterator(); it.hasNext();) {
42 ASTLocalVariableDeclaration var = (ASTLocalVariableDeclaration) it.next();
43 ASTType type = (ASTType) var.jjtGetChild(0);
44
45 if (type.jjtGetChild(0) instanceof ASTName && ((ASTName) type.jjtGetChild(0)).getImage().equals("Connection")) {
46 ASTVariableDeclaratorId id = (ASTVariableDeclaratorId) var.jjtGetChild(1).jjtGetChild(0);
47 ids.add(id);
48 }
49 }
50
51 // if there are connections, ensure each is closed.
52 for (int i = 0; i < ids.size(); i++) {
53 ASTVariableDeclaratorId x = (ASTVariableDeclaratorId) ids.get(i);
54 ensureClosed((ASTLocalVariableDeclaration) x.jjtGetParent()
55 .jjtGetParent(), x, data);
56 }
57 return data;
58 }
59
60 private void ensureClosed(ASTLocalVariableDeclaration var,
61 ASTVariableDeclaratorId id, Object data) {
62 // What are the chances of a Connection being instantiated in a
63 // for-loop init block? Anyway, I'm lazy!
64 String target = id.getImage() + ".close";
65 Node n = var;
66
67 while (!((n = n.jjtGetParent()) instanceof ASTBlock))
68 ;
69
70 ASTBlock top = (ASTBlock) n;
71
72 List tryblocks = new Vector();
73 top.findChildrenOfType(ASTTryStatement.class, tryblocks, true);
74
75 boolean closed = false;
76
77 // look for try blocks below the line the variable was
78 // introduced and make sure there is a .close call in a finally
79 // block.
80 for (Iterator it = tryblocks.iterator(); it.hasNext();) {
81 ASTTryStatement t = (ASTTryStatement) it.next();
82
83 if ((t.getBeginLine() > id.getBeginLine()) && (t.hasFinally())) {
84 ASTBlock f = t.getFinallyBlock();
85 List names = new ArrayList();
86 f.findChildrenOfType(ASTName.class, names, true);
87 for (Iterator it2 = names.iterator(); it2.hasNext();) {
88 if (((ASTName) it2.next()).getImage().equals(target)) {
89 closed = true;
90 }
91 }
92 }
93 }
94
95 // if all is not well, complain
96 if (!closed) {
97 RuleContext ctx = (RuleContext) data;
98 ctx.getReport().addRuleViolation(createRuleViolation(ctx, id.getBeginLine(), getMessage()));
99 }
100 }
101 }
This page was automatically generated by Maven