1 |
| |
2 |
| |
3 |
| |
4 |
| package net.sourceforge.pmd; |
5 |
| |
6 |
| import java.text.MessageFormat; |
7 |
| import java.util.Collections; |
8 |
| import java.util.HashMap; |
9 |
| import java.util.Iterator; |
10 |
| import java.util.List; |
11 |
| import java.util.Map; |
12 |
| import java.util.Properties; |
13 |
| |
14 |
| import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration; |
15 |
| import net.sourceforge.pmd.ast.ASTCompilationUnit; |
16 |
| import net.sourceforge.pmd.ast.ASTImportDeclaration; |
17 |
| import net.sourceforge.pmd.ast.JavaParserVisitorAdapter; |
18 |
| import net.sourceforge.pmd.ast.Node; |
19 |
| import net.sourceforge.pmd.ast.SimpleNode; |
20 |
| |
21 |
| public abstract class AbstractRule extends JavaParserVisitorAdapter implements Rule { |
22 |
| |
23 |
| protected String name = getClass().getName(); |
24 |
| protected Properties properties = new Properties(); |
25 |
| protected String message; |
26 |
| protected String description; |
27 |
| protected String example; |
28 |
| protected String ruleSetName; |
29 |
| protected boolean include; |
30 |
| protected boolean usesDFA; |
31 |
| protected boolean usesTypeResolution; |
32 |
| protected int priority = LOWEST_PRIORITY; |
33 |
| protected String externalInfoUrl; |
34 |
| |
35 |
| private static final boolean inOldPropertyMode = true; |
36 |
| |
37 |
251
| protected static Map asFixedMap(PropertyDescriptor[] descriptors) {
|
38 |
| |
39 |
251
| Map descsById = new HashMap(descriptors.length);
|
40 |
| |
41 |
251
| for (int i=0; i<descriptors.length; i++) {
|
42 |
533
| descsById.put(descriptors[i].name(), descriptors[i]);
|
43 |
| } |
44 |
251
| return Collections.unmodifiableMap(descsById);
|
45 |
| } |
46 |
| |
47 |
72
| protected static Map asFixedMap(PropertyDescriptor descriptor) {
|
48 |
72
| return asFixedMap(new PropertyDescriptor[] {descriptor});
|
49 |
| } |
50 |
| |
51 |
12
| public String getRuleSetName() {
|
52 |
12
| return ruleSetName;
|
53 |
| } |
54 |
| |
55 |
4599
| public void setRuleSetName(String ruleSetName) {
|
56 |
4599
| this.ruleSetName = ruleSetName;
|
57 |
| } |
58 |
| |
59 |
2
| public String getDescription() {
|
60 |
2
| return description;
|
61 |
| } |
62 |
| |
63 |
4346
| public void setDescription(String description) {
|
64 |
4346
| this.description = description;
|
65 |
| } |
66 |
| |
67 |
1
| public String getExample() {
|
68 |
1
| return example;
|
69 |
| } |
70 |
| |
71 |
4434
| public void setExample(String example) {
|
72 |
4434
| this.example = example;
|
73 |
| } |
74 |
| |
75 |
| |
76 |
| |
77 |
| |
78 |
603
| public boolean hasProperty(String name) {
|
79 |
| |
80 |
603
| return inOldPropertyMode ?
|
81 |
| properties.containsKey(name) : |
82 |
| propertiesByName().containsKey(name); |
83 |
| } |
84 |
| |
85 |
| |
86 |
| |
87 |
| |
88 |
3455
| public void addProperty(String name, String value) {
|
89 |
3455
| properties.setProperty(name, value);
|
90 |
| } |
91 |
| |
92 |
| |
93 |
| |
94 |
| |
95 |
2
| public void addProperties(Properties properties) {
|
96 |
2
| this.properties.putAll(properties);
|
97 |
| } |
98 |
| |
99 |
0
| public double[] getDoubleProperties(PropertyDescriptor descriptor) {
|
100 |
| |
101 |
0
| Number[] values = (Number[])getProperties(descriptor);
|
102 |
| |
103 |
0
| double[] doubles = new double[values.length];
|
104 |
0
| for (int i=0; i<doubles.length; i++) doubles[i] = values[i].doubleValue();
|
105 |
0
| return doubles;
|
106 |
| } |
107 |
| |
108 |
| |
109 |
| |
110 |
| |
111 |
1
| public double getDoubleProperty(String name) {
|
112 |
| |
113 |
1
| return Double.parseDouble(properties.getProperty(name));
|
114 |
| } |
115 |
| |
116 |
253
| public double getDoubleProperty(PropertyDescriptor descriptor) {
|
117 |
| |
118 |
253
| return ((Number)getProperty(descriptor)).doubleValue();
|
119 |
| } |
120 |
| |
121 |
1
| public int[] getIntProperties(PropertyDescriptor descriptor) {
|
122 |
| |
123 |
1
| Number[] values = (Number[])getProperties(descriptor);
|
124 |
| |
125 |
1
| int[] ints = new int[values.length];
|
126 |
2
| for (int i=0; i<ints.length; i++) ints[i] = values[i].intValue();
|
127 |
1
| return ints;
|
128 |
| } |
129 |
| |
130 |
| |
131 |
| |
132 |
| |
133 |
8
| public int getIntProperty(String name) {
|
134 |
| |
135 |
8
| return Integer.parseInt(properties.getProperty(name));
|
136 |
| } |
137 |
| |
138 |
176
| public int getIntProperty(PropertyDescriptor descriptor) {
|
139 |
| |
140 |
176
| return ((Number)getProperty(descriptor)).intValue();
|
141 |
| } |
142 |
| |
143 |
0
| public Class[] getTypeProperties(PropertyDescriptor descriptor) {
|
144 |
| |
145 |
0
| return (Class[])getProperties(descriptor);
|
146 |
| } |
147 |
| |
148 |
0
| public Class getTypeProperty(PropertyDescriptor descriptor) {
|
149 |
| |
150 |
0
| return (Class)getProperty(descriptor);
|
151 |
| } |
152 |
| |
153 |
1
| public boolean[] getBooleanProperties(PropertyDescriptor descriptor) {
|
154 |
| |
155 |
1
| Boolean[] values = (Boolean[])getProperties(descriptor);
|
156 |
| |
157 |
1
| boolean[] bools = new boolean[values.length];
|
158 |
2
| for (int i=0; i<bools.length; i++) bools[i] = values[i].booleanValue();
|
159 |
1
| return bools;
|
160 |
| } |
161 |
| |
162 |
25
| public boolean getBooleanProperty(PropertyDescriptor descriptor) {
|
163 |
| |
164 |
25
| return ((Boolean)getProperty(descriptor)).booleanValue();
|
165 |
| } |
166 |
| |
167 |
| |
168 |
| |
169 |
| |
170 |
16
| public boolean getBooleanProperty(String name) {
|
171 |
| |
172 |
16
| return Boolean.valueOf(properties.getProperty(name)).booleanValue();
|
173 |
| } |
174 |
| |
175 |
| |
176 |
| |
177 |
| |
178 |
| |
179 |
| |
180 |
| |
181 |
0
| public void setBooleanProperty(String name, boolean flag) {
|
182 |
| |
183 |
0
| properties.setProperty(name, Boolean.toString(flag));
|
184 |
| } |
185 |
| |
186 |
41
| public String[] getStringProperties(PropertyDescriptor descriptor) {
|
187 |
| |
188 |
41
| return (String[])getProperties(descriptor);
|
189 |
| } |
190 |
| |
191 |
| |
192 |
| |
193 |
| |
194 |
| |
195 |
| |
196 |
109
| public String getStringProperty(String name) {
|
197 |
109
| return properties.getProperty(name);
|
198 |
| } |
199 |
| |
200 |
37
| public String getStringProperty(PropertyDescriptor descriptor) {
|
201 |
37
| return (String)getProperty(descriptor);
|
202 |
| } |
203 |
| |
204 |
491
| private Object getProperty(PropertyDescriptor descriptor) {
|
205 |
| |
206 |
0
| if (descriptor.maxValueCount() > 1) propertyGetError(descriptor, true);
|
207 |
| |
208 |
491
| String rawValue = properties.getProperty(descriptor.name());
|
209 |
| |
210 |
491
| return rawValue == null || rawValue.length() == 0 ?
|
211 |
| descriptor.defaultValue() : |
212 |
| descriptor.valueFrom(rawValue); |
213 |
| } |
214 |
| |
215 |
29
| public void setProperty(PropertyDescriptor descriptor, Object value) {
|
216 |
| |
217 |
3
| if (descriptor.maxValueCount() > 1) propertySetError(descriptor, true);
|
218 |
| |
219 |
26
| properties.setProperty(descriptor.name(), descriptor.asDelimitedString(value));
|
220 |
| } |
221 |
| |
222 |
43
| private Object[] getProperties(PropertyDescriptor descriptor) {
|
223 |
| |
224 |
0
| if (descriptor.maxValueCount() == 1) propertyGetError(descriptor, false);
|
225 |
| |
226 |
43
| String rawValue = properties.getProperty(descriptor.name());
|
227 |
| |
228 |
43
| return rawValue == null || rawValue.length() == 0 ?
|
229 |
| (Object[])descriptor.defaultValue() : |
230 |
| (Object[])descriptor.valueFrom(rawValue); |
231 |
| } |
232 |
| |
233 |
6
| public void setProperties(PropertyDescriptor descriptor, Object[] values) {
|
234 |
| |
235 |
3
| if (descriptor.maxValueCount() == 1) propertySetError(descriptor, false);
|
236 |
| |
237 |
3
| properties.setProperty(descriptor.name(), descriptor.asDelimitedString(values));
|
238 |
| } |
239 |
| |
240 |
0
| private void propertyGetError(PropertyDescriptor descriptor, boolean requestedSingleValue) {
|
241 |
| |
242 |
0
| if (requestedSingleValue) {
|
243 |
0
| throw new RuntimeException("Cannot retrieve a single value from a multi-value property field");
|
244 |
| } |
245 |
0
| throw new RuntimeException("Cannot retrieve multiple values from a single-value property field");
|
246 |
| } |
247 |
| |
248 |
6
| private void propertySetError(PropertyDescriptor descriptor, boolean setSingleValue) {
|
249 |
| |
250 |
6
| if (setSingleValue) {
|
251 |
3
| throw new RuntimeException("Cannot set a single value within a multi-value property field");
|
252 |
| } |
253 |
3
| throw new RuntimeException("Cannot set multiple values within a single-value property field");
|
254 |
| } |
255 |
| |
256 |
2846
| public String getName() {
|
257 |
2846
| return name;
|
258 |
| } |
259 |
| |
260 |
4413
| public void setName(String name) {
|
261 |
4413
| this.name = name;
|
262 |
| } |
263 |
| |
264 |
849
| public String getMessage() {
|
265 |
849
| return message;
|
266 |
| } |
267 |
| |
268 |
4417
| public void setMessage(String message) {
|
269 |
4417
| this.message = message;
|
270 |
| } |
271 |
| |
272 |
15
| public String getExternalInfoUrl() {
|
273 |
15
| return externalInfoUrl;
|
274 |
| } |
275 |
| |
276 |
4391
| public void setExternalInfoUrl(String url) {
|
277 |
4391
| this.externalInfoUrl = url;
|
278 |
| } |
279 |
| |
280 |
| |
281 |
| |
282 |
| |
283 |
| |
284 |
| |
285 |
| |
286 |
| |
287 |
16
| public boolean equals(Object o) {
|
288 |
16
| if (o == null) {
|
289 |
1
| return false;
|
290 |
| } |
291 |
| |
292 |
15
| if (this == o) {
|
293 |
5
| return true;
|
294 |
| } |
295 |
| |
296 |
10
| Rule rule = null;
|
297 |
10
| boolean equality = this.getClass().getName().equals(o.getClass().getName());
|
298 |
| |
299 |
10
| if (equality) {
|
300 |
8
| rule = (Rule) o;
|
301 |
8
| equality = this.getName().equals(rule.getName())
|
302 |
| && this.getPriority() == rule.getPriority() |
303 |
| && this.getProperties().equals(rule.getProperties()); |
304 |
| } |
305 |
| |
306 |
10
| return equality;
|
307 |
| } |
308 |
| |
309 |
| |
310 |
| |
311 |
| |
312 |
20
| public int hashCode() {
|
313 |
20
| String s = getClass().getName() + getName() + getPriority() + getProperties().toString();
|
314 |
20
| return s.hashCode();
|
315 |
| } |
316 |
| |
317 |
1189
| public void apply(List acus, RuleContext ctx) {
|
318 |
1189
| visitAll(acus, ctx);
|
319 |
| } |
320 |
| |
321 |
| |
322 |
| |
323 |
| |
324 |
1200
| public Properties getProperties() {
|
325 |
1200
| return properties;
|
326 |
| } |
327 |
| |
328 |
0
| public boolean include() {
|
329 |
0
| return include;
|
330 |
| } |
331 |
| |
332 |
0
| public void setInclude(boolean include) {
|
333 |
0
| this.include = include;
|
334 |
| } |
335 |
| |
336 |
4483
| public int getPriority() {
|
337 |
4483
| return priority;
|
338 |
| } |
339 |
| |
340 |
0
| public String getPriorityName() {
|
341 |
0
| return PRIORITIES[getPriority() - 1];
|
342 |
| } |
343 |
| |
344 |
4356
| public void setPriority(int priority) {
|
345 |
4356
| this.priority = priority;
|
346 |
| } |
347 |
| |
348 |
19
| public void setUsesDFA() {
|
349 |
19
| this.usesDFA = true;
|
350 |
| } |
351 |
| |
352 |
1229
| public boolean usesDFA() {
|
353 |
1229
| return this.usesDFA;
|
354 |
| } |
355 |
| |
356 |
4
| public void setUsesTypeResolution() {
|
357 |
4
| this.usesTypeResolution = true;
|
358 |
| } |
359 |
| |
360 |
1225
| public boolean usesTypeResolution() {
|
361 |
1225
| return this.usesTypeResolution;
|
362 |
| } |
363 |
| |
364 |
1383
| protected void visitAll(List acus, RuleContext ctx) {
|
365 |
1383
| for (Iterator i = acus.iterator(); i.hasNext();) {
|
366 |
1225
| ASTCompilationUnit node = (ASTCompilationUnit) i.next();
|
367 |
1225
| visit(node, ctx);
|
368 |
| } |
369 |
| } |
370 |
| |
371 |
| |
372 |
| |
373 |
| |
374 |
| |
375 |
| |
376 |
| |
377 |
224
| protected final void addViolation(Object data, SimpleNode node) {
|
378 |
224
| RuleContext ctx = (RuleContext) data;
|
379 |
224
| ctx.getReport().addRuleViolation(new RuleViolation(this, ctx, node));
|
380 |
| } |
381 |
| |
382 |
| |
383 |
| |
384 |
| |
385 |
| |
386 |
| |
387 |
| |
388 |
| |
389 |
2239
| protected final void addViolationWithMessage(Object data, SimpleNode node, String msg) {
|
390 |
2239
| RuleContext ctx = (RuleContext) data;
|
391 |
2239
| ctx.getReport().addRuleViolation(new RuleViolation(this, ctx, node, msg));
|
392 |
| } |
393 |
| |
394 |
| |
395 |
| |
396 |
| |
397 |
| |
398 |
| |
399 |
| |
400 |
| |
401 |
326
| protected final void addViolation(Object data, SimpleNode node, String embed) {
|
402 |
326
| RuleContext ctx = (RuleContext) data;
|
403 |
326
| ctx.getReport().addRuleViolation(new RuleViolation(this, ctx, node, MessageFormat.format(getMessage(), new Object[]{embed})));
|
404 |
| } |
405 |
| |
406 |
| |
407 |
| |
408 |
| |
409 |
| |
410 |
| |
411 |
| |
412 |
| |
413 |
62
| protected final void addViolation(Object data, Node node, Object[] args) {
|
414 |
62
| RuleContext ctx = (RuleContext) data;
|
415 |
62
| ctx.getReport().addRuleViolation(new RuleViolation(this, ctx, (SimpleNode) node, MessageFormat.format(getMessage(), args)));
|
416 |
| } |
417 |
| |
418 |
| |
419 |
| |
420 |
| |
421 |
| |
422 |
| |
423 |
12
| protected final String getDeclaringType(SimpleNode node) {
|
424 |
12
| ASTClassOrInterfaceDeclaration c = (ASTClassOrInterfaceDeclaration) node.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class);
|
425 |
12
| if (c != null)
|
426 |
12
| return c.getImage();
|
427 |
0
| return null;
|
428 |
| } |
429 |
| |
430 |
46
| public static boolean isQualifiedName(SimpleNode node) {
|
431 |
46
| return node.getImage().indexOf('.') != -1;
|
432 |
| } |
433 |
| |
434 |
0
| public static boolean importsPackage(ASTCompilationUnit node, String packageName) {
|
435 |
| |
436 |
0
| List nodes = node.findChildrenOfType(ASTImportDeclaration.class);
|
437 |
0
| for (Iterator i = nodes.iterator(); i.hasNext();) {
|
438 |
0
| ASTImportDeclaration n = (ASTImportDeclaration) i.next();
|
439 |
0
| if (n.getPackageName().startsWith(packageName)) {
|
440 |
0
| return true;
|
441 |
| } |
442 |
| } |
443 |
0
| return false;
|
444 |
| } |
445 |
| |
446 |
| |
447 |
| |
448 |
| |
449 |
| |
450 |
| |
451 |
| |
452 |
0
| protected Map propertiesByName() {
|
453 |
0
| return Collections.EMPTY_MAP;
|
454 |
| } |
455 |
| |
456 |
| |
457 |
| |
458 |
| |
459 |
| |
460 |
| |
461 |
| |
462 |
0
| public PropertyDescriptor propertyDescriptorFor(String propertyName) {
|
463 |
0
| PropertyDescriptor desc = (PropertyDescriptor)propertiesByName().get(propertyName);
|
464 |
0
| if (desc == null) throw new IllegalArgumentException("unknown property: " + propertyName);
|
465 |
0
| return desc;
|
466 |
| } |
467 |
| } |