Clover coverage report - PMD - 3.3
Coverage timestamp: Thu Sep 15 2005 17:59:57 EDT
file stats: LOC: 296   Methods: 23
NCLOC: 214   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
AccessorClassGeneration.java 63.6% 72.6% 95.7% 73.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.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  4 public Object visit(ASTCompilationUnit node, Object data) {
 46  4 classDataList.clear();
 47  4 packageName = node.getScope().getEnclosingSourceFileScope().getPackageName();
 48  4 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  8 public ClassData(String className) {
 61  8 m_ClassName = className;
 62  8 m_PrivateConstructors = new ArrayList();
 63  8 m_Instantiations = new ArrayList();
 64  8 m_ClassQualifyingNames = new ArrayList();
 65    }
 66   
 67  3 public void addInstantiation(AllocData ad) {
 68  3 m_Instantiations.add(ad);
 69    }
 70  2 public Iterator getInstantiationIterator() {
 71  2 return m_Instantiations.iterator();
 72    }
 73  2 public void addConstructor(ASTConstructorDeclaration cd) {
 74  2 m_PrivateConstructors.add(cd);
 75    }
 76  8 public Iterator getPrivateConstructorIterator() {
 77  8 return m_PrivateConstructors.iterator();
 78    }
 79  5 public String getClassName() {
 80  5 return m_ClassName;
 81    }
 82  3 public void addClassQualifyingName(String name) {
 83  3 m_ClassQualifyingNames.add(name);
 84    }
 85  3 public List getClassQualifyingNamesList() {
 86  3 return m_ClassQualifyingNames;
 87    }
 88    }
 89   
 90    private static class AllocData {
 91    private String m_Name;
 92    private int m_ArgumentCount;
 93    private ASTAllocationExpression m_ASTAllocationExpression;
 94    private boolean isArray;
 95   
 96  3 public AllocData(ASTAllocationExpression node, String aPackageName, List classQualifyingNames) {
 97  3 if (node.jjtGetChild(1) instanceof ASTArguments) {
 98  3 ASTArguments aa = (ASTArguments) node.jjtGetChild(1);
 99  3 m_ArgumentCount = aa.getArgumentCount();
 100    //Get name and strip off all superfluous data
 101    //strip off package name if it is current package
 102  3 if (!(node.jjtGetChild(0) instanceof ASTClassOrInterfaceType)) {
 103  0 throw new RuntimeException("BUG: Expected a ASTClassOrInterfaceType, got a " + node.jjtGetChild(0).getClass());
 104    }
 105  3 ASTClassOrInterfaceType an = (ASTClassOrInterfaceType)node.jjtGetChild(0);
 106  3 m_Name = stripString(aPackageName + ".", an.getImage());
 107   
 108    //strip off outer class names
 109    //try OuterClass, then try OuterClass.InnerClass, then try OuterClass.InnerClass.InnerClass2, etc...
 110  3 String findName = "";
 111  3 for (ListIterator li = classQualifyingNames.listIterator(classQualifyingNames.size()); li.hasPrevious();) {
 112  1 String aName = (String) li.previous();
 113  1 findName = aName + "." + findName;
 114  1 if (m_Name.startsWith(findName)) {
 115    //strip off name and exit
 116  0 m_Name = m_Name.substring(findName.length());
 117  0 break;
 118    }
 119    }
 120  0 } else if (node.jjtGetChild(1) instanceof ASTArrayDimsAndInits) {
 121    //this is incomplete because I dont need it.
 122    // child 0 could be primitive or object (ASTName or ASTPrimitiveType)
 123  0 isArray = true;
 124    }
 125  3 m_ASTAllocationExpression = node;
 126    }
 127   
 128  2 public String getName() {
 129  2 return m_Name;
 130    }
 131  2 public int getArgumentCount() {
 132  2 return m_ArgumentCount;
 133    }
 134  2 public ASTAllocationExpression getASTAllocationExpression() {
 135  2 return m_ASTAllocationExpression;
 136    }
 137  3 public boolean isArray() {
 138  3 return isArray;
 139    }
 140    }
 141   
 142    /**
 143    * Outer interface visitation
 144    */
 145  8 public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
 146  8 if (node.isInterface()) {
 147  0 if (node.isNested()) {
 148  0 String interfaceName = node.getImage();
 149  0 int formerID = getClassID();
 150  0 setClassID(classDataList.size());
 151  0 ClassData newClassData = new ClassData(interfaceName);
 152    //store the names of any outer classes of this class in the classQualifyingName List
 153  0 ClassData formerClassData = (ClassData) classDataList.get(formerID);
 154  0 newClassData.addClassQualifyingName(formerClassData.getClassName());
 155  0 classDataList.add(getClassID(), newClassData);
 156  0 Object o = super.visit(node, data);
 157  0 setClassID(formerID);
 158  0 return o;
 159    } else {
 160  0 String interfaceName = node.getImage();
 161  0 classDataList.clear();
 162  0 setClassID(0);
 163  0 classDataList.add(getClassID(), new ClassData(interfaceName));
 164  0 Object o = super.visit(node, data);
 165  0 if (o != null) {
 166  0 processRule(o);
 167    } else {
 168  0 processRule(data);
 169    }
 170  0 setClassID(-1);
 171  0 return o;
 172    }
 173  8 } else if (node.isNested()) {
 174  3 String className = node.getImage();
 175  3 int formerID = getClassID();
 176  3 setClassID(classDataList.size());
 177  3 ClassData newClassData = new ClassData(className);
 178    // TODO
 179    // this is a hack to bail out here
 180    // but I'm not sure why this is happening
 181    // TODO
 182  3 if (formerID == -1 || formerID >= classDataList.size()) {
 183  0 return null;
 184    }
 185    //store the names of any outer classes of this class in the classQualifyingName List
 186  3 ClassData formerClassData = (ClassData) classDataList.get(formerID);
 187  3 newClassData.addClassQualifyingName(formerClassData.getClassName());
 188  3 classDataList.add(getClassID(), newClassData);
 189  3 Object o = super.visit(node, data);
 190  3 setClassID(formerID);
 191  3 return o;
 192    }
 193    // outer classes
 194  5 String className = node.getImage();
 195  5 classDataList.clear();
 196  5 setClassID(0);//first class
 197  5 classDataList.add(getClassID(), new ClassData(className));
 198  5 Object o = super.visit(node, data);
 199  5 if (o != null) {
 200  0 processRule(o);
 201    } else {
 202  5 processRule(data);
 203    }
 204  5 setClassID(-1);
 205  5 return o;
 206    }
 207   
 208    /**
 209    * Store all target constructors
 210    */
 211  3 public Object visit(ASTConstructorDeclaration node, Object data) {
 212  3 if (node.isPrivate()) {
 213  2 getCurrentClassData().addConstructor(node);
 214    }
 215  3 return super.visit(node, data);
 216    }
 217   
 218  4 public Object visit(ASTAllocationExpression node, Object data) {
 219    // TODO
 220    // this is a hack to bail out here
 221    // but I'm not sure why this is happening
 222    // TODO
 223  4 if (classID == -1 || getCurrentClassData() == null) {
 224  1 return data;
 225    }
 226  3 AllocData ad = new AllocData(node, packageName, getCurrentClassData().getClassQualifyingNamesList());
 227  3 if (ad.isArray() == false) {
 228  3 getCurrentClassData().addInstantiation(ad);
 229    }
 230  3 return super.visit(node, data);
 231    }
 232   
 233  5 private void processRule(Object ctx) {
 234    //check constructors of outerIterator against allocations of innerIterator
 235  5 for (Iterator outerIterator = classDataList.iterator(); outerIterator.hasNext();) {
 236  8 ClassData outerDataSet = (ClassData) outerIterator.next();
 237  8 for (Iterator constructors = outerDataSet.getPrivateConstructorIterator(); constructors.hasNext();) {
 238  2 ASTConstructorDeclaration cd = (ASTConstructorDeclaration) constructors.next();
 239   
 240  2 for (Iterator innerIterator = classDataList.iterator(); innerIterator.hasNext();) {
 241  4 ClassData innerDataSet = (ClassData) innerIterator.next();
 242  4 if (outerDataSet == innerDataSet) {
 243  2 continue;
 244    }
 245  2 for (Iterator allocations = innerDataSet.getInstantiationIterator(); allocations.hasNext();) {
 246  2 AllocData ad = (AllocData) allocations.next();
 247    //if the constructor matches the instantiation
 248    //flag the instantiation as a generator of an extra class
 249  2 if (outerDataSet.getClassName().equals(ad.getName()) && (cd.getParameterCount() == ad.getArgumentCount())) {
 250  2 addViolation(ctx, ad.getASTAllocationExpression());
 251    }
 252    }
 253    }
 254    }
 255    }
 256    }
 257   
 258  11 private ClassData getCurrentClassData() {
 259    // TODO
 260    // this is a hack to bail out here
 261    // but I'm not sure why this is happening
 262    // TODO
 263  11 if (classID >= classDataList.size()) {
 264  0 return null;
 265    }
 266  11 return (ClassData) classDataList.get(classID);
 267    }
 268   
 269  16 private void setClassID(int ID) {
 270  16 classID = ID;
 271    }
 272   
 273  11 private int getClassID() {
 274  11 return classID;
 275    }
 276   
 277    //remove = Fire.
 278    //value = someFire.Fighter
 279    // 0123456789012345
 280    //index = 4
 281    //remove.size() = 5
 282    //value.substring(0,4) = some
 283    //value.substring(4 + remove.size()) = Fighter
 284    //return "someFighter"
 285  3 private static String stripString(String remove, String value) {
 286  3 String returnValue;
 287  3 int index = value.indexOf(remove);
 288  3 if (index != -1) { //if the package name can start anywhere but 0 please inform the author because this will break
 289  0 returnValue = value.substring(0, index) + value.substring(index + remove.length());
 290    } else {
 291  3 returnValue = value;
 292    }
 293  3 return returnValue;
 294    }
 295   
 296    }