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

This page was automatically generated by Maven