001: /**
002: * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003: */package net.sourceforge.pmd;
004:
005: import java.io.File;
006: import java.util.ArrayList;
007: import java.util.Collection;
008: import java.util.Iterator;
009: import java.util.List;
010:
011: import net.sourceforge.pmd.util.Benchmark;
012: import net.sourceforge.pmd.util.filter.Filter;
013: import net.sourceforge.pmd.util.filter.Filters;
014:
015: /**
016: * This class represents a collection of rules.
017: *
018: * @see Rule
019: */
020: //FUTURE Implement Cloneable and clone()
021: public class RuleSet {
022:
023: private List<Rule> rules = new ArrayList<Rule>();
024: private String fileName;
025: private String name = "";
026: private String description = "";
027: private Language language;
028: private List<String> excludePatterns = new ArrayList<String>(0);
029: private List<String> includePatterns = new ArrayList<String>(0);
030: private Filter<File> filter;
031:
032: /**
033: * Returns the number of rules in this ruleset
034: *
035: * @return an int representing the number of rules
036: */
037: public int size() {
038: return rules.size();
039: }
040:
041: /**
042: * Add a new rule to this ruleset
043: *
044: * @param rule the rule to be added
045: */
046: public void addRule(Rule rule) {
047: if (rule == null) {
048: throw new RuntimeException(
049: "Null Rule reference added to a RuleSet; that's a bug somewhere in PMD");
050: }
051: rules.add(rule);
052: }
053:
054: /**
055: * Add a new rule by reference to this ruleset.
056: *
057: * @param ruleSetFileName the ruleset which contains the rule
058: * @param rule the rule to be added
059: */
060: public void addRuleByReference(String ruleSetFileName, Rule rule) {
061: if (ruleSetFileName == null) {
062: throw new RuntimeException(
063: "Adding a rule by reference is not allowed with a null rule set file name.");
064: }
065: if (rule == null) {
066: throw new RuntimeException(
067: "Null Rule reference added to a RuleSet; that's a bug somewhere in PMD");
068: }
069: if (!(rule instanceof RuleReference)) {
070: RuleSetReference ruleSetReference = new RuleSetReference();
071: ruleSetReference.setRuleSetFileName(ruleSetFileName);
072: RuleReference ruleReference = new RuleReference();
073: ruleReference.setRule(rule);
074: ruleReference.setRuleSetReference(ruleSetReference);
075: rule = ruleReference;
076: }
077: rules.add(rule);
078: }
079:
080: /**
081: * Returns the actual Collection of rules in this ruleset
082: *
083: * @return a Collection with the rules. All objects are of type {@link Rule}
084: */
085: public Collection<Rule> getRules() {
086: return rules;
087: }
088:
089: /**
090: * @return true if any rule in the RuleSet needs the DFA layer
091: */
092: public boolean usesDFA() {
093: for (Rule r : rules) {
094: if (r.usesDFA()) {
095: return true;
096: }
097: }
098: return false;
099: }
100:
101: /**
102: * Returns the Rule with the given name
103: *
104: * @param ruleName the name of the rule to find
105: * @return the rule or null if not found
106: */
107: public Rule getRuleByName(String ruleName) {
108: Rule rule = null;
109: for (Iterator<Rule> i = rules.iterator(); i.hasNext()
110: && (rule == null);) {
111: Rule r = i.next();
112: if (r.getName().equals(ruleName)) {
113: rule = r;
114: }
115: }
116: return rule;
117: }
118:
119: /**
120: * Add a whole RuleSet to this RuleSet
121: *
122: * @param ruleSet the RuleSet to add
123: */
124: public void addRuleSet(RuleSet ruleSet) {
125: rules.addAll(rules.size(), ruleSet.getRules());
126: }
127:
128: /**
129: * Add all rules by reference from one RuleSet to this RuleSet. The rules
130: * can be added as individual references, or collectively as an all rule
131: * reference.
132: *
133: * @param ruleSet the RuleSet to add
134: * @param allRules
135: */
136: public void addRuleSetByReference(RuleSet ruleSet, boolean allRules) {
137: if (ruleSet.getFileName() == null) {
138: throw new RuntimeException(
139: "Adding a rule by reference is not allowed with a null rule set file name.");
140: }
141: RuleSetReference ruleSetReference = new RuleSetReference();
142: ruleSetReference.setRuleSetFileName(ruleSet.getFileName());
143: ruleSetReference.setAllRules(allRules);
144: for (Rule rule : ruleSet.getRules()) {
145: RuleReference ruleReference = new RuleReference();
146: ruleReference.setRule(rule);
147: ruleReference.setRuleSetReference(ruleSetReference);
148: rules.add(ruleReference);
149: }
150: }
151:
152: /**
153: * Check if a given source file should be checked by rules in this RuleSet. A file
154: * should not be checked if there is an <code>exclude</code> pattern which matches
155: * the file, unless there is an <code>include</code> pattern which also matches
156: * the file. In other words, <code>include</code> patterns override <code>exclude</code>
157: * patterns.
158: *
159: * @param file the source file to check
160: * @return <code>true</code> if the file should be checked, <code>false</code> otherwise
161: */
162: public boolean applies(File file) {
163: // Initialize filter based on patterns
164: if (filter == null) {
165: Filter<String> regexFilter = Filters
166: .buildRegexFilterIncludeOverExclude(
167: includePatterns, excludePatterns);
168: filter = Filters.toNormalizedFileFilter(regexFilter);
169: }
170:
171: return file != null ? filter.filter(file) : true;
172: }
173:
174: public void start(RuleContext ctx) {
175: for (Rule rule : rules) {
176: rule.start(ctx);
177: }
178: }
179:
180: public void apply(List acuList, RuleContext ctx) {
181: long start = System.nanoTime();
182: for (Rule rule : rules) {
183: if (!rule.usesRuleChain()) {
184: rule.apply(acuList, ctx);
185: long end = System.nanoTime();
186: Benchmark.mark(Benchmark.TYPE_RULE, rule.getName(), end
187: - start, 1);
188: start = end;
189: }
190: }
191: }
192:
193: public void end(RuleContext ctx) {
194: for (Rule rule : rules) {
195: rule.end(ctx);
196: }
197: }
198:
199: /**
200: * @see java.lang.Object#equals(java.lang.Object)
201: */
202: public boolean equals(Object o) {
203: if ((o == null) || !(o instanceof RuleSet)) {
204: return false; // Trivial
205: }
206:
207: if (this == o) {
208: return true; // Basic equality
209: }
210:
211: RuleSet ruleSet = (RuleSet) o;
212: return this .getName().equals(ruleSet.getName())
213: && this .getRules().equals(ruleSet.getRules());
214: }
215:
216: /**
217: * @see java.lang.Object#hashCode()
218: */
219: public int hashCode() {
220: return this .getName().hashCode() + 13
221: * this .getRules().hashCode();
222: }
223:
224: public Language getLanguage() {
225: return language;
226: }
227:
228: public void setLanguage(Language language) {
229: this .language = language;
230: }
231:
232: public String getFileName() {
233: return fileName;
234: }
235:
236: public void setFileName(String fileName) {
237: this .fileName = fileName;
238: }
239:
240: public String getName() {
241: return name;
242: }
243:
244: public void setName(String name) {
245: this .name = name;
246: }
247:
248: public String getDescription() {
249: return description;
250: }
251:
252: public void setDescription(String description) {
253: this .description = description;
254: }
255:
256: public List<String> getExcludePatterns() {
257: return this .excludePatterns;
258: }
259:
260: public void addExcludePattern(String excludePattern) {
261: this .excludePatterns.add(excludePattern);
262: }
263:
264: public void addExcludePatterns(List<String> excludePatterns) {
265: this .excludePatterns.addAll(excludePatterns);
266: }
267:
268: public void setExcludePatterns(List<String> excludePatterns) {
269: this .excludePatterns = excludePatterns;
270: }
271:
272: public List<String> getIncludePatterns() {
273: return this .includePatterns;
274: }
275:
276: public void addIncludePattern(String includePattern) {
277: this .includePatterns.add(includePattern);
278: }
279:
280: public void addIncludePatterns(List<String> includePatterns) {
281: this .includePatterns.addAll(includePatterns);
282: }
283:
284: public void setIncludePatterns(List<String> includePatterns) {
285: this .includePatterns = includePatterns;
286: }
287:
288: public boolean usesTypeResolution() {
289: for (Rule r : rules) {
290: if (r.usesTypeResolution()) {
291: return true;
292: }
293: }
294: return false;
295: }
296:
297: }
|