Clover coverage report - PMD - 3.7
Coverage timestamp: Wed May 31 2006 09:25:59 EDT
file stats: LOC: 140   Methods: 4
NCLOC: 97   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
CloseResource.java 65.6% 87.8% 100% 80%
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.ast.ASTBlock;
 8    import net.sourceforge.pmd.ast.ASTClassOrInterfaceType;
 9    import net.sourceforge.pmd.ast.ASTCompilationUnit;
 10    import net.sourceforge.pmd.ast.ASTImportDeclaration;
 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   
 20    import java.util.ArrayList;
 21    import java.util.HashSet;
 22    import java.util.Iterator;
 23    import java.util.List;
 24    import java.util.Set;
 25    import java.util.StringTokenizer;
 26    import java.util.Vector;
 27   
 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  5 public Object visit(ASTCompilationUnit node, Object data) {
 46  5 if (!importsJavaSqlPackage(node)) {
 47  2 return data;
 48    }
 49  3 if (types.isEmpty()) {
 50  1 for (StringTokenizer st = new StringTokenizer(getStringProperty("types"), ","); st.hasMoreTokens();) {
 51  3 types.add(st.nextToken());
 52    }
 53    }
 54  3 return super.visit(node, data);
 55    }
 56   
 57  3 public Object visit(ASTMethodDeclaration node, Object data) {
 58  3 List vars = node.findChildrenOfType(ASTLocalVariableDeclaration.class);
 59  3 List ids = new Vector();
 60   
 61    // find all variable references to Connection objects
 62  3 for (Iterator it = vars.iterator(); it.hasNext();) {
 63  3 ASTLocalVariableDeclaration var = (ASTLocalVariableDeclaration) it.next();
 64  3 ASTType type = (ASTType) var.jjtGetChild(0);
 65   
 66  3 if (type.jjtGetChild(0) instanceof ASTReferenceType) {
 67  3 ASTReferenceType ref = (ASTReferenceType) type.jjtGetChild(0);
 68  3 if (ref.jjtGetChild(0) instanceof ASTClassOrInterfaceType) {
 69  3 ASTClassOrInterfaceType clazz = (ASTClassOrInterfaceType) ref.jjtGetChild(0);
 70  3 if (types.contains(clazz.getImage())) {
 71  3 ASTVariableDeclaratorId id = (ASTVariableDeclaratorId) var.jjtGetChild(1).jjtGetChild(0);
 72  3 ids.add(id);
 73    }
 74    }
 75    }
 76    }
 77   
 78    // if there are connections, ensure each is closed.
 79  3 for (int i = 0; i < ids.size(); i++) {
 80  3 ASTVariableDeclaratorId x = (ASTVariableDeclaratorId) ids.get(i);
 81  3 ensureClosed((ASTLocalVariableDeclaration) x.jjtGetParent().jjtGetParent(), x, data);
 82    }
 83  3 return data;
 84    }
 85   
 86  3 private void ensureClosed(ASTLocalVariableDeclaration var,
 87    ASTVariableDeclaratorId id, Object data) {
 88    // What are the chances of a Connection being instantiated in a
 89    // for-loop init block? Anyway, I'm lazy!
 90  3 String target = id.getImage() + ".close";
 91  3 Node n = var;
 92   
 93  ? while (!((n = n.jjtGetParent()) instanceof ASTBlock)) ;
 94   
 95  3 ASTBlock top = (ASTBlock) n;
 96   
 97  3 List tryblocks = new Vector();
 98  3 top.findChildrenOfType(ASTTryStatement.class, tryblocks, true);
 99   
 100  3 boolean closed = false;
 101   
 102    // look for try blocks below the line the variable was
 103    // introduced and make sure there is a .close call in a finally
 104    // block.
 105  3 for (Iterator it = tryblocks.iterator(); it.hasNext();) {
 106  3 ASTTryStatement t = (ASTTryStatement) it.next();
 107   
 108  3 if ((t.getBeginLine() > id.getBeginLine()) && (t.hasFinally())) {
 109  0 ASTBlock f = (ASTBlock) t.getFinally().jjtGetChild(0);
 110  0 List names = new ArrayList();
 111  0 f.findChildrenOfType(ASTName.class, names, true);
 112  0 for (Iterator it2 = names.iterator(); it2.hasNext();) {
 113  0 if (((ASTName) it2.next()).getImage().equals(target)) {
 114  0 closed = true;
 115    }
 116    }
 117    }
 118    }
 119   
 120    // if all is not well, complain
 121  3 if (!closed) {
 122  3 ASTType type = (ASTType) var.jjtGetChild(0);
 123  3 ASTReferenceType ref = (ASTReferenceType) type.jjtGetChild(0);
 124  3 ASTClassOrInterfaceType clazz = (ASTClassOrInterfaceType) ref.jjtGetChild(0);
 125  3 addViolation(data, id, clazz.getImage());
 126    }
 127    }
 128   
 129  5 private boolean importsJavaSqlPackage(ASTCompilationUnit node) {
 130  5 List nodes = node.findChildrenOfType(ASTImportDeclaration.class);
 131  5 for (Iterator i = nodes.iterator(); i.hasNext();) {
 132  4 ASTImportDeclaration n = (ASTImportDeclaration) i.next();
 133  4 if (n.getPackageName().startsWith("java.sql")) {
 134  3 return true;
 135    }
 136    }
 137  2 return false;
 138    }
 139   
 140    }