1 package net.sourceforge.pmd.lang.rule;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.HashSet;
6 import java.util.Iterator;
7 import java.util.LinkedHashMap;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11
12 import net.sourceforge.pmd.Rule;
13 import net.sourceforge.pmd.RuleContext;
14 import net.sourceforge.pmd.RuleSet;
15 import net.sourceforge.pmd.benchmark.Benchmark;
16 import net.sourceforge.pmd.benchmark.Benchmarker;
17 import net.sourceforge.pmd.lang.ast.Node;
18
19
20
21
22
23
24 public abstract class AbstractRuleChainVisitor implements RuleChainVisitor {
25
26
27
28 protected Map<RuleSet, List<Rule>> ruleSetRules = new LinkedHashMap<RuleSet, List<Rule>>();
29
30
31
32
33 protected Map<String, List<Node>> nodeNameToNodes;
34
35
36
37
38 public void add(RuleSet ruleSet, Rule rule) {
39
40 if (!ruleSetRules.containsKey(ruleSet)) {
41 ruleSetRules.put(ruleSet, new ArrayList<Rule>());
42 }
43 ruleSetRules.get(ruleSet).add(rule);
44 }
45
46
47
48
49 public void visitAll(List<Node> nodes, RuleContext ctx) {
50 initialize();
51 clear();
52
53
54
55 long start = System.nanoTime();
56 indexNodes(nodes, ctx);
57 long end = System.nanoTime();
58 Benchmarker.mark(Benchmark.RuleChainVisit, end - start, 1);
59
60
61 for (Map.Entry<RuleSet, List<Rule>> entry : ruleSetRules.entrySet()) {
62 RuleSet ruleSet = entry.getKey();
63 if (!ruleSet.applies(ctx.getSourceCodeFile())) {
64 continue;
65 }
66
67
68 start = System.nanoTime();
69 for (Rule rule: entry.getValue()) {
70 int visits = 0;
71 if (!RuleSet.applies(rule, ctx.getLanguageVersion())) {
72 continue;
73 }
74 final List<String> nodeNames = rule.getRuleChainVisits();
75 for (int j = 0; j < nodeNames.size(); j++) {
76 List<Node> ns = nodeNameToNodes.get(nodeNames.get(j));
77 for (Node node: ns) {
78
79 while (rule instanceof RuleReference) {
80 rule = ((RuleReference)rule).getRule();
81 }
82 visit(rule, node, ctx);
83 }
84 visits += ns.size();
85 }
86 end = System.nanoTime();
87 Benchmarker.mark(Benchmark.RuleChainRule, rule.getName(), end - start, visits);
88 start = end;
89 }
90 }
91 }
92
93
94
95
96 protected abstract void visit(Rule rule, Node node, RuleContext ctx);
97
98
99
100
101 protected abstract void indexNodes(List<Node> nodes, RuleContext ctx);
102
103
104
105
106 protected void indexNode(Node node) {
107 List<Node> nodes = nodeNameToNodes.get(node.toString());
108 if (nodes != null) {
109 nodes.add(node);
110 }
111 }
112
113
114
115
116
117
118
119
120
121 protected void initialize() {
122 if (nodeNameToNodes != null) {
123 return;
124 }
125
126
127 Set<String> visitedNodes = new HashSet<String>();
128 for (Iterator<Map.Entry<RuleSet, List<Rule>>> entryIterator = ruleSetRules.entrySet().iterator(); entryIterator.hasNext();) {
129 Map.Entry<RuleSet, List<Rule>> entry = entryIterator.next();
130 for (Iterator<Rule> ruleIterator = entry.getValue().iterator(); ruleIterator.hasNext();) {
131 Rule rule = ruleIterator.next();
132 if (rule.usesRuleChain()) {
133 visitedNodes.addAll(rule.getRuleChainVisits());
134 }
135 else {
136
137 ruleIterator.remove();
138 }
139 }
140
141 if (entry.getValue().isEmpty()) {
142 entryIterator.remove();
143 }
144 }
145
146
147
148
149 nodeNameToNodes = new HashMap<String, List<Node>>();
150 for (String s: visitedNodes) {
151 List<Node> nodes = new ArrayList<Node>(100);
152 nodeNameToNodes.put(s, nodes);
153 }
154 }
155
156
157
158
159
160 protected void clear() {
161 for (List<Node> l: nodeNameToNodes.values()) {
162 l.clear();
163 }
164 }
165 }