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