/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import net.sourceforge.pmd.lang.Language;
import net.sourceforge.pmd.lang.ast.Node;
/**
* Grouping of Rules per Language in a RuleSet.
*
* @author pieter_van_raemdonck - Application Engineers NV/SA - www.ae.be
*/
public class RuleSets {
/**
* Map of RuleLanguage on RuleSet.
*/
private List<RuleSet> ruleSets = new ArrayList<>();
/**
* RuleChain for efficient AST visitation.
*/
private RuleChain ruleChain = new RuleChain();
/**
* Public constructor.
*/
public RuleSets() {
}
/**
* Public constructor. Add the given rule set.
*
* @param ruleSet
* the RuleSet
*/
public RuleSets(RuleSet ruleSet) {
this();
addRuleSet(ruleSet);
}
/**
* Add a ruleset for a language. Only one ruleset can be added for a
* specific language. If ruleSet.getLanguage() is null, it is assumed to be
* a RuleSet of java rules.
*
* @param ruleSet
* the RuleSet
*/
public void addRuleSet(RuleSet ruleSet) {
ruleSets.add(ruleSet);
ruleChain.add(ruleSet);
}
/**
* Get all the RuleSets.
*
* @return RuleSet[]
*/
public RuleSet[] getAllRuleSets() {
return ruleSets.toArray(new RuleSet[ruleSets.size()]);
}
public Iterator<RuleSet> getRuleSetsIterator() {
return ruleSets.iterator();
}
/**
* Return all rules from all rulesets.
*
* @return Set
*/
public Set<Rule> getAllRules() {
Set<Rule> result = new HashSet<>();
for (RuleSet r : ruleSets) {
result.addAll(r.getRules());
}
return result;
}
/**
* Check if a given source file should be checked by rules in this RuleSets.
*
* @param file
* the source file to check
* @return <code>true</code> if the file should be checked,
* <code>false</code> otherwise
*/
public boolean applies(File file) {
for (RuleSet ruleSet : ruleSets) {
if (ruleSet.applies(file)) {
return true;
}
}
return false;
}
/**
* Notify all rules of the start of processing.
*/
public void start(RuleContext ctx) {
for (RuleSet ruleSet : ruleSets) {
ruleSet.start(ctx);
}
}
/**
* Apply all applicable rules to the compilation units. Applicable means the
* language of the rules must match the language of the source (@see
* applies).
*
* @param acuList
* the List of compilation units; the type these must have,
* depends on the source language
* @param ctx
* the RuleContext
* @param language
* the Language of the source
*/
public void apply(List<Node> acuList, RuleContext ctx, Language language) {
ruleChain.apply(acuList, ctx, language);
for (RuleSet ruleSet : ruleSets) {
if (ruleSet.applies(ctx.getSourceCodeFile())) {
ruleSet.apply(acuList, ctx);
}
}
}
/**
* Notify all rules of the end of processing.
*/
public void end(RuleContext ctx) {
for (RuleSet ruleSet : ruleSets) {
ruleSet.end(ctx);
}
}
/**
* Check if the rules that apply to a source of the given language use DFA.
*
* @param language
* the language of a source
* @return true if any rule in the RuleSet needs the DFA layer
*/
public boolean usesDFA(Language language) {
for (RuleSet ruleSet : ruleSets) {
if (ruleSet.usesDFA(language)) {
return true;
}
}
return false;
}
/**
* Returns the first Rule found with the given name.
*
* Note: Since we support multiple languages, rule names are not expected to
* be unique within any specific ruleset.
*
* @param ruleName
* the exact name of the rule to find
* @return the rule or null if not found
*/
public Rule getRuleByName(String ruleName) {
Rule rule = null;
for (Iterator<RuleSet> i = ruleSets.iterator(); i.hasNext() && rule == null;) {
RuleSet ruleSet = i.next();
rule = ruleSet.getRuleByName(ruleName);
}
return rule;
}
/**
* Determines the total count of rules that are used in all rule sets.
*
* @return the count
*/
public int ruleCount() {
int count = 0;
for (RuleSet r : ruleSets) {
count += r.getRules().size();
}
return count;
}
public boolean usesTypeResolution(Language language) {
for (RuleSet ruleSet : ruleSets) {
if (ruleSet.usesTypeResolution(language)) {
return true;
}
}
return false;
}
/**
* Remove and collect any rules that report problems.
*
* @param collector
*/
public void removeDysfunctionalRules(Collection<Rule> collector) {
for (RuleSet ruleSet : ruleSets) {
ruleSet.removeDysfunctionalRules(collector);
}
}
/**
* Retrieves a checksum of the rulesets being used. Any change to any rule
* of any ruleset should trigger a checksum change.
*
* @return The checksum for this ruleset collection.
*/
public long getChecksum() {
long checksum = 1;
for (final RuleSet ruleSet : ruleSets) {
checksum = checksum * 31 + ruleSet.getChecksum();
}
return checksum;
}
}