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