Clover coverage report - PMD - 3.9
Coverage timestamp: Tue Dec 19 2006 09:38:44 EST
file stats: LOC: 307   Methods: 23
NCLOC: 214   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
AccessorClassGeneration.java 75% 82.3% 95.7% 82.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;
 5   
 6    import net.sourceforge.pmd.AbstractRule;
 7    import net.sourceforge.pmd.ast.ASTAllocationExpression;
 8    import net.sourceforge.pmd.ast.ASTArguments;
 9    import net.sourceforge.pmd.ast.ASTArrayDimsAndInits;
 10    import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
 11    import net.sourceforge.pmd.ast.ASTClassOrInterfaceType;
 12    import net.sourceforge.pmd.ast.ASTCompilationUnit;
 13    import net.sourceforge.pmd.ast.ASTConstructorDeclaration;
 14    import net.sourceforge.pmd.ast.ASTEnumDeclaration;
 15   
 16    import java.util.ArrayList;
 17    import java.util.Iterator;
 18    import java.util.List;
 19    import java.util.ListIterator;
 20   
 21    /**
 22    * 1. Note all private constructors.
 23    * 2. Note all instantiations from outside of the class by way of the private
 24    * constructor.
 25    * 3. Flag instantiations.
 26    * <p/>
 27    * <p/>
 28    * Parameter types can not be matched because they can come as exposed members
 29    * of classes. In this case we have no way to know what the type is. We can
 30    * make a best effort though which can filter some?
 31    *
 32    * @author CL Gilbert (dnoyeb@users.sourceforge.net)
 33    * @author David Konecny (david.konecny@)
 34    */
 35    public class AccessorClassGeneration extends AbstractRule {
 36   
 37    private List classDataList = new ArrayList();
 38    private int classID = -1;
 39    private String packageName;
 40   
 41  0 public Object visit(ASTEnumDeclaration node, Object data) {
 42  0 return data; // just skip Enums
 43    }
 44   
 45  6 public Object visit(ASTCompilationUnit node, Object data) {
 46  6 classDataList.clear();
 47  6 packageName = node.getScope().getEnclosingSourceFileScope().getPackageName();
 48  6 return super.visit(node, data);
 49    }
 50   
 51    private static class ClassData {
 52    private String m_ClassName;
 53    private List m_PrivateConstructors;
 54    private List m_Instantiations;
 55    /**
 56    * List of outer class names that exist above this class
 57    */
 58    private List m_ClassQualifyingNames;
 59   
 60  12 public ClassData(String className) {
 61  12 m_ClassName = className;
 62  12 m_PrivateConstructors = new ArrayList();
 63  12 m_Instantiations = new ArrayList();
 64  12 m_ClassQualifyingNames = new ArrayList();
 65    }
 66   
 67  6 public void addInstantiation(AllocData ad) {
 68  6 m_Instantiations.add(ad);
 69    }
 70   
 71  4 public Iterator getInstantiationIterator() {
 72  4 return m_Instantiations.iterator();
 73    }
 74   
 75  4 public void addConstructor(ASTConstructorDeclaration cd) {
 76  4 m_PrivateConstructors.add(cd);
 77    }
 78   
 79  12 public Iterator getPrivateConstructorIterator() {
 80  12 return m_PrivateConstructors.iterator();
 81    }
 82   
 83  10 public String getClassName() {
 84  10 return m_ClassName;
 85    }
 86   
 87  6 public void addClassQualifyingName(String name) {
 88  6 m_ClassQualifyingNames.add(name);
 89    }
 90   
 91  7 public List getClassQualifyingNamesList() {
 92  7 return m_ClassQualifyingNames;
 93    }
 94    }
 95   
 96    private static class AllocData {
 97    private String m_Name;
 98    private int m_ArgumentCount;
 99    private ASTAllocationExpression m_ASTAllocationExpression;
 100    private boolean isArray;
 101   
 102  7 public AllocData(ASTAllocationExpression node, String aPackageName, List classQualifyingNames) {
 103  7 if (node.jjtGetChild(1) instanceof ASTArguments) {
 104  6 ASTArguments aa = (ASTArguments) node.jjtGetChild(1);
 105  6 m_ArgumentCount = aa.getArgumentCount();
 106    //Get name and strip off all superfluous data
 107    //strip off package name if it is current package
 108  6 if (!(node.jjtGetChild(0) instanceof ASTClassOrInterfaceType)) {
 109  0 throw new RuntimeException("BUG: Expected a ASTClassOrInterfaceType, got a " + node.jjtGetChild(0).getClass());
 110    }
 111  6 ASTClassOrInterfaceType an = (ASTClassOrInterfaceType) node.jjtGetChild(0);
 112  6 m_Name = stripString(aPackageName + ".", an.getImage());
 113   
 114    //strip off outer class names
 115    //try OuterClass, then try OuterClass.InnerClass, then try OuterClass.InnerClass.InnerClass2, etc...
 116  6 String findName = "";
 117  6 for (ListIterator li = classQualifyingNames.listIterator(classQualifyingNames.size()); li.hasPrevious();) {
 118  1 String aName = (String) li.previous();
 119  1 findName = aName + "." + findName;
 120  1 if (m_Name.startsWith(findName)) {
 121    //strip off name and exit
 122  0 m_Name = m_Name.substring(findName.length());
 123  0 break;
 124    }
 125    }
 126  1 } else if (node.jjtGetChild(1) instanceof ASTArrayDimsAndInits) {
 127    //this is incomplete because I dont need it.
 128    // child 0 could be primitive or object (ASTName or ASTPrimitiveType)
 129  1 isArray = true;
 130    }
 131  7 m_ASTAllocationExpression = node;
 132    }
 133   
 134  4 public String getName() {
 135  4 return m_Name;
 136    }
 137   
 138  4 public int getArgumentCount() {
 139  4 return m_ArgumentCount;
 140    }
 141   
 142  4 public ASTAllocationExpression getASTAllocationExpression() {
 143  4 return m_ASTAllocationExpression;
 144    }
 145   
 146  7 public boolean isArray() {
 147  7 return isArray;
 148    }
 149    }
 150   
 151    /**
 152    * Outer interface visitation
 153    */
 154  12 public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
 155  12 if (node.isInterface()) {
 156  1 if (!(node.jjtGetParent().jjtGetParent() instanceof ASTCompilationUnit)) {
 157    // not a top level interface
 158  0 String interfaceName = node.getImage();
 159  0 int formerID = getClassID();
 160  0 setClassID(classDataList.size());
 161  0 ClassData newClassData = new ClassData(interfaceName);
 162    //store the names of any outer classes of this class in the classQualifyingName List
 163  0 ClassData formerClassData = (ClassData) classDataList.get(formerID);
 164  0 newClassData.addClassQualifyingName(formerClassData.getClassName());
 165  0 classDataList.add(getClassID(), newClassData);
 166  0 Object o = super.visit(node, data);
 167  0 setClassID(formerID);
 168  0 return o;
 169    } else {
 170  1 String interfaceName = node.getImage();
 171  1 classDataList.clear();
 172  1 setClassID(0);
 173  1 classDataList.add(getClassID(), new ClassData(interfaceName));
 174  1 Object o = super.visit(node, data);
 175  1 if (o != null) {
 176  0 processRule(o);
 177    } else {
 178  1 processRule(data);
 179    }
 180  1 setClassID(-1);
 181  1 return o;
 182    }
 183  11 } else if (!(node.jjtGetParent().jjtGetParent() instanceof ASTCompilationUnit)) {
 184    // not a top level class
 185  6 String className = node.getImage();
 186  6 int formerID = getClassID();
 187  6 setClassID(classDataList.size());
 188  6 ClassData newClassData = new ClassData(className);
 189    // TODO
 190    // this is a hack to bail out here
 191    // but I'm not sure why this is happening
 192    // TODO
 193  6 if (formerID == -1 || formerID >= classDataList.size()) {
 194  0 return null;
 195    }
 196    //store the names of any outer classes of this class in the classQualifyingName List
 197  6 ClassData formerClassData = (ClassData) classDataList.get(formerID);
 198  6 newClassData.addClassQualifyingName(formerClassData.getClassName());
 199  6 classDataList.add(getClassID(), newClassData);
 200  6 Object o = super.visit(node, data);
 201  6 setClassID(formerID);
 202  6 return o;
 203    }
 204    // outer classes
 205  5 String className = node.getImage();
 206  5 classDataList.clear();
 207  5 setClassID(0);//first class
 208  5 classDataList.add(getClassID(), new ClassData(className));
 209  5 Object o = super.visit(node, data);
 210  5 if (o != null) {
 211  0 processRule(o);
 212    } else {
 213  5 processRule(data);
 214    }
 215  5 setClassID(-1);
 216  5 return o;
 217    }
 218   
 219    /**
 220    * Store all target constructors
 221    */
 222  5 public Object visit(ASTConstructorDeclaration node, Object data) {
 223  5 if (node.isPrivate()) {
 224  4 getCurrentClassData().addConstructor(node);
 225    }
 226  5 return super.visit(node, data);
 227    }
 228   
 229  7 public Object visit(ASTAllocationExpression node, Object data) {
 230    // TODO
 231    // this is a hack to bail out here
 232    // but I'm not sure why this is happening
 233    // TODO
 234  7 if (classID == -1 || getCurrentClassData() == null) {
 235  0 return data;
 236    }
 237  7 AllocData ad = new AllocData(node, packageName, getCurrentClassData().getClassQualifyingNamesList());
 238  7 if (!ad.isArray()) {
 239  6 getCurrentClassData().addInstantiation(ad);
 240    }
 241  7 return super.visit(node, data);
 242    }
 243   
 244  6 private void processRule(Object ctx) {
 245    //check constructors of outerIterator against allocations of innerIterator
 246  6 for (Iterator outerIterator = classDataList.iterator(); outerIterator.hasNext();) {
 247  12 ClassData outerDataSet = (ClassData) outerIterator.next();
 248  12 for (Iterator constructors = outerDataSet.getPrivateConstructorIterator(); constructors.hasNext();) {
 249  4 ASTConstructorDeclaration cd = (ASTConstructorDeclaration) constructors.next();
 250   
 251  4 for (Iterator innerIterator = classDataList.iterator(); innerIterator.hasNext();) {
 252  8 ClassData innerDataSet = (ClassData) innerIterator.next();
 253  8 if (outerDataSet == innerDataSet) {
 254  4 continue;
 255    }
 256  4 for (Iterator allocations = innerDataSet.getInstantiationIterator(); allocations.hasNext();) {
 257  4 AllocData ad = (AllocData) allocations.next();
 258    //if the constructor matches the instantiation
 259    //flag the instantiation as a generator of an extra class
 260  4 if (outerDataSet.getClassName().equals(ad.getName()) && (cd.getParameterCount() == ad.getArgumentCount())) {
 261  4 addViolation(ctx, ad.getASTAllocationExpression());
 262    }
 263    }
 264    }
 265    }
 266    }
 267    }
 268   
 269  24 private ClassData getCurrentClassData() {
 270    // TODO
 271    // this is a hack to bail out here
 272    // but I'm not sure why this is happening
 273    // TODO
 274  24 if (classID >= classDataList.size()) {
 275  0 return null;
 276    }
 277  24 return (ClassData) classDataList.get(classID);
 278    }
 279   
 280  24 private void setClassID(int ID) {
 281  24 classID = ID;
 282    }
 283   
 284  18 private int getClassID() {
 285  18 return classID;
 286    }
 287   
 288    //remove = Fire.
 289    //value = someFire.Fighter
 290    // 0123456789012345
 291    //index = 4
 292    //remove.size() = 5
 293    //value.substring(0,4) = some
 294    //value.substring(4 + remove.size()) = Fighter
 295    //return "someFighter"
 296  6 private static String stripString(String remove, String value) {
 297  6 String returnValue;
 298  6 int index = value.indexOf(remove);
 299  6 if (index != -1) { //if the package name can start anywhere but 0 please inform the author because this will break
 300  0 returnValue = value.substring(0, index) + value.substring(index + remove.length());
 301    } else {
 302  6 returnValue = value;
 303    }
 304  6 return returnValue;
 305    }
 306   
 307    }