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.renderers.AbstractAccumulatingRenderer;
18 import net.sourceforge.pmd.stat.Metric;
19 import net.sourceforge.pmd.util.DateTimeUtil;
20 import net.sourceforge.pmd.util.EmptyIterator;
21 import net.sourceforge.pmd.util.NumericConstants;
22 import net.sourceforge.pmd.util.StringUtil;
23
24
25
26
27
28
29 public class Report implements Iterable<RuleViolation> {
30
31
32
33
34
35
36
37
38 public static Report createReport(RuleContext ctx, String fileName) {
39 Report report = new Report();
40
41
42 report.addSynchronizedListeners(ctx.getReport().getSynchronizedListeners());
43
44 ctx.setReport(report);
45 ctx.setSourceCodeFilename(fileName);
46 ctx.setSourceCodeFile(new File(fileName));
47 return report;
48 }
49
50
51
52
53 public static class ReadableDuration {
54 private final long duration;
55
56
57
58
59
60
61 public ReadableDuration(long duration) {
62 this.duration = duration;
63 }
64
65
66
67
68
69
70
71 public String getTime() {
72 return DateTimeUtil.asHoursMinutesSeconds(duration);
73 }
74 }
75
76
77
78
79 public static class RuleConfigurationError {
80 private final Rule rule;
81 private final String issue;
82
83
84
85
86
87
88
89 public RuleConfigurationError(Rule theRule, String theIssue) {
90 rule = theRule;
91 issue = theIssue;
92 }
93
94
95
96
97
98
99 public Rule rule() {
100 return rule;
101 }
102
103
104
105
106
107
108 public String issue() {
109 return issue;
110 }
111 }
112
113
114
115
116 public static class ProcessingError {
117 private final String msg;
118 private final String file;
119
120
121
122
123
124
125
126 public ProcessingError(String msg, String file) {
127 this.msg = msg;
128 this.file = file;
129 }
130
131 public String getMsg() {
132 return msg;
133 }
134
135 public String getFile() {
136 return file;
137 }
138 }
139
140
141
142
143 public static class SuppressedViolation {
144 private final RuleViolation rv;
145 private final boolean isNOPMD;
146 private final String userMessage;
147
148
149
150
151
152
153
154
155
156
157
158 public SuppressedViolation(RuleViolation rv, boolean isNOPMD, String userMessage) {
159 this.isNOPMD = isNOPMD;
160 this.rv = rv;
161 this.userMessage = userMessage;
162 }
163
164
165
166
167
168
169
170
171 public boolean suppressedByNOPMD() {
172 return this.isNOPMD;
173 }
174
175
176
177
178
179
180
181
182 public boolean suppressedByAnnotation() {
183 return !this.isNOPMD;
184 }
185
186 public RuleViolation getRuleViolation() {
187 return this.rv;
188 }
189
190 public String getUserMessage() {
191 return userMessage;
192 }
193 }
194
195
196
197
198
199
200 private final ReportTree violationTree = new ReportTree();
201
202
203
204 private final List<RuleViolation> violations = new ArrayList<RuleViolation>();
205 private final Set<Metric> metrics = new HashSet<Metric>();
206 private final List<SynchronizedReportListener> listeners = new ArrayList<SynchronizedReportListener>();
207 private List<ProcessingError> errors;
208 private List<RuleConfigurationError> configErrors;
209 private Map<Integer, String> linesToSuppress = new HashMap<Integer, String>();
210 private long start;
211 private long end;
212
213 private List<SuppressedViolation> suppressedRuleViolations = new ArrayList<SuppressedViolation>();
214
215
216
217
218
219
220 public void suppress(Map<Integer, String> lines) {
221 linesToSuppress = lines;
222 }
223
224 private static String keyFor(RuleViolation rv) {
225
226 return StringUtil.isNotEmpty(rv.getPackageName()) ? rv.getPackageName() + '.' + rv.getClassName() : "";
227 }
228
229
230
231
232
233
234 public Map<String, Integer> getCountSummary() {
235 Map<String, Integer> summary = new HashMap<String, Integer>();
236 for (RuleViolation rv : violationTree) {
237 String key = keyFor(rv);
238 Integer o = summary.get(key);
239 summary.put(key, o == null ? NumericConstants.ONE : o + 1);
240 }
241 return summary;
242 }
243
244 public ReportTree getViolationTree() {
245 return this.violationTree;
246 }
247
248
249
250
251
252
253
254 public Map<String, Integer> getSummary() {
255 Map<String, Integer> summary = new HashMap<String, Integer>();
256 for (RuleViolation rv : violations) {
257 String name = rv.getRule().getName();
258 if (!summary.containsKey(name)) {
259 summary.put(name, NumericConstants.ZERO);
260 }
261 Integer count = summary.get(name);
262 summary.put(name, count + 1);
263 }
264 return summary;
265 }
266
267
268
269
270
271
272 public void addListener(ReportListener listener) {
273 listeners.add(new SynchronizedReportListener(listener));
274 }
275
276 public List<SuppressedViolation> getSuppressedRuleViolations() {
277 return suppressedRuleViolations;
278 }
279
280
281
282
283
284
285 public void addRuleViolation(RuleViolation violation) {
286
287
288 int line = violation.getBeginLine();
289 if (linesToSuppress.containsKey(line)) {
290 suppressedRuleViolations.add(new SuppressedViolation(violation, true, linesToSuppress.get(line)));
291 return;
292 }
293
294 if (violation.isSuppressed()) {
295 suppressedRuleViolations.add(new SuppressedViolation(violation, false, null));
296 return;
297 }
298
299 int index = Collections.binarySearch(violations, violation, RuleViolationComparator.INSTANCE);
300 violations.add(index < 0 ? -index - 1 : index, violation);
301 violationTree.addRuleViolation(violation);
302 for (ReportListener listener : listeners) {
303 listener.ruleViolationAdded(violation);
304 }
305 }
306
307
308
309
310
311
312 public void addMetric(Metric metric) {
313 metrics.add(metric);
314 for (ReportListener listener : listeners) {
315 listener.metricAdded(metric);
316 }
317 }
318
319
320
321
322
323
324 public void addConfigError(RuleConfigurationError error) {
325 if (configErrors == null)
326 configErrors = new ArrayList<RuleConfigurationError>();
327 configErrors.add(error);
328 }
329
330
331
332
333
334
335 public void addError(ProcessingError error) {
336 if (errors == null)
337 errors = new ArrayList<ProcessingError>();
338 errors.add(error);
339 }
340
341
342
343
344
345
346
347
348
349 public void merge(Report r) {
350 Iterator<ProcessingError> i = r.errors();
351 while (i.hasNext()) {
352 addError(i.next());
353 }
354 Iterator<Metric> m = r.metrics();
355 while (m.hasNext()) {
356 addMetric(m.next());
357 }
358 Iterator<RuleViolation> v = r.iterator();
359 while (v.hasNext()) {
360 RuleViolation violation = v.next();
361 int index = Collections.binarySearch(violations, violation, RuleViolationComparator.INSTANCE);
362 violations.add(index < 0 ? -index - 1 : index, violation);
363 violationTree.addRuleViolation(violation);
364 }
365 Iterator<SuppressedViolation> s = r.getSuppressedRuleViolations().iterator();
366 while (s.hasNext()) {
367 suppressedRuleViolations.add(s.next());
368 }
369 }
370
371
372
373
374
375
376
377 public boolean hasMetrics() {
378 return !metrics.isEmpty();
379 }
380
381
382
383
384
385
386 public Iterator<Metric> metrics() {
387 return metrics.iterator();
388 }
389
390 public boolean isEmpty() {
391 return !violations.iterator().hasNext() && !hasErrors();
392 }
393
394
395
396
397
398
399
400 public boolean hasErrors() {
401 return errors != null && !errors.isEmpty();
402 }
403
404
405
406
407
408
409
410 public boolean hasConfigErrors() {
411 return configErrors != null && !configErrors.isEmpty();
412 }
413
414
415
416
417
418
419
420 public boolean treeIsEmpty() {
421 return !violationTree.iterator().hasNext();
422 }
423
424
425
426
427
428
429 public Iterator<RuleViolation> treeIterator() {
430 return violationTree.iterator();
431 }
432
433 @Override
434 public Iterator<RuleViolation> iterator() {
435 return violations.iterator();
436 }
437
438
439
440
441
442
443 public Iterator<ProcessingError> errors() {
444 return errors == null ? EmptyIterator.<ProcessingError> instance() : errors.iterator();
445 }
446
447
448
449
450
451
452 public Iterator<RuleConfigurationError> configErrors() {
453 return configErrors == null ? EmptyIterator.<RuleConfigurationError> instance() : configErrors.iterator();
454 }
455
456
457
458
459
460
461 public int treeSize() {
462 return violationTree.size();
463 }
464
465
466
467
468
469
470 public int size() {
471 return violations.size();
472 }
473
474
475
476
477
478
479
480 public void start() {
481 start = System.currentTimeMillis();
482 }
483
484
485
486
487
488
489 public void end() {
490 end = System.currentTimeMillis();
491 }
492
493 public long getElapsedTimeInMillis() {
494 return end - start;
495 }
496
497 public List<SynchronizedReportListener> getSynchronizedListeners() {
498 return listeners;
499 }
500
501
502
503
504
505
506 public void addSynchronizedListeners(List<SynchronizedReportListener> synchronizedListeners) {
507 listeners.addAll(synchronizedListeners);
508 }
509 }