KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > pmd > rules > AccessorClassGeneration


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 JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.List JavaDoc;
19 import java.util.ListIterator JavaDoc;
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 JavaDoc classDataList = new ArrayList JavaDoc();
38     private int classID = -1;
39     private String JavaDoc packageName;
40
41     public Object JavaDoc visit(ASTEnumDeclaration node, Object JavaDoc data) {
42         return data; // just skip Enums
43
}
44
45     public Object JavaDoc visit(ASTCompilationUnit node, Object JavaDoc data) {
46         classDataList.clear();
47         packageName = node.getScope().getEnclosingSourceFileScope().getPackageName();
48         return super.visit(node, data);
49     }
50
51     private static class ClassData {
52         private String JavaDoc m_ClassName;
53         private List JavaDoc m_PrivateConstructors;
54         private List JavaDoc m_Instantiations;
55         /**
56          * List of outer class names that exist above this class
57          */

58         private List JavaDoc m_ClassQualifyingNames;
59
60         public ClassData(String JavaDoc className) {
61             m_ClassName = className;
62             m_PrivateConstructors = new ArrayList JavaDoc();
63             m_Instantiations = new ArrayList JavaDoc();
64             m_ClassQualifyingNames = new ArrayList JavaDoc();
65         }
66
67         public void addInstantiation(AllocData ad) {
68             m_Instantiations.add(ad);
69         }
70
71         public Iterator JavaDoc getInstantiationIterator() {
72             return m_Instantiations.iterator();
73         }
74
75         public void addConstructor(ASTConstructorDeclaration cd) {
76             m_PrivateConstructors.add(cd);
77         }
78
79         public Iterator JavaDoc getPrivateConstructorIterator() {
80             return m_PrivateConstructors.iterator();
81         }
82
83         public String JavaDoc getClassName() {
84             return m_ClassName;
85         }
86
87         public void addClassQualifyingName(String JavaDoc name) {
88             m_ClassQualifyingNames.add(name);
89         }
90
91         public List JavaDoc getClassQualifyingNamesList() {
92             return m_ClassQualifyingNames;
93         }
94     }
95
96     private static class AllocData {
97         private String JavaDoc m_Name;
98         private int m_ArgumentCount;
99         private ASTAllocationExpression m_ASTAllocationExpression;
100         private boolean isArray;
101
102         public AllocData(ASTAllocationExpression node, String JavaDoc aPackageName, List JavaDoc classQualifyingNames) {
103             if (node.jjtGetChild(1) instanceof ASTArguments) {
104                 ASTArguments aa = (ASTArguments) node.jjtGetChild(1);
105                 m_ArgumentCount = aa.getArgumentCount();
106                 //Get name and strip off all superfluous data
107
//strip off package name if it is current package
108
if (!(node.jjtGetChild(0) instanceof ASTClassOrInterfaceType)) {
109                     throw new RuntimeException JavaDoc("BUG: Expected a ASTClassOrInterfaceType, got a " + node.jjtGetChild(0).getClass());
110                 }
111                 ASTClassOrInterfaceType an = (ASTClassOrInterfaceType) node.jjtGetChild(0);
112                 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
String JavaDoc findName = "";
117                 for (ListIterator JavaDoc li = classQualifyingNames.listIterator(classQualifyingNames.size()); li.hasPrevious();) {
118                     String JavaDoc aName = (String JavaDoc) li.previous();
119                     findName = aName + "." + findName;
120                     if (m_Name.startsWith(findName)) {
121                         //strip off name and exit
122
m_Name = m_Name.substring(findName.length());
123                         break;
124                     }
125                 }
126             } 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
isArray = true;
130             }
131             m_ASTAllocationExpression = node;
132         }
133
134         public String JavaDoc getName() {
135             return m_Name;
136         }
137
138         public int getArgumentCount() {
139             return m_ArgumentCount;
140         }
141
142         public ASTAllocationExpression getASTAllocationExpression() {
143             return m_ASTAllocationExpression;
144         }
145
146         public boolean isArray() {
147             return isArray;
148         }
149     }
150
151     /**
152      * Outer interface visitation
153      */

154     public Object JavaDoc visit(ASTClassOrInterfaceDeclaration node, Object JavaDoc data) {
155         if (node.isInterface()) {
156             if (!(node.jjtGetParent().jjtGetParent() instanceof ASTCompilationUnit)) {
157                 // not a top level interface
158
String JavaDoc interfaceName = node.getImage();
159                 int formerID = getClassID();
160                 setClassID(classDataList.size());
161                 ClassData newClassData = new ClassData(interfaceName);
162                 //store the names of any outer classes of this class in the classQualifyingName List
163
ClassData formerClassData = (ClassData) classDataList.get(formerID);
164                 newClassData.addClassQualifyingName(formerClassData.getClassName());
165                 classDataList.add(getClassID(), newClassData);
166                 Object JavaDoc o = super.visit(node, data);
167                 setClassID(formerID);
168                 return o;
169             } else {
170                 String JavaDoc interfaceName = node.getImage();
171                 classDataList.clear();
172                 setClassID(0);
173                 classDataList.add(getClassID(), new ClassData(interfaceName));
174                 Object JavaDoc o = super.visit(node, data);
175                 if (o != null) {
176                     processRule(o);
177                 } else {
178                     processRule(data);
179                 }
180                 setClassID(-1);
181                 return o;
182             }
183         } else if (!(node.jjtGetParent().jjtGetParent() instanceof ASTCompilationUnit)) {
184             // not a top level class
185
String JavaDoc className = node.getImage();
186             int formerID = getClassID();
187             setClassID(classDataList.size());
188             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
if (formerID == -1 || formerID >= classDataList.size()) {
194                 return null;
195             }
196             //store the names of any outer classes of this class in the classQualifyingName List
197
ClassData formerClassData = (ClassData) classDataList.get(formerID);
198             newClassData.addClassQualifyingName(formerClassData.getClassName());
199             classDataList.add(getClassID(), newClassData);
200             Object JavaDoc o = super.visit(node, data);
201             setClassID(formerID);
202             return o;
203         }
204         // outer classes
205
String JavaDoc className = node.getImage();
206         classDataList.clear();
207         setClassID(0);//first class
208
classDataList.add(getClassID(), new ClassData(className));
209         Object JavaDoc o = super.visit(node, data);
210         if (o != null) {
211             processRule(o);
212         } else {
213             processRule(data);
214         }
215         setClassID(-1);
216         return o;
217     }
218
219     /**
220      * Store all target constructors
221      */

222     public Object JavaDoc visit(ASTConstructorDeclaration node, Object JavaDoc data) {
223         if (node.isPrivate()) {
224             getCurrentClassData().addConstructor(node);
225         }
226         return super.visit(node, data);
227     }
228
229     public Object JavaDoc visit(ASTAllocationExpression node, Object JavaDoc 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
if (classID == -1 || getCurrentClassData() == null) {
235             return data;
236         }
237         AllocData ad = new AllocData(node, packageName, getCurrentClassData().getClassQualifyingNamesList());
238         if (!ad.isArray()) {
239             getCurrentClassData().addInstantiation(ad);
240         }
241         return super.visit(node, data);
242     }
243
244     private void processRule(Object JavaDoc ctx) {
245         //check constructors of outerIterator against allocations of innerIterator
246
for (Iterator JavaDoc outerIterator = classDataList.iterator(); outerIterator.hasNext();) {
247             ClassData outerDataSet = (ClassData) outerIterator.next();
248             for (Iterator JavaDoc constructors = outerDataSet.getPrivateConstructorIterator(); constructors.hasNext();) {
249                 ASTConstructorDeclaration cd = (ASTConstructorDeclaration) constructors.next();
250
251                 for (Iterator JavaDoc innerIterator = classDataList.iterator(); innerIterator.hasNext();) {
252                     ClassData innerDataSet = (ClassData) innerIterator.next();
253                     if (outerDataSet == innerDataSet) {
254                         continue;
255                     }
256                     for (Iterator JavaDoc allocations = innerDataSet.getInstantiationIterator(); allocations.hasNext();) {
257                         AllocData ad = (AllocData) allocations.next();
258                         //if the constructor matches the instantiation
259
//flag the instantiation as a generator of an extra class
260
if (outerDataSet.getClassName().equals(ad.getName()) && (cd.getParameterCount() == ad.getArgumentCount())) {
261                             addViolation(ctx, ad.getASTAllocationExpression());
262                         }
263                     }
264                 }
265             }
266         }
267     }
268
269     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
if (classID >= classDataList.size()) {
275             return null;
276         }
277         return (ClassData) classDataList.get(classID);
278     }
279
280     private void setClassID(int ID) {
281         classID = ID;
282     }
283
284     private int getClassID() {
285         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
private static String JavaDoc stripString(String JavaDoc remove, String JavaDoc value) {
297         String JavaDoc returnValue;
298         int index = value.indexOf(remove);
299         if (index != -1) { //if the package name can start anywhere but 0 please inform the author because this will break
300
returnValue = value.substring(0, index) + value.substring(index + remove.length());
301         } else {
302             returnValue = value;
303         }
304         return returnValue;
305     }
306
307 }
308
Popular Tags