1 /**
2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 */
4 package net.sourceforge.pmd;
5
6 import java.io.File;
7 import java.util.ArrayList;
8 import java.util.Collection;
9 import java.util.Iterator;
10 import java.util.List;
11
12 import net.sourceforge.pmd.util.Benchmark;
13 import net.sourceforge.pmd.util.filter.Filter;
14 import net.sourceforge.pmd.util.filter.Filters;
15
16
17 /**
18 * This class represents a collection of rules.
19 *
20 * @see Rule
21 */
22
23 public class RuleSet {
24
25 private List<Rule> rules = new ArrayList<Rule>();
26 private String fileName;
27 private String name = "";
28 private String description = "";
29 private Language language;
30 private List<String> excludePatterns = new ArrayList<String>(0);
31 private List<String> includePatterns = new ArrayList<String>(0);
32 private Filter<File> filter;
33
34 /**
35 * Returns the number of rules in this ruleset
36 *
37 * @return an int representing the number of rules
38 */
39 public int size() {
40 return rules.size();
41 }
42
43 /**
44 * Add a new rule to this ruleset
45 *
46 * @param rule the rule to be added
47 */
48 public void addRule(Rule rule) {
49 if (rule == null) {
50 throw new RuntimeException("Null Rule reference added to a RuleSet; that's a bug somewhere in PMD");
51 }
52 rules.add(rule);
53 }
54
55 /**
56 * Add a new rule by reference to this ruleset.
57 *
58 * @param ruleSetFileName the ruleset which contains the rule
59 * @param rule the rule to be added
60 */
61 public void addRuleByReference(String ruleSetFileName, Rule rule) {
62 if (ruleSetFileName == null) {
63 throw new RuntimeException("Adding a rule by reference is not allowed with a null rule set file name.");
64 }
65 if (rule == null) {
66 throw new RuntimeException("Null Rule reference added to a RuleSet; that's a bug somewhere in PMD");
67 }
68 if (!(rule instanceof RuleReference)) {
69 RuleSetReference ruleSetReference = new RuleSetReference();
70 ruleSetReference.setRuleSetFileName(ruleSetFileName);
71 RuleReference ruleReference = new RuleReference();
72 ruleReference.setRule(rule);
73 ruleReference.setRuleSetReference(ruleSetReference);
74 rule = ruleReference;
75 }
76 rules.add(rule);
77 }
78
79 /**
80 * Returns the actual Collection of rules in this ruleset
81 *
82 * @return a Collection with the rules. All objects are of type {@link Rule}
83 */
84 public Collection<Rule> getRules() {
85 return rules;
86 }
87
88 /**
89 * @return true if any rule in the RuleSet needs the DFA layer
90 */
91 public boolean usesDFA() {
92 for (Rule r: rules) {
93 if (r.usesDFA()) {
94 return true;
95 }
96 }
97 return false;
98 }
99
100 /**
101 * Returns the Rule with the given name
102 *
103 * @param ruleName the name of the rule to find
104 * @return the rule or null if not found
105 */
106 public Rule getRuleByName(String ruleName) {
107 Rule rule = null;
108 for (Iterator<Rule> i = rules.iterator(); i.hasNext() && (rule == null);) {
109 Rule r = i.next();
110 if (r.getName().equals(ruleName)) {
111 rule = r;
112 }
113 }
114 return rule;
115 }
116
117 /**
118 * Add a whole RuleSet to this RuleSet
119 *
120 * @param ruleSet the RuleSet to add
121 */
122 public void addRuleSet(RuleSet ruleSet) {
123 rules.addAll(rules.size(), ruleSet.getRules());
124 }
125
126 /**
127 * Add all rules by reference from one RuleSet to this RuleSet. The rules
128 * can be added as individual references, or collectively as an all rule
129 * reference.
130 *
131 * @param ruleSet the RuleSet to add
132 * @param allRules
133 */
134 public void addRuleSetByReference(RuleSet ruleSet, boolean allRules) {
135 if (ruleSet.getFileName() == null) {
136 throw new RuntimeException("Adding a rule by reference is not allowed with a null rule set file name.");
137 }
138 RuleSetReference ruleSetReference = new RuleSetReference();
139 ruleSetReference.setRuleSetFileName(ruleSet.getFileName());
140 ruleSetReference.setAllRules(allRules);
141 for(Rule rule: ruleSet.getRules()) {
142 RuleReference ruleReference = new RuleReference();
143 ruleReference.setRule(rule);
144 ruleReference.setRuleSetReference(ruleSetReference);
145 rules.add(ruleReference);
146 }
147 }
148
149 /**
150 * Check if a given source file should be checked by rules in this RuleSet. A file
151 * should not be checked if there is an <code>exclude</code> pattern which matches
152 * the file, unless there is an <code>include</code> pattern which also matches
153 * the file. In other words, <code>include</code> patterns override <code>exclude</code>
154 * patterns.
155 *
156 * @param file the source file to check
157 * @return <code>true</code> if the file should be checked, <code>false</code> otherwise
158 */
159 public boolean applies(File file) {
160
161 if (filter == null) {
162 Filter<String> regexFilter = Filters.buildRegexFilterIncludeOverExclude(includePatterns, excludePatterns);
163 filter = Filters.toNormalizedFileFilter(regexFilter);
164 }
165
166 return file != null ? filter.filter(file) : true;
167 }
168
169 public void start(RuleContext ctx) {
170 for (Rule rule: rules) {
171 rule.start(ctx);
172 }
173 }
174
175 public void apply(List acuList, RuleContext ctx) {
176 long start = System.nanoTime();
177 for (Rule rule: rules) {
178 if (!rule.usesRuleChain()) {
179 rule.apply(acuList, ctx);
180 long end = System.nanoTime();
181 Benchmark.mark(Benchmark.TYPE_RULE, rule.getName(), end - start, 1);
182 start = end;
183 }
184 }
185 }
186
187 public void end(RuleContext ctx) {
188 for (Rule rule: rules) {
189 rule.end(ctx);
190 }
191 }
192
193 /**
194 * @see java.lang.Object#equals(java.lang.Object)
195 */
196 public boolean equals(Object o) {
197 if ((o == null) || !(o instanceof RuleSet)) {
198 return false;
199 }
200
201 if (this == o) {
202 return true;
203 }
204
205 RuleSet ruleSet = (RuleSet) o;
206 return this.getName().equals(ruleSet.getName()) && this.getRules().equals(ruleSet.getRules());
207 }
208
209 /**
210 * @see java.lang.Object#hashCode()
211 */
212 public int hashCode() {
213 return this.getName().hashCode() + 13 * this.getRules().hashCode();
214 }
215
216 public Language getLanguage() {
217 return language;
218 }
219
220 public void setLanguage(Language language) {
221 this.language = language;
222 }
223
224 public String getFileName() {
225 return fileName;
226 }
227
228 public void setFileName(String fileName) {
229 this.fileName = fileName;
230 }
231
232 public String getName() {
233 return name;
234 }
235
236 public void setName(String name) {
237 this.name = name;
238 }
239
240 public String getDescription() {
241 return description;
242 }
243
244 public void setDescription(String description) {
245 this.description = description;
246 }
247
248 public List<String> getExcludePatterns() {
249 return this.excludePatterns;
250 }
251
252 public void addExcludePattern(String excludePattern) {
253 this.excludePatterns.add(excludePattern);
254 }
255
256 public void addExcludePatterns(List<String> excludePatterns) {
257 this.excludePatterns.addAll(excludePatterns);
258 }
259
260 public void setExcludePatterns(List<String> excludePatterns) {
261 this.excludePatterns = excludePatterns;
262 }
263
264 public List<String> getIncludePatterns() {
265 return this.includePatterns;
266 }
267
268 public void addIncludePattern(String includePattern) {
269 this.includePatterns.add(includePattern);
270 }
271
272 public void addIncludePatterns(List<String> includePatterns) {
273 this.includePatterns.addAll(includePatterns);
274 }
275
276 public void setIncludePatterns(List<String> includePatterns) {
277 this.includePatterns = includePatterns;
278 }
279
280 public boolean usesTypeResolution() {
281 for (Rule r: rules) {
282 if (r.usesTypeResolution()) {
283 return true;
284 }
285 }
286 return false;
287 }
288
289 }