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 implements Iterable<RuleViolation> {
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() {
59 return rule;
60 }
61
62 public String issue() {
63 return issue;
64 }
65 }
66
67 public static class ProcessingError {
68 private final String msg;
69 private final String file;
70
71 public ProcessingError(String msg, String file) {
72 this.msg = msg;
73 this.file = file;
74 }
75
76 public String getMsg() {
77 return msg;
78 }
79
80 public String getFile() {
81 return file;
82 }
83 }
84
85 public static class SuppressedViolation {
86 private final RuleViolation rv;
87 private final boolean isNOPMD;
88 private final String userMessage;
89
90 public SuppressedViolation(RuleViolation rv, boolean isNOPMD, String userMessage) {
91 this.isNOPMD = isNOPMD;
92 this.rv = rv;
93 this.userMessage = userMessage;
94 }
95
96 public boolean suppressedByNOPMD() {
97 return this.isNOPMD;
98 }
99
100 public boolean suppressedByAnnotation() {
101 return !this.isNOPMD;
102 }
103
104 public RuleViolation getRuleViolation() {
105 return this.rv;
106 }
107
108 public String getUserMessage() {
109 return userMessage;
110 }
111 }
112
113
114
115
116
117
118 private final ReportTree violationTree = new ReportTree();
119
120
121
122 private final List<RuleViolation> violations = new ArrayList<RuleViolation>();
123 private final Set<Metric> metrics = new HashSet<Metric>();
124 private final List<SynchronizedReportListener> listeners = new ArrayList<SynchronizedReportListener>();
125 private List<ProcessingError> errors;
126 private List<RuleConfigurationError> configErrors;
127 private Map<Integer, String> linesToSuppress = new HashMap<Integer, String>();
128 private long start;
129 private long end;
130
131 private List<SuppressedViolation> suppressedRuleViolations = new ArrayList<SuppressedViolation>();
132
133 public void suppress(Map<Integer, String> lines) {
134 linesToSuppress = lines;
135 }
136
137 private static String keyFor(RuleViolation rv) {
138
139 return StringUtil.isNotEmpty(rv.getPackageName()) ? rv.getPackageName() + '.' + rv.getClassName() : "";
140 }
141
142 public Map<String, Integer> getCountSummary() {
143 Map<String, Integer> summary = new HashMap<String, Integer>();
144 for (RuleViolation rv : violationTree) {
145 String key = keyFor(rv);
146 Integer o = summary.get(key);
147 summary.put(key, o == null ? NumericConstants.ONE : o + 1);
148 }
149 return summary;
150 }
151
152 public ReportTree getViolationTree() {
153 return this.violationTree;
154 }
155
156
157
158
159
160 public Map<String, Integer> getSummary() {
161 Map<String, Integer> summary = new HashMap<String, Integer>();
162 for (RuleViolation rv : violations) {
163 String name = rv.getRule().getName();
164 if (!summary.containsKey(name)) {
165 summary.put(name, NumericConstants.ZERO);
166 }
167 Integer count = summary.get(name);
168 summary.put(name, count + 1);
169 }
170 return summary;
171 }
172
173 public void addListener(ReportListener listener) {
174 listeners.add(new SynchronizedReportListener(listener));
175 }
176
177 public List<SuppressedViolation> getSuppressedRuleViolations() {
178 return suppressedRuleViolations;
179 }
180
181 public void addRuleViolation(RuleViolation violation) {
182
183
184 int line = violation.getBeginLine();
185 if (linesToSuppress.containsKey(line)) {
186 suppressedRuleViolations.add(new SuppressedViolation(violation, true, linesToSuppress.get(line)));
187 return;
188 }
189
190 if (violation.isSuppressed()) {
191 suppressedRuleViolations.add(new SuppressedViolation(violation, false, null));
192 return;
193 }
194
195 int index = Collections.binarySearch(violations, violation, RuleViolationComparator.INSTANCE);
196 violations.add(index < 0 ? -index - 1 : index, violation);
197 violationTree.addRuleViolation(violation);
198 for (ReportListener listener : listeners) {
199 listener.ruleViolationAdded(violation);
200 }
201 }
202
203 public void addMetric(Metric metric) {
204 metrics.add(metric);
205 for (ReportListener listener : listeners) {
206 listener.metricAdded(metric);
207 }
208 }
209
210 public void addConfigError(RuleConfigurationError error) {
211 if (configErrors == null)
212 configErrors = new ArrayList<RuleConfigurationError>();
213 configErrors.add(error);
214 }
215
216 public void addError(ProcessingError error) {
217 if (errors == null)
218 errors = new ArrayList<ProcessingError>();
219 errors.add(error);
220 }
221
222 public void merge(Report r) {
223 Iterator<ProcessingError> i = r.errors();
224 while (i.hasNext()) {
225 addError(i.next());
226 }
227 Iterator<Metric> m = r.metrics();
228 while (m.hasNext()) {
229 addMetric(m.next());
230 }
231 Iterator<RuleViolation> v = r.iterator();
232 while (v.hasNext()) {
233 RuleViolation violation = v.next();
234 int index = Collections.binarySearch(violations, violation, RuleViolationComparator.INSTANCE);
235 violations.add(index < 0 ? -index - 1 : index, violation);
236 violationTree.addRuleViolation(violation);
237 }
238 Iterator<SuppressedViolation> s = r.getSuppressedRuleViolations().iterator();
239 while (s.hasNext()) {
240 suppressedRuleViolations.add(s.next());
241 }
242 }
243
244 public boolean hasMetrics() {
245 return !metrics.isEmpty();
246 }
247
248 public Iterator<Metric> metrics() {
249 return metrics.iterator();
250 }
251
252 public boolean isEmpty() {
253 return !violations.iterator().hasNext() && !hasErrors();
254 }
255
256 public boolean hasErrors() {
257 return errors != null;
258 }
259
260 public boolean hasConfigErrors() {
261 return configErrors != null;
262 }
263
264 public boolean treeIsEmpty() {
265 return !violationTree.iterator().hasNext();
266 }
267
268 public Iterator<RuleViolation> treeIterator() {
269 return violationTree.iterator();
270 }
271
272 @Override
273 public Iterator<RuleViolation> iterator() {
274 return violations.iterator();
275 }
276
277 public Iterator<ProcessingError> errors() {
278 return errors == null ? EmptyIterator.<ProcessingError> instance() : errors.iterator();
279 }
280
281 public Iterator<RuleConfigurationError> configErrors() {
282 return configErrors == null ? EmptyIterator.<RuleConfigurationError> instance() : configErrors.iterator();
283 }
284
285 public int treeSize() {
286 return violationTree.size();
287 }
288
289 public int size() {
290 return violations.size();
291 }
292
293 public void start() {
294 start = System.currentTimeMillis();
295 }
296
297 public void end() {
298 end = System.currentTimeMillis();
299 }
300
301 public long getElapsedTimeInMillis() {
302 return end - start;
303 }
304
305 public List<SynchronizedReportListener> getSynchronizedListeners() {
306 return listeners;
307 }
308
309 public void addSynchronizedListeners(List<SynchronizedReportListener> synchronizedListeners) {
310 listeners.addAll(synchronizedListeners);
311 }
312 }