1
2
3
4 package net.sourceforge.pmd.lang.rule;
5
6 import java.util.ArrayList;
7 import java.util.List;
8
9 import net.sourceforge.pmd.AbstractPropertySource;
10 import net.sourceforge.pmd.Rule;
11 import net.sourceforge.pmd.RuleContext;
12 import net.sourceforge.pmd.RulePriority;
13 import net.sourceforge.pmd.lang.Language;
14 import net.sourceforge.pmd.lang.LanguageVersion;
15 import net.sourceforge.pmd.lang.ParserOptions;
16 import net.sourceforge.pmd.lang.ast.Node;
17
18
19
20
21
22
23
24
25 public abstract class AbstractRule extends AbstractPropertySource implements Rule {
26
27 private Language language;
28 private LanguageVersion minimumLanguageVersion;
29 private LanguageVersion maximumLanguageVersion;
30 private boolean deprecated;
31 private String name = getClass().getName();
32 private String since;
33 private String ruleClass = getClass().getName();
34 private String ruleSetName;
35 private String message;
36 private String description;
37 private List<String> examples = new ArrayList<String>();
38 private String externalInfoUrl;
39 private RulePriority priority = RulePriority.LOW;
40 private boolean usesDFA;
41 private boolean usesTypeResolution;
42 private List<String> ruleChainVisits = new ArrayList<String>();
43
44 public AbstractRule() {
45 definePropertyDescriptor(Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR);
46 definePropertyDescriptor(Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR);
47 }
48
49 public void deepCopyValuesTo(AbstractRule otherRule) {
50 otherRule.language = language;
51 otherRule.minimumLanguageVersion = minimumLanguageVersion;
52 otherRule.maximumLanguageVersion = maximumLanguageVersion;
53 otherRule.deprecated = deprecated;
54 otherRule.name = name;
55 otherRule.since = since;
56 otherRule.ruleClass = ruleClass;
57 otherRule.ruleSetName = ruleSetName;
58 otherRule.message = message;
59 otherRule.description = description;
60 otherRule.examples = copyExamples();
61 otherRule.externalInfoUrl = externalInfoUrl;
62 otherRule.priority = priority;
63 otherRule.propertyDescriptors = copyPropertyDescriptors();
64 otherRule.propertyValuesByDescriptor = copyPropertyValues();
65 otherRule.usesDFA = usesDFA;
66 otherRule.usesTypeResolution = usesTypeResolution;
67 otherRule.ruleChainVisits = copyRuleChainVisits();
68 }
69
70 private List<String> copyExamples() {
71 List<String> copy = new ArrayList<String>(examples.size());
72 copy.addAll(examples);
73 return copy;
74 }
75
76 private List<String> copyRuleChainVisits() {
77 List<String> copy = new ArrayList<String>(ruleChainVisits.size());
78 copy.addAll(ruleChainVisits);
79 return copy;
80 }
81
82
83
84
85 public Language getLanguage() {
86 return language;
87 }
88
89
90
91
92 public void setLanguage(Language language) {
93 if (this.language != null && this instanceof ImmutableLanguage && !this.language.equals(language)) {
94 throw new UnsupportedOperationException("The Language for Rule class " + this.getClass().getName()
95 + " is immutable and cannot be changed.");
96 }
97 this.language = language;
98 }
99
100
101
102
103 public LanguageVersion getMinimumLanguageVersion() {
104 return minimumLanguageVersion;
105 }
106
107
108
109
110 public void setMinimumLanguageVersion(LanguageVersion minimumLanguageVersion) {
111 this.minimumLanguageVersion = minimumLanguageVersion;
112 }
113
114
115
116
117 public LanguageVersion getMaximumLanguageVersion() {
118 return maximumLanguageVersion;
119 }
120
121
122
123
124 public void setMaximumLanguageVersion(LanguageVersion maximumLanguageVersion) {
125 this.maximumLanguageVersion = maximumLanguageVersion;
126 }
127
128
129
130
131 public boolean isDeprecated() {
132 return deprecated;
133 }
134
135
136
137
138 public void setDeprecated(boolean deprecated) {
139 this.deprecated = deprecated;
140 }
141
142
143
144
145 public String getName() {
146 return name;
147 }
148
149
150
151
152 public void setName(String name) {
153 this.name = name;
154 }
155
156
157
158
159 public String getSince() {
160 return since;
161 }
162
163
164
165
166 public void setSince(String since) {
167 this.since = since;
168 }
169
170
171
172
173 public String getRuleClass() {
174 return ruleClass;
175 }
176
177
178
179
180 public void setRuleClass(String ruleClass) {
181 this.ruleClass = ruleClass;
182 }
183
184
185
186
187 public String getRuleSetName() {
188 return ruleSetName;
189 }
190
191
192
193
194 public void setRuleSetName(String ruleSetName) {
195 this.ruleSetName = ruleSetName;
196 }
197
198
199
200
201 public String getMessage() {
202 return message;
203 }
204
205
206
207
208 public void setMessage(String message) {
209 this.message = message;
210 }
211
212
213
214
215 public String getDescription() {
216 return description;
217 }
218
219
220
221
222 public void setDescription(String description) {
223 this.description = description;
224 }
225
226
227
228
229 public List<String> getExamples() {
230
231 return examples;
232 }
233
234
235
236
237 public void addExample(String example) {
238 examples.add(example);
239 }
240
241
242
243
244 public String getExternalInfoUrl() {
245 return externalInfoUrl;
246 }
247
248
249
250
251 public void setExternalInfoUrl(String externalInfoUrl) {
252 this.externalInfoUrl = externalInfoUrl;
253 }
254
255
256
257
258 public RulePriority getPriority() {
259 return priority;
260 }
261
262
263
264
265 public void setPriority(RulePriority priority) {
266 this.priority = priority;
267 }
268
269
270
271
272
273
274 public ParserOptions getParserOptions() {
275 return new ParserOptions();
276 }
277
278
279
280
281 public void setUsesDFA() {
282 usesDFA = true;
283 }
284
285
286
287
288 public boolean usesDFA() {
289 return usesDFA;
290 }
291
292
293
294
295 public void setUsesTypeResolution() {
296 usesTypeResolution = true;
297 }
298
299
300
301
302 public boolean usesTypeResolution() {
303 return usesTypeResolution;
304 }
305
306
307
308
309 public boolean usesRuleChain() {
310 return !getRuleChainVisits().isEmpty();
311 }
312
313
314
315
316 public List<String> getRuleChainVisits() {
317 return ruleChainVisits;
318 }
319
320
321
322
323 public void addRuleChainVisit(Class<? extends Node> nodeClass) {
324 if (!nodeClass.getSimpleName().startsWith("AST")) {
325 throw new IllegalArgumentException("Node class does not start with 'AST' prefix: " + nodeClass);
326 }
327 addRuleChainVisit(nodeClass.getSimpleName().substring("AST".length()));
328 }
329
330
331
332
333 public void addRuleChainVisit(String astNodeName) {
334 if (!ruleChainVisits.contains(astNodeName)) {
335 ruleChainVisits.add(astNodeName);
336 }
337 }
338
339
340
341
342 public void start(RuleContext ctx) {
343
344 }
345
346
347
348
349 public void end(RuleContext ctx) {
350
351 }
352
353
354
355
356 public void addViolation(Object data, Node node) {
357 RuleContext ruleContext = (RuleContext) data;
358 ruleContext.getLanguageVersion().getLanguageVersionHandler().getRuleViolationFactory().addViolation(
359 ruleContext, this, node, this.getMessage(), null);
360 }
361
362
363
364
365 public void addViolation(Object data, Node node, String arg) {
366 RuleContext ruleContext = (RuleContext) data;
367 ruleContext.getLanguageVersion().getLanguageVersionHandler().getRuleViolationFactory().addViolation(
368 ruleContext, this, node, this.getMessage(), new Object[] { arg });
369 }
370
371
372
373
374 public void addViolation(Object data, Node node, Object[] args) {
375 RuleContext ruleContext = (RuleContext) data;
376 ruleContext.getLanguageVersion().getLanguageVersionHandler().getRuleViolationFactory().addViolation(
377 ruleContext, this, node, this.getMessage(), args);
378 }
379
380
381
382
383 public void addViolationWithMessage(Object data, Node node, String message) {
384 RuleContext ruleContext = (RuleContext) data;
385 ruleContext.getLanguageVersion().getLanguageVersionHandler().getRuleViolationFactory().addViolation(
386 ruleContext, this, node, message, null);
387 }
388
389
390
391
392 public void addViolationWithMessage(Object data, Node node, String message, int beginLine, int endLine) {
393 RuleContext ruleContext = (RuleContext) data;
394 ruleContext.getLanguageVersion().getLanguageVersionHandler().getRuleViolationFactory().addViolation(
395 ruleContext, this, node, message, beginLine, endLine, null
396 );
397 }
398
399
400
401
402 public void addViolationWithMessage(Object data, Node node, String message, Object[] args) {
403 RuleContext ruleContext = (RuleContext) data;
404 ruleContext.getLanguageVersion().getLanguageVersionHandler().getRuleViolationFactory().addViolation(
405 ruleContext, this, node, message, args);
406 }
407
408
409
410
411
412
413
414
415
416
417 @Override
418 public boolean equals(Object o) {
419 if (o == null) {
420 return false;
421 }
422
423 if (this == o) {
424 return true;
425 }
426
427 boolean equality = getClass() == o.getClass();
428
429 if (equality) {
430 Rule that = (Rule) o;
431 equality = getName().equals(that.getName()) && getPriority().equals(that.getPriority())
432 && getPropertiesByPropertyDescriptor().equals(that.getPropertiesByPropertyDescriptor());
433 }
434
435 return equality;
436 }
437
438
439
440
441 @Override
442 public int hashCode() {
443 Object propertyValues = getPropertiesByPropertyDescriptor();
444 return getClass().getName().hashCode() + (getName() != null ? getName().hashCode() : 0)
445 + getPriority().hashCode() + (propertyValues != null ? propertyValues.hashCode() : 0);
446 }
447 }