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