Update RuleChainVisitor to group rules by RuleSet, and use RuleSet.applies(File) before visiting.
git-svn-id: https://pmd.svn.sourceforge.net/svnroot/pmd/branches/pmd/4.2.x@6170 51baf565-9d33-0410-a72c-fc3788e3496d
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
???? - 4.2.3:
|
||||
|
||||
Fixes for exclude-pattern
|
||||
Updates to RuleChain to honor RuleSet exclude-pattern
|
||||
|
||||
May 20, 2008 - 4.2.2:
|
||||
|
||||
|
@ -19,11 +19,14 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sourceforge.pmd.MockRule;
|
||||
import net.sourceforge.pmd.PMD;
|
||||
import net.sourceforge.pmd.PMDException;
|
||||
import net.sourceforge.pmd.Report;
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.RuleContext;
|
||||
import net.sourceforge.pmd.RuleReference;
|
||||
import net.sourceforge.pmd.RuleSet;
|
||||
import net.sourceforge.pmd.RuleSets;
|
||||
import net.sourceforge.pmd.RuleViolation;
|
||||
import net.sourceforge.pmd.TargetJDKVersion;
|
||||
import net.sourceforge.pmd.ast.ASTCompilationUnit;
|
||||
@ -31,7 +34,9 @@ import net.sourceforge.pmd.ast.JavaParser;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class RuleSetTest {
|
||||
import test.net.sourceforge.pmd.testframework.RuleTst;
|
||||
|
||||
public class RuleSetTest extends RuleTst {
|
||||
|
||||
private String javaCode = "public class Test { }";
|
||||
|
||||
@ -328,6 +333,50 @@ public class RuleSetTest {
|
||||
assertTrue("Matching include", ruleSet.applies(file));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncludeExcludeMultipleRuleSetWithRuleChainApplies() throws PMDException {
|
||||
File file = new File("C:\\myworkspace\\project\\some\\random\\package\\RandomClass.java");
|
||||
|
||||
RuleSet ruleSet1 = new RuleSet();
|
||||
ruleSet1.setName("RuleSet1");
|
||||
Rule rule = findRule("basic", "EmptyIfStmt");
|
||||
assertTrue("RuleChain rule", rule.usesRuleChain());
|
||||
ruleSet1.addRule(rule);
|
||||
|
||||
RuleSet ruleSet2 = new RuleSet();
|
||||
ruleSet2.setName("RuleSet2");
|
||||
ruleSet2.addRule(rule);
|
||||
|
||||
RuleSets ruleSets = new RuleSets();
|
||||
ruleSets.addRuleSet(ruleSet1);
|
||||
ruleSets.addRuleSet(ruleSet2);
|
||||
|
||||
// Two violations
|
||||
PMD p = new PMD();
|
||||
RuleContext ctx = new RuleContext();
|
||||
Report r = new Report();
|
||||
ctx.setReport(r);
|
||||
ctx.setSourceCodeFilename(file.getName());
|
||||
ctx.setSourceCodeFile(file);
|
||||
p.processFile(new StringReader(TEST1), ruleSets, ctx);
|
||||
assertEquals("Violations", 2, r.size());
|
||||
|
||||
// One violation
|
||||
ruleSet1 = new RuleSet();
|
||||
ruleSet1.setName("RuleSet1");
|
||||
ruleSet1.addExcludePattern(".*/package/.*");
|
||||
ruleSet1.addRule(rule);
|
||||
|
||||
ruleSets = new RuleSets();
|
||||
ruleSets.addRuleSet(ruleSet1);
|
||||
ruleSets.addRuleSet(ruleSet2);
|
||||
|
||||
r = new Report();
|
||||
ctx.setReport(r);
|
||||
p.processFile(new StringReader(TEST1), ruleSets, ctx);
|
||||
assertEquals("Violations", 1, r.size());
|
||||
}
|
||||
|
||||
protected void verifyRuleSet(RuleSet IUT, int size, Set values) throws Throwable {
|
||||
|
||||
RuleContext context = new RuleContext();
|
||||
@ -359,6 +408,12 @@ public class RuleSetTest {
|
||||
RC.add(parser.CompilationUnit());
|
||||
return RC;
|
||||
}
|
||||
|
||||
private static final String TEST1 = "public class Foo {" + PMD.EOL +
|
||||
" public void foo() {" + PMD.EOL +
|
||||
" if (true) { }" + PMD.EOL +
|
||||
" }" + PMD.EOL +
|
||||
"}" + PMD.EOL;
|
||||
|
||||
public static junit.framework.Test suite() {
|
||||
return new junit.framework.JUnit4TestAdapter(RuleSetTest.class);
|
||||
|
@ -4,6 +4,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -19,9 +20,9 @@ import net.sourceforge.pmd.util.Benchmark;
|
||||
*/
|
||||
public abstract class AbstractRuleChainVisitor implements RuleChainVisitor {
|
||||
/**
|
||||
* These are all the rules participating in the RuleChain.
|
||||
* These are all the rules participating in the RuleChain, grouped by RuleSet.
|
||||
*/
|
||||
protected List<Rule> rules = new ArrayList<Rule>();
|
||||
protected Map<RuleSet, List<Rule>> ruleSetRules = new LinkedHashMap<RuleSet, List<Rule>>();
|
||||
|
||||
/**
|
||||
* This is a mapping from node names to nodes instances for the current AST.
|
||||
@ -29,10 +30,13 @@ public abstract class AbstractRuleChainVisitor implements RuleChainVisitor {
|
||||
protected Map<String, List<SimpleNode>> nodeNameToNodes;
|
||||
|
||||
/**
|
||||
* @see RuleChainVisitor#add(Rule)
|
||||
* @see RuleChainVisitor#add(RuleSet, Rule)
|
||||
*/
|
||||
public void add(Rule rule) {
|
||||
rules.add(rule);
|
||||
public void add(RuleSet ruleSet, Rule rule) {
|
||||
if (!ruleSetRules.containsKey(ruleSet)) {
|
||||
ruleSetRules.put(ruleSet, new ArrayList<Rule>());
|
||||
}
|
||||
ruleSetRules.get(ruleSet).add(rule);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,25 +53,31 @@ public abstract class AbstractRuleChainVisitor implements RuleChainVisitor {
|
||||
long end = System.nanoTime();
|
||||
Benchmark.mark(Benchmark.TYPE_RULE_CHAIN_VISIT, end - start, 1);
|
||||
|
||||
// For each rule, allow it to visit the nodes it desires
|
||||
int visits = 0;
|
||||
start = System.nanoTime();
|
||||
for (Rule rule: rules) {
|
||||
final List<String> nodeNames = rule.getRuleChainVisits();
|
||||
for (int j = 0; j < nodeNames.size(); j++) {
|
||||
List<SimpleNode> nodes = nodeNameToNodes.get(nodeNames.get(j));
|
||||
for (SimpleNode node: nodes) {
|
||||
// Visit with underlying Rule, not the RuleReference
|
||||
while (rule instanceof RuleReference) {
|
||||
rule = ((RuleReference)rule).getRule();
|
||||
}
|
||||
visit(rule, node, ctx);
|
||||
}
|
||||
visits += nodes.size();
|
||||
// For each RuleSet, only if this source file applies
|
||||
for (RuleSet ruleSet : ruleSetRules.keySet()) {
|
||||
if (!ruleSet.applies(ctx.getSourceCodeFile())) {
|
||||
continue;
|
||||
}
|
||||
// For each rule, allow it to visit the nodes it desires
|
||||
int visits = 0;
|
||||
start = System.nanoTime();
|
||||
for (Rule rule: ruleSetRules.get(ruleSet)) {
|
||||
final List<String> nodeNames = rule.getRuleChainVisits();
|
||||
for (int j = 0; j < nodeNames.size(); j++) {
|
||||
List<SimpleNode> nodes = nodeNameToNodes.get(nodeNames.get(j));
|
||||
for (SimpleNode node: nodes) {
|
||||
// Visit with underlying Rule, not the RuleReference
|
||||
while (rule instanceof RuleReference) {
|
||||
rule = ((RuleReference)rule).getRule();
|
||||
}
|
||||
visit(rule, node, ctx);
|
||||
}
|
||||
visits += nodes.size();
|
||||
}
|
||||
end = System.nanoTime();
|
||||
Benchmark.mark(Benchmark.TYPE_RULE_CHAIN_RULE, rule.getName(), end - start, visits);
|
||||
start = end;
|
||||
}
|
||||
end = System.nanoTime();
|
||||
Benchmark.mark(Benchmark.TYPE_RULE_CHAIN_RULE, rule.getName(), end - start, visits);
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,14 +116,21 @@ public abstract class AbstractRuleChainVisitor implements RuleChainVisitor {
|
||||
|
||||
// Determine all node types that need visiting
|
||||
Set<String> visitedNodes = new HashSet<String>();
|
||||
for (Iterator<Rule> i = rules.iterator(); i.hasNext();) {
|
||||
Rule rule = i.next();
|
||||
if (rule.usesRuleChain()) {
|
||||
visitedNodes.addAll(rule.getRuleChainVisits());
|
||||
for (Iterator<Map.Entry<RuleSet, List<Rule>>> entryIterator = ruleSetRules.entrySet().iterator(); entryIterator.hasNext();) {
|
||||
Map.Entry<RuleSet, List<Rule>> entry = entryIterator.next();
|
||||
for (Iterator<Rule> ruleIterator = entry.getValue().iterator(); ruleIterator.hasNext();) {
|
||||
Rule rule = ruleIterator.next();
|
||||
if (rule.usesRuleChain()) {
|
||||
visitedNodes.addAll(rule.getRuleChainVisits());
|
||||
}
|
||||
else {
|
||||
// Drop rules which do not participate in the rule chain.
|
||||
ruleIterator.remove();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Drop rules which do not participate in the rule chain.
|
||||
i.remove();
|
||||
// Drop RuleSets in which all Rules have been dropped.
|
||||
if (entry.getValue().isEmpty()) {
|
||||
entryIterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,22 +28,24 @@ public class RuleChain {
|
||||
public void add(RuleSet ruleSet) {
|
||||
Language language = ruleSet.getLanguage();
|
||||
for (Rule r: ruleSet.getRules()) {
|
||||
add(language, r);
|
||||
add(ruleSet, r, language);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given Rule if it wants to participate in the RuleChain.
|
||||
*
|
||||
* @param language
|
||||
* The Language used by the Rule.
|
||||
* @param ruleSet
|
||||
* The RuleSet to which the rule belongs.
|
||||
* @param rule
|
||||
* The Rule to add.
|
||||
* @param language
|
||||
* The Language used by the Rule.
|
||||
*/
|
||||
public void add(Language language, Rule rule) {
|
||||
private void add(RuleSet ruleSet, Rule rule, Language language) {
|
||||
RuleChainVisitor visitor = getRuleChainVisitor(language);
|
||||
if (visitor != null) {
|
||||
visitor.add(rule);
|
||||
visitor.add(ruleSet, rule);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,10 +12,12 @@ public interface RuleChainVisitor {
|
||||
/**
|
||||
* Add the given rule to the visitor.
|
||||
*
|
||||
* @param ruleSet
|
||||
* The RuleSet to which the rule belongs.
|
||||
* @param rule
|
||||
* The rule to add.
|
||||
*/
|
||||
void add(Rule rule);
|
||||
void add(RuleSet ruleSet, Rule rule);
|
||||
|
||||
/**
|
||||
* Visit all the given ASTCompilationUnits provided using the given
|
||||
|
Reference in New Issue
Block a user