1 |
| |
2 |
| |
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 |
| |
23 |
| |
24 |
| |
25 |
| |
26 |
| |
27 |
| |
28 |
| |
29 |
| |
30 |
| |
31 |
| |
32 |
| |
33 |
| |
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;
|
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 |
| |
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 |
| |
71 |
2
| public Iterator getInstantiationIterator() {
|
72 |
2
| return m_Instantiations.iterator();
|
73 |
| } |
74 |
| |
75 |
2
| public void addConstructor(ASTConstructorDeclaration cd) {
|
76 |
2
| m_PrivateConstructors.add(cd);
|
77 |
| } |
78 |
| |
79 |
8
| public Iterator getPrivateConstructorIterator() {
|
80 |
8
| return m_PrivateConstructors.iterator();
|
81 |
| } |
82 |
| |
83 |
5
| public String getClassName() {
|
84 |
5
| return m_ClassName;
|
85 |
| } |
86 |
| |
87 |
3
| public void addClassQualifyingName(String name) {
|
88 |
3
| m_ClassQualifyingNames.add(name);
|
89 |
| } |
90 |
| |
91 |
3
| public List getClassQualifyingNamesList() {
|
92 |
3
| 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 |
3
| public AllocData(ASTAllocationExpression node, String aPackageName, List classQualifyingNames) {
|
103 |
3
| if (node.jjtGetChild(1) instanceof ASTArguments) {
|
104 |
3
| ASTArguments aa = (ASTArguments) node.jjtGetChild(1);
|
105 |
3
| m_ArgumentCount = aa.getArgumentCount();
|
106 |
| |
107 |
| |
108 |
3
| if (!(node.jjtGetChild(0) instanceof ASTClassOrInterfaceType)) {
|
109 |
0
| throw new RuntimeException("BUG: Expected a ASTClassOrInterfaceType, got a " + node.jjtGetChild(0).getClass());
|
110 |
| } |
111 |
3
| ASTClassOrInterfaceType an = (ASTClassOrInterfaceType) node.jjtGetChild(0);
|
112 |
3
| m_Name = stripString(aPackageName + ".", an.getImage());
|
113 |
| |
114 |
| |
115 |
| |
116 |
3
| String findName = "";
|
117 |
3
| 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 |
| |
122 |
0
| m_Name = m_Name.substring(findName.length());
|
123 |
0
| break;
|
124 |
| } |
125 |
| } |
126 |
0
| } else if (node.jjtGetChild(1) instanceof ASTArrayDimsAndInits) {
|
127 |
| |
128 |
| |
129 |
0
| isArray = true;
|
130 |
| } |
131 |
3
| m_ASTAllocationExpression = node;
|
132 |
| } |
133 |
| |
134 |
2
| public String getName() {
|
135 |
2
| return m_Name;
|
136 |
| } |
137 |
| |
138 |
2
| public int getArgumentCount() {
|
139 |
2
| return m_ArgumentCount;
|
140 |
| } |
141 |
| |
142 |
2
| public ASTAllocationExpression getASTAllocationExpression() {
|
143 |
2
| return m_ASTAllocationExpression;
|
144 |
| } |
145 |
| |
146 |
3
| public boolean isArray() {
|
147 |
3
| return isArray;
|
148 |
| } |
149 |
| } |
150 |
| |
151 |
| |
152 |
| |
153 |
| |
154 |
8
| public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
|
155 |
8
| if (node.isInterface()) {
|
156 |
0
| if (node.isNested()) {
|
157 |
0
| String interfaceName = node.getImage();
|
158 |
0
| int formerID = getClassID();
|
159 |
0
| setClassID(classDataList.size());
|
160 |
0
| ClassData newClassData = new ClassData(interfaceName);
|
161 |
| |
162 |
0
| ClassData formerClassData = (ClassData) classDataList.get(formerID);
|
163 |
0
| newClassData.addClassQualifyingName(formerClassData.getClassName());
|
164 |
0
| classDataList.add(getClassID(), newClassData);
|
165 |
0
| Object o = super.visit(node, data);
|
166 |
0
| setClassID(formerID);
|
167 |
0
| return o;
|
168 |
| } else { |
169 |
0
| String interfaceName = node.getImage();
|
170 |
0
| classDataList.clear();
|
171 |
0
| setClassID(0);
|
172 |
0
| classDataList.add(getClassID(), new ClassData(interfaceName));
|
173 |
0
| Object o = super.visit(node, data);
|
174 |
0
| if (o != null) {
|
175 |
0
| processRule(o);
|
176 |
| } else { |
177 |
0
| processRule(data);
|
178 |
| } |
179 |
0
| setClassID(-1);
|
180 |
0
| return o;
|
181 |
| } |
182 |
8
| } else if (node.isNested()) {
|
183 |
3
| String className = node.getImage();
|
184 |
3
| int formerID = getClassID();
|
185 |
3
| setClassID(classDataList.size());
|
186 |
3
| ClassData newClassData = new ClassData(className);
|
187 |
| |
188 |
| |
189 |
| |
190 |
| |
191 |
3
| if (formerID == -1 || formerID >= classDataList.size()) {
|
192 |
0
| return null;
|
193 |
| } |
194 |
| |
195 |
3
| ClassData formerClassData = (ClassData) classDataList.get(formerID);
|
196 |
3
| newClassData.addClassQualifyingName(formerClassData.getClassName());
|
197 |
3
| classDataList.add(getClassID(), newClassData);
|
198 |
3
| Object o = super.visit(node, data);
|
199 |
3
| setClassID(formerID);
|
200 |
3
| return o;
|
201 |
| } |
202 |
| |
203 |
5
| String className = node.getImage();
|
204 |
5
| classDataList.clear();
|
205 |
5
| setClassID(0);
|
206 |
5
| classDataList.add(getClassID(), new ClassData(className));
|
207 |
5
| Object o = super.visit(node, data);
|
208 |
5
| if (o != null) {
|
209 |
0
| processRule(o);
|
210 |
| } else { |
211 |
5
| processRule(data);
|
212 |
| } |
213 |
5
| setClassID(-1);
|
214 |
5
| return o;
|
215 |
| } |
216 |
| |
217 |
| |
218 |
| |
219 |
| |
220 |
3
| public Object visit(ASTConstructorDeclaration node, Object data) {
|
221 |
3
| if (node.isPrivate()) {
|
222 |
2
| getCurrentClassData().addConstructor(node);
|
223 |
| } |
224 |
3
| return super.visit(node, data);
|
225 |
| } |
226 |
| |
227 |
4
| public Object visit(ASTAllocationExpression node, Object data) {
|
228 |
| |
229 |
| |
230 |
| |
231 |
| |
232 |
4
| if (classID == -1 || getCurrentClassData() == null) {
|
233 |
1
| return data;
|
234 |
| } |
235 |
3
| AllocData ad = new AllocData(node, packageName, getCurrentClassData().getClassQualifyingNamesList());
|
236 |
3
| if (ad.isArray() == false) {
|
237 |
3
| getCurrentClassData().addInstantiation(ad);
|
238 |
| } |
239 |
3
| return super.visit(node, data);
|
240 |
| } |
241 |
| |
242 |
5
| private void processRule(Object ctx) {
|
243 |
| |
244 |
5
| for (Iterator outerIterator = classDataList.iterator(); outerIterator.hasNext();) {
|
245 |
8
| ClassData outerDataSet = (ClassData) outerIterator.next();
|
246 |
8
| for (Iterator constructors = outerDataSet.getPrivateConstructorIterator(); constructors.hasNext();) {
|
247 |
2
| ASTConstructorDeclaration cd = (ASTConstructorDeclaration) constructors.next();
|
248 |
| |
249 |
2
| for (Iterator innerIterator = classDataList.iterator(); innerIterator.hasNext();) {
|
250 |
4
| ClassData innerDataSet = (ClassData) innerIterator.next();
|
251 |
4
| if (outerDataSet == innerDataSet) {
|
252 |
2
| continue;
|
253 |
| } |
254 |
2
| for (Iterator allocations = innerDataSet.getInstantiationIterator(); allocations.hasNext();) {
|
255 |
2
| AllocData ad = (AllocData) allocations.next();
|
256 |
| |
257 |
| |
258 |
2
| if (outerDataSet.getClassName().equals(ad.getName()) && (cd.getParameterCount() == ad.getArgumentCount())) {
|
259 |
2
| addViolation(ctx, ad.getASTAllocationExpression());
|
260 |
| } |
261 |
| } |
262 |
| } |
263 |
| } |
264 |
| } |
265 |
| } |
266 |
| |
267 |
11
| private ClassData getCurrentClassData() {
|
268 |
| |
269 |
| |
270 |
| |
271 |
| |
272 |
11
| if (classID >= classDataList.size()) {
|
273 |
0
| return null;
|
274 |
| } |
275 |
11
| return (ClassData) classDataList.get(classID);
|
276 |
| } |
277 |
| |
278 |
16
| private void setClassID(int ID) {
|
279 |
16
| classID = ID;
|
280 |
| } |
281 |
| |
282 |
11
| private int getClassID() {
|
283 |
11
| return classID;
|
284 |
| } |
285 |
| |
286 |
| |
287 |
| |
288 |
| |
289 |
| |
290 |
| |
291 |
| |
292 |
| |
293 |
| |
294 |
3
| private static String stripString(String remove, String value) {
|
295 |
3
| String returnValue;
|
296 |
3
| int index = value.indexOf(remove);
|
297 |
3
| if (index != -1) {
|
298 |
0
| returnValue = value.substring(0, index) + value.substring(index + remove.length());
|
299 |
| } else { |
300 |
3
| returnValue = value;
|
301 |
| } |
302 |
3
| return returnValue;
|
303 |
| } |
304 |
| |
305 |
| } |