1
2
3
4 package net.sourceforge.pmd;
5
6 import java.io.File;
7 import java.util.ArrayList;
8 import java.util.Collections;
9 import java.util.HashMap;
10 import java.util.HashSet;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Set;
15
16 import net.sourceforge.pmd.lang.dfa.report.ReportTree;
17 import net.sourceforge.pmd.stat.Metric;
18 import net.sourceforge.pmd.util.DateTimeUtil;
19 import net.sourceforge.pmd.util.EmptyIterator;
20 import net.sourceforge.pmd.util.NumericConstants;
21 import net.sourceforge.pmd.util.StringUtil;
22
23 public class Report {
24
25 public static Report createReport(RuleContext ctx, String fileName) {
26 Report report = new Report();
27
28
29 report.addSynchronizedListeners(ctx.getReport().getSynchronizedListeners());
30
31 ctx.setReport(report);
32 ctx.setSourceCodeFilename(fileName);
33 ctx.setSourceCodeFile(new File(fileName));
34 return report;
35 }
36
37 public static class ReadableDuration {
38 private final long duration;
39
40 public ReadableDuration(long duration) {
41 this.duration = duration;
42 }
43
44 public String getTime() {
45 return DateTimeUtil.asHoursMinutesSeconds(duration);
46 }
47 }
48
49 public static class RuleConfigurationError {
50 private final Rule rule;
51 private final String issue;
52
53 public RuleConfigurationError(Rule theRule, String theIssue) {
54 rule = theRule;
55 issue = theIssue;
56 }
57
58 public Rule rule() { return rule; }
59 public String issue() { return issue; }
60 }
61
62 public static class ProcessingError {
63 private final String msg;
64 private final String file;
65
66 public ProcessingError(String msg, String file) {
67 this.msg = msg;
68 this.file = file;
69 }
70
71 public String getMsg() {
72 return msg;
73 }
74
75 public String getFile() {
76 return file;
77 }
78 }
79
80 public static class SuppressedViolation {
81 private final RuleViolation rv;
82 private final boolean isNOPMD;
83 private final String userMessage;
84
85 public SuppressedViolation(RuleViolation rv, boolean isNOPMD, String userMessage) {
86 this.isNOPMD = isNOPMD;
87 this.rv = rv;
88 this.userMessage = userMessage;
89 }
90
91 public boolean suppressedByNOPMD() {
92 return this.isNOPMD;
93 }
94
95 public boolean suppressedByAnnotation() {
96 return !this.isNOPMD;
97 }
98
99 public RuleViolation getRuleViolation() {
100 return this.rv;
101 }
102
103 public String getUserMessage() {
104 return userMessage;
105 }
106 }
107
108
109
110
111
112
113 private final ReportTree violationTree = new ReportTree();
114
115
116 private final List<RuleViolation> violations = new ArrayList<RuleViolation>();
117 private final Set<Metric> metrics = new HashSet<Metric>();
118 private final List<SynchronizedReportListener> listeners = new ArrayList<SynchronizedReportListener>();
119 private List<ProcessingError> errors;
120 private List<RuleConfigurationError> configErrors;
121 private Map<Integer, String> linesToSuppress = new HashMap<Integer, String>();
122 private long start;
123 private long end;
124
125 private List<SuppressedViolation> suppressedRuleViolations = new ArrayList<SuppressedViolation>();
126
127 public void suppress(Map<Integer, String> lines) {
128 linesToSuppress = lines;
129 }
130
131 private static String keyFor(RuleViolation rv) {
132
133 return StringUtil.isNotEmpty(rv.getPackageName()) ?
134 rv.getPackageName() + '.' + rv.getClassName() :
135 "";
136 }
137
138 public Map<String, Integer> getCountSummary() {
139 Map<String, Integer> summary = new HashMap<String, Integer>();
140 for (Iterator<RuleViolation> iter = violationTree.iterator(); iter.hasNext();) {
141 RuleViolation rv = iter.next();
142 String key = keyFor(rv);
143 Integer o = summary.get(key);
144 summary.put(key, o==null ? NumericConstants.ONE : o+1);
145 }
146 return summary;
147 }
148
149 public ReportTree getViolationTree() {
150 return this.violationTree;
151 }
152
153
154
155
156 public Map<String, Integer> getSummary() {
157 Map<String, Integer> summary = new HashMap<String, Integer>();
158 for (RuleViolation rv: violations) {
159 String name = rv.getRule().getName();
160 if (!summary.containsKey(name)) {
161 summary.put(name, NumericConstants.ZERO);
162 }
163 Integer count = summary.get(name);
164 summary.put(name, count + 1);
165 }
166 return summary;
167 }
168
169 public void addListener(ReportListener listener) {
170 listeners.add(new SynchronizedReportListener(listener));
171 }
172
173 public List<SuppressedViolation> getSuppressedRuleViolations() {
174 return suppressedRuleViolations;
175 }
176
177 public void addRuleViolation(RuleViolation violation) {
178
179
180 int line = violation.getBeginLine();
181 if (linesToSuppress.containsKey(line)) {
182 suppressedRuleViolations.add(new SuppressedViolation(violation, true, linesToSuppress.get(line)));
183 return;
184 }
185
186 if (violation.isSuppressed()) {
187 suppressedRuleViolations.add(new SuppressedViolation(violation, false, null));
188 return;
189 }
190
191
192 int index = Collections.binarySearch(violations, violation, RuleViolationComparator.INSTANCE);
193 violations.add(index < 0 ? -index - 1 : index, violation);
194 violationTree.addRuleViolation(violation);
195 for (ReportListener listener: listeners) {
196 listener.ruleViolationAdded(violation);
197 }
198 }
199
200 public void addMetric(Metric metric) {
201 metrics.add(metric);
202 for (ReportListener listener: listeners) {
203 listener.metricAdded(metric);
204 }
205 }
206
207 public void addConfigError(RuleConfigurationError error) {
208 if (configErrors == null) configErrors = new ArrayList<RuleConfigurationError>();
209 configErrors.add(error);
210 }
211
212 public void addError(ProcessingError error) {
213 if (errors == null) errors = new ArrayList<ProcessingError>();
214 errors.add(error);
215 }
216
217 public void merge(Report r) {
218 Iterator<ProcessingError> i = r.errors();
219 while (i.hasNext()) {
220 addError(i.next());
221 }
222 Iterator<Metric> m = r.metrics();
223 while (m.hasNext()) {
224 addMetric(m.next());
225 }
226 Iterator<RuleViolation> v = r.iterator();
227 while (v.hasNext()) {
228 RuleViolation violation = v.next();
229 int index = Collections.binarySearch(violations, violation, RuleViolationComparator.INSTANCE);
230 violations.add(index < 0 ? -index - 1 : index, violation);
231 violationTree.addRuleViolation(violation);
232 }
233 Iterator<SuppressedViolation> s = r.getSuppressedRuleViolations().iterator();
234 while (s.hasNext()) {
235 suppressedRuleViolations.add(s.next());
236 }
237 }
238
239 public boolean hasMetrics() {
240 return !metrics.isEmpty();
241 }
242
243 public Iterator<Metric> metrics() {
244 return metrics.iterator();
245 }
246
247 public boolean isEmpty() {
248 return !violations.iterator().hasNext() && !hasErrors();
249 }
250
251 public boolean hasErrors() {
252 return errors != null;
253 }
254
255 public boolean hasConfigErrors() {
256 return configErrors != null;
257 }
258
259 public boolean treeIsEmpty() {
260 return !violationTree.iterator().hasNext();
261 }
262
263 public Iterator<RuleViolation> treeIterator() {
264 return violationTree.iterator();
265 }
266
267 public Iterator<RuleViolation> iterator() {
268 return violations.iterator();
269 }
270
271 public Iterator<ProcessingError> errors() {
272 return errors == null ? EmptyIterator.<ProcessingError> instance() : errors.iterator();
273 }
274
275 public Iterator<RuleConfigurationError> configErrors() {
276 return configErrors == null ? EmptyIterator.<RuleConfigurationError> instance() : configErrors.iterator();
277 }
278
279 public int treeSize() {
280 return violationTree.size();
281 }
282
283 public int size() {
284 return violations.size();
285 }
286
287 public void start() {
288 start = System.currentTimeMillis();
289 }
290
291 public void end() {
292 end = System.currentTimeMillis();
293 }
294
295 public long getElapsedTimeInMillis() {
296 return end - start;
297 }
298
299 public List<SynchronizedReportListener> getSynchronizedListeners() {
300 return listeners;
301 }
302
303 public void addSynchronizedListeners(List<SynchronizedReportListener> synchronizedListeners) {
304 listeners.addAll(synchronizedListeners);
305 }
306 }