1
2
3
4 package net.sourceforge.pmd;
5
6 import java.io.File;
7 import java.util.ArrayList;
8 import java.util.Arrays;
9 import java.util.Collection;
10 import java.util.HashSet;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.logging.Level;
14 import java.util.logging.Logger;
15
16 import net.sourceforge.pmd.benchmark.Benchmark;
17 import net.sourceforge.pmd.benchmark.Benchmarker;
18 import net.sourceforge.pmd.lang.Language;
19 import net.sourceforge.pmd.lang.LanguageVersion;
20 import net.sourceforge.pmd.lang.ast.Node;
21 import net.sourceforge.pmd.lang.rule.RuleReference;
22 import net.sourceforge.pmd.util.CollectionUtil;
23 import net.sourceforge.pmd.util.StringUtil;
24 import net.sourceforge.pmd.util.filter.Filter;
25 import net.sourceforge.pmd.util.filter.Filters;
26
27
28
29
30
31
32
33
34 public class RuleSet {
35
36 private static final Logger LOG = Logger.getLogger(RuleSet.class.getName());
37
38 private List<Rule> rules = new ArrayList<Rule>();
39 private String fileName;
40 private String name = "";
41 private String description = "";
42
43
44 private List<String> excludePatterns = new ArrayList<String>(0);
45 private List<String> includePatterns = new ArrayList<String>(0);
46
47 private Filter<File> filter;
48
49
50
51
52
53
54
55
56 public static RuleSet createFor(String name, Rule... theRules) {
57
58 RuleSet rs = new RuleSet();
59 rs.setName(name);
60 for (Rule rule : theRules) {
61 rs.addRule(rule);
62 }
63 return rs;
64 }
65
66
67
68
69
70
71 public int size() {
72 return rules.size();
73 }
74
75
76
77
78
79
80 public void addRule(Rule rule) {
81 if (rule == null) {
82 throw new IllegalArgumentException("Missing rule");
83 }
84 rules.add(rule);
85 }
86
87
88
89
90
91
92
93 public boolean addRuleReplaceIfExists(Rule rule) {
94 if (rule == null) {
95 throw new IllegalArgumentException("Missing rule");
96 }
97
98 boolean replaced = false;
99 for (Iterator<Rule> it = rules.iterator(); it.hasNext(); ) {
100 Rule r = it.next();
101 if (r.getName().equals(rule.getName()) && r.getLanguage() == rule.getLanguage()) {
102 it.remove();
103 replaced = true;
104 }
105 }
106 addRule(rule);
107 return replaced;
108 }
109
110
111
112
113
114
115
116 public boolean addRuleIfNotExists(Rule rule) {
117 if (rule == null) {
118 throw new IllegalArgumentException("Missing rule");
119 }
120
121 boolean exists = false;
122 for (Rule r : rules) {
123 if (r.getName().equals(rule.getName()) && r.getLanguage() == rule.getLanguage()) {
124 exists = true;
125 break;
126 }
127 }
128 if (!exists) {
129 addRule(rule);
130 }
131 return !exists;
132 }
133
134
135
136
137
138
139
140 public void addRuleByReference(String ruleSetFileName, Rule rule) {
141 if (StringUtil.isEmpty(ruleSetFileName)) {
142 throw new RuntimeException("Adding a rule by reference is not allowed with an empty rule set file name.");
143 }
144 if (rule == null) {
145 throw new IllegalArgumentException("Cannot add a null rule reference to a RuleSet");
146 }
147 if (!(rule instanceof RuleReference)) {
148 RuleSetReference ruleSetReference = new RuleSetReference();
149 ruleSetReference.setRuleSetFileName(ruleSetFileName);
150 RuleReference ruleReference = new RuleReference();
151 ruleReference.setRule(rule);
152 ruleReference.setRuleSetReference(ruleSetReference);
153 rule = ruleReference;
154 }
155 rules.add(rule);
156 }
157
158
159
160
161
162
163 public Collection<Rule> getRules() {
164 return rules;
165 }
166
167
168
169
170
171
172
173 public boolean usesDFA(Language language) {
174 for (Rule r : rules) {
175 if (r.getLanguage().equals(language)) {
176 if (r.usesDFA()) {
177 return true;
178 }
179 }
180 }
181 return false;
182 }
183
184
185
186
187
188
189
190
191
192
193
194 public Rule getRuleByName(String ruleName) {
195
196 for (Rule r : rules) {
197 if (r.getName().equals(ruleName)) {
198 return r;
199 }
200 }
201 return null;
202 }
203
204
205
206
207
208
209 public void addRuleSet(RuleSet ruleSet) {
210 rules.addAll(rules.size(), ruleSet.getRules());
211 }
212
213
214
215
216
217
218
219
220
221 public void addRuleSetByReference(RuleSet ruleSet, boolean allRules) {
222 addRuleSetByReference(ruleSet, allRules, (String[])null);
223 }
224
225
226
227
228
229
230
231
232
233
234 public void addRuleSetByReference(RuleSet ruleSet, boolean allRules, String ... excludes) {
235 if (StringUtil.isEmpty(ruleSet.getFileName())) {
236 throw new RuntimeException("Adding a rule by reference is not allowed with an empty rule set file name.");
237 }
238 RuleSetReference ruleSetReference = new RuleSetReference(ruleSet.getFileName());
239 ruleSetReference.setAllRules(allRules);
240 if (excludes != null) {
241 ruleSetReference.setExcludes(new HashSet<String>(Arrays.asList(excludes)));
242 }
243 for (Rule rule : ruleSet.getRules()) {
244 RuleReference ruleReference = new RuleReference(rule, ruleSetReference);
245 rules.add(ruleReference);
246 }
247 }
248
249
250
251
252
253
254
255
256
257
258
259 public boolean applies(File file) {
260
261 if (filter == null) {
262 Filter<String> regexFilter = Filters.buildRegexFilterIncludeOverExclude(includePatterns, excludePatterns);
263 filter = Filters.toNormalizedFileFilter(regexFilter);
264 }
265
266 return file != null ? filter.filter(file) : true;
267 }
268
269 public void start(RuleContext ctx) {
270 for (Rule rule : rules) {
271 rule.start(ctx);
272 }
273 }
274
275 public void apply(List<? extends Node> acuList, RuleContext ctx) {
276 long start = System.nanoTime();
277 for (Rule rule : rules) {
278 try {
279 if (!rule.usesRuleChain() && applies(rule, ctx.getLanguageVersion())) {
280 rule.apply(acuList, ctx);
281 long end = System.nanoTime();
282 Benchmarker.mark(Benchmark.Rule, rule.getName(), end - start, 1);
283 start = end;
284 }
285 } catch (ThreadDeath td) {
286 throw td;
287 } catch (Throwable t) {
288 LOG.log(Level.WARNING, "Exception applying rule " + rule.getName() + ", continuing with next rule", t);
289 }
290 }
291 }
292
293
294
295
296
297
298
299
300
301 public static boolean applies(Rule rule, LanguageVersion languageVersion) {
302 final LanguageVersion min = rule.getMinimumLanguageVersion();
303 final LanguageVersion max = rule.getMinimumLanguageVersion();
304 return rule.getLanguage().equals(languageVersion.getLanguage())
305 && (min == null || min.compareTo(languageVersion) <= 0)
306 && (max == null || max.compareTo(languageVersion) >= 0);
307 }
308
309 public void end(RuleContext ctx) {
310 for (Rule rule : rules) {
311 rule.end(ctx);
312 }
313 }
314
315
316
317
318 @Override
319 public boolean equals(Object o) {
320 if (!(o instanceof RuleSet)) {
321 return false;
322 }
323
324 if (this == o) {
325 return true;
326 }
327
328 RuleSet ruleSet = (RuleSet) o;
329 return getName().equals(ruleSet.getName()) && getRules().equals(ruleSet.getRules());
330 }
331
332
333
334
335 @Override
336 public int hashCode() {
337 return getName().hashCode() + 13 * getRules().hashCode();
338 }
339
340 public String getFileName() {
341 return fileName;
342 }
343
344 public void setFileName(String fileName) {
345 this.fileName = fileName;
346 }
347
348 public String getName() {
349 return name;
350 }
351
352 public void setName(String name) {
353 this.name = name;
354 }
355
356 public String getDescription() {
357 return description;
358 }
359
360 public void setDescription(String description) {
361 this.description = description;
362 }
363
364 public List<String> getExcludePatterns() {
365 return excludePatterns;
366 }
367
368 public void addExcludePattern(String aPattern) {
369
370 if (excludePatterns.contains(aPattern)) return;
371
372 excludePatterns.add(aPattern);
373 patternsChanged();
374 }
375
376 public void addExcludePatterns(Collection<String> someExcludePatterns) {
377
378 int added = CollectionUtil.addWithoutDuplicates(someExcludePatterns, excludePatterns);
379 if (added > 0) patternsChanged();
380 }
381
382 public void setExcludePatterns(Collection<String> theExcludePatterns) {
383
384 if (excludePatterns.equals(theExcludePatterns)) return;
385
386 excludePatterns.clear();
387 CollectionUtil.addWithoutDuplicates(theExcludePatterns, excludePatterns);
388 patternsChanged();
389 }
390
391 public List<String> getIncludePatterns() {
392 return includePatterns;
393 }
394
395 public void addIncludePattern(String aPattern) {
396
397 if (includePatterns.contains(aPattern)) return;
398
399 includePatterns.add(aPattern);
400 patternsChanged();
401 }
402
403 public void addIncludePatterns(Collection<String> someIncludePatterns) {
404
405 int added = CollectionUtil.addWithoutDuplicates(someIncludePatterns, includePatterns);
406 if (added > 0) patternsChanged();
407 }
408
409 public void setIncludePatterns(Collection<String> theIncludePatterns) {
410
411 if (includePatterns.equals(theIncludePatterns)) return;
412
413 includePatterns.clear();
414 CollectionUtil.addWithoutDuplicates(theIncludePatterns, includePatterns);
415 patternsChanged();
416 }
417
418 private void patternsChanged() {
419 filter = null;
420 }
421
422
423
424
425
426
427
428 public boolean usesTypeResolution(Language language) {
429 for (Rule r : rules) {
430 if (r.getLanguage().equals(language)) {
431 if (r.usesTypeResolution()) {
432 return true;
433 }
434 }
435 }
436 return false;
437 }
438
439
440
441
442
443
444 public void removeDysfunctionalRules(Collection<Rule> collector) {
445
446 Iterator<Rule> iter = rules.iterator();
447
448 while (iter.hasNext()) {
449 Rule rule = iter.next();
450 if (rule.dysfunctionReason() != null) {
451 iter.remove();
452 collector.add(rule);
453 }
454 }
455 }
456
457 }