Clover coverage report - PMD - 3.9
Coverage timestamp: Tue Dec 19 2006 09:38:44 EST
file stats: LOC: 113   Methods: 6
NCLOC: 96   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
ImmutableField.java 91.7% 100% 100% 97.2%
coverage coverage
 1    /**
 2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
 3    */
 4    package net.sourceforge.pmd.rules.design;
 5   
 6    import net.sourceforge.pmd.AbstractRule;
 7    import net.sourceforge.pmd.ast.ASTClassOrInterfaceBodyDeclaration;
 8    import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
 9    import net.sourceforge.pmd.ast.ASTConstructorDeclaration;
 10    import net.sourceforge.pmd.ast.ASTDoStatement;
 11    import net.sourceforge.pmd.ast.ASTForStatement;
 12    import net.sourceforge.pmd.ast.ASTMethodDeclaration;
 13    import net.sourceforge.pmd.ast.ASTTryStatement;
 14    import net.sourceforge.pmd.ast.ASTVariableInitializer;
 15    import net.sourceforge.pmd.ast.ASTWhileStatement;
 16    import net.sourceforge.pmd.ast.SimpleNode;
 17    import net.sourceforge.pmd.symboltable.NameOccurrence;
 18    import net.sourceforge.pmd.symboltable.VariableNameDeclaration;
 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.Map;
 25    import java.util.Set;
 26   
 27    /**
 28    * @author Olander
 29    */
 30    public class ImmutableField extends AbstractRule {
 31   
 32    private static final int MUTABLE = 0;
 33    private static final int IMMUTABLE = 1;
 34    private static final int CHECKDECL = 2;
 35   
 36  16 public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
 37  16 Map vars = node.getScope().getVariableDeclarations();
 38  16 List constructors = findAllConstructors(node);
 39  16 for (Iterator i = vars.entrySet().iterator(); i.hasNext();) {
 40  18 Map.Entry entry = (Map.Entry) i.next();
 41  18 VariableNameDeclaration field = (VariableNameDeclaration) entry.getKey();
 42  18 if (field.getAccessNodeParent().isStatic() || !field.getAccessNodeParent().isPrivate() || field.getAccessNodeParent().isFinal()) {
 43  2 continue;
 44    }
 45   
 46  16 int result = initializedInConstructor((List) entry.getValue(), new HashSet(constructors));
 47  16 if (result == MUTABLE) {
 48  12 continue;
 49    }
 50  4 if (result == IMMUTABLE || (result == CHECKDECL && initializedWhenDeclared(field))) {
 51  2 addViolation(data, field.getNode(), field.getImage());
 52    }
 53    }
 54  16 return super.visit(node, data);
 55    }
 56   
 57  3 private boolean initializedWhenDeclared(VariableNameDeclaration field) {
 58  3 return !field.getAccessNodeParent().findChildrenOfType(ASTVariableInitializer.class).isEmpty();
 59    }
 60   
 61  16 private int initializedInConstructor(List usages, Set allConstructors) {
 62  16 int result = MUTABLE, methodInitCount = 0;
 63  16 Set consSet = new HashSet();
 64  16 for (Iterator j = usages.iterator(); j.hasNext();) {
 65  18 NameOccurrence occ = (NameOccurrence) j.next();
 66  18 if (occ.isOnLeftHandSide() || occ.isSelfAssignment()) {
 67  18 SimpleNode node = occ.getLocation();
 68  18 SimpleNode constructor = (SimpleNode) node.getFirstParentOfType(ASTConstructorDeclaration.class);
 69  18 if (constructor != null) {
 70  6 if (inLoopOrTry(node)) {
 71  2 continue;
 72    }
 73  4 if (inAnonymousInnerClass(node)) {
 74  1 methodInitCount++;
 75    } else {
 76  3 consSet.add(constructor);
 77    }
 78    } else {
 79  12 if (node.getFirstParentOfType(ASTMethodDeclaration.class) != null) {
 80  12 methodInitCount++;
 81    }
 82    }
 83    }
 84    }
 85  16 if (usages.isEmpty() || ((methodInitCount == 0) && consSet.isEmpty())) {
 86  3 result = CHECKDECL;
 87    } else {
 88  13 allConstructors.removeAll(consSet);
 89  13 if (allConstructors.isEmpty() && (methodInitCount == 0)) {
 90  1 result = IMMUTABLE;
 91    }
 92    }
 93  16 return result;
 94    }
 95   
 96  6 private boolean inLoopOrTry(SimpleNode node) {
 97  6 return (SimpleNode) node.getFirstParentOfType(ASTTryStatement.class) != null ||
 98    (SimpleNode) node.getFirstParentOfType(ASTForStatement.class) != null ||
 99    (SimpleNode) node.getFirstParentOfType(ASTWhileStatement.class) != null ||
 100    (SimpleNode) node.getFirstParentOfType(ASTDoStatement.class) != null;
 101    }
 102   
 103  4 private boolean inAnonymousInnerClass(SimpleNode node) {
 104  4 ASTClassOrInterfaceBodyDeclaration parent = (ASTClassOrInterfaceBodyDeclaration) node.getFirstParentOfType(ASTClassOrInterfaceBodyDeclaration.class);
 105  4 return parent != null && parent.isAnonymousInnerClass();
 106    }
 107   
 108  16 private List findAllConstructors(ASTClassOrInterfaceDeclaration node) {
 109  16 List cons = new ArrayList();
 110  16 node.findChildrenOfType(ASTConstructorDeclaration.class, cons, false);
 111  16 return cons;
 112    }
 113    }