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

This page was automatically generated by Maven