OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library analyzer_cli.src.error_formatter; | 5 library analyzer_cli.src.error_formatter; |
6 | 6 |
7 import 'package:analyzer/src/generated/engine.dart'; | 7 import 'package:analyzer/src/generated/engine.dart'; |
8 import 'package:analyzer/src/generated/error.dart'; | 8 import 'package:analyzer/src/generated/error.dart'; |
9 import 'package:analyzer/src/generated/source.dart'; | 9 import 'package:analyzer/src/generated/source.dart'; |
10 import 'package:analyzer_cli/src/options.dart'; | 10 import 'package:analyzer_cli/src/options.dart'; |
11 | 11 |
12 /// Returns the given error's severity. | 12 /// Returns the given error's severity. |
13 ProcessedSeverity _identity(AnalysisError error) => | 13 ProcessedSeverity _identity(AnalysisError error) => |
14 new ProcessedSeverity(error.errorCode.errorSeverity); | 14 new ProcessedSeverity(error.errorCode.errorSeverity); |
15 | 15 |
16 String _pluralize(String word, int count) => count == 1 ? word : word + "s"; | |
17 | |
18 /// Returns desired severity for the given [error] (or `null` if it's to be | 16 /// Returns desired severity for the given [error] (or `null` if it's to be |
19 /// suppressed). | 17 /// suppressed). |
20 typedef ProcessedSeverity _SeverityProcessor(AnalysisError error); | 18 typedef ProcessedSeverity _SeverityProcessor(AnalysisError error); |
21 | 19 |
22 /// Analysis statistics counter. | |
23 class AnalysisStats { | |
24 int errorCount; | |
25 int hintCount; | |
26 int lintCount; | |
27 int warnCount; | |
28 | |
29 AnalysisStats() { | |
30 init(); | |
31 } | |
32 | |
33 /// (Re)set initial values. | |
34 void init() { | |
35 errorCount = 0; | |
36 hintCount = 0; | |
37 lintCount = 0; | |
38 warnCount = 0; | |
39 } | |
40 | |
41 /// Print statistics to [out]. | |
42 void print(StringSink out) { | |
43 var hasErrors = errorCount != 0; | |
44 var hasWarns = warnCount != 0; | |
45 var hasHints = hintCount != 0; | |
46 var hasLints = lintCount != 0; | |
47 bool hasContent = false; | |
48 if (hasErrors) { | |
49 out.write(errorCount); | |
50 out.write(' '); | |
51 out.write(_pluralize("error", errorCount)); | |
52 hasContent = true; | |
53 } | |
54 if (hasWarns) { | |
55 if (hasContent) { | |
56 if (!hasHints && !hasLints) { | |
57 out.write(' and '); | |
58 } else { | |
59 out.write(", "); | |
60 } | |
61 } | |
62 out.write(warnCount); | |
63 out.write(' '); | |
64 out.write(_pluralize("warning", warnCount)); | |
65 hasContent = true; | |
66 } | |
67 if (hasHints) { | |
68 if (hasContent) { | |
69 if (!hasLints) { | |
70 out.write(' and '); | |
71 } else { | |
72 out.write(", "); | |
73 } | |
74 } | |
75 out.write(hintCount); | |
76 out.write(' '); | |
77 out.write(_pluralize("hint", hintCount)); | |
78 hasContent = true; | |
79 } | |
80 if (hasLints) { | |
81 if (hasContent) { | |
82 out.write(" and "); | |
83 } | |
84 out.write(lintCount); | |
85 out.write(' '); | |
86 out.write(_pluralize("lint", lintCount)); | |
87 hasContent = true; | |
88 } | |
89 if (hasContent) { | |
90 out.writeln(" found."); | |
91 } else { | |
92 out.writeln("No issues found"); | |
93 } | |
94 } | |
95 } | |
96 | |
97 /// Helper for formatting [AnalysisError]s. | 20 /// Helper for formatting [AnalysisError]s. |
98 /// The two format options are a user consumable format and a machine consumable | 21 /// The two format options are a user consumable format and a machine consumable |
99 /// format. | 22 /// format. |
100 class ErrorFormatter { | 23 class ErrorFormatter { |
101 final StringSink out; | 24 final StringSink out; |
102 final CommandLineOptions options; | 25 final CommandLineOptions options; |
103 final AnalysisStats stats; | |
104 final _SeverityProcessor processSeverity; | 26 final _SeverityProcessor processSeverity; |
105 | 27 |
106 ErrorFormatter(this.out, this.options, this.stats, | 28 ErrorFormatter(this.out, this.options, [this.processSeverity = _identity]); |
107 [this.processSeverity = _identity]); | |
108 | 29 |
109 /// Compute the severity for this [error] or `null` if this error should be | 30 /// Compute the severity for this [error] or `null` if this error should be |
110 /// filtered. | 31 /// filtered. |
111 ErrorSeverity computeSeverity(AnalysisError error) => | 32 ErrorSeverity computeSeverity(AnalysisError error) => |
112 processSeverity(error)?.severity; | 33 processSeverity(error)?.severity; |
113 | 34 |
114 void formatError( | 35 void formatError( |
115 Map<AnalysisError, LineInfo> errorToLine, AnalysisError error) { | 36 Map<AnalysisError, LineInfo> errorToLine, AnalysisError error) { |
116 Source source = error.source; | 37 Source source = error.source; |
117 LineInfo_Location location = errorToLine[error].getLocation(error.offset); | 38 LineInfo_Location location = errorToLine[error].getLocation(error.offset); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
184 // Path. | 105 // Path. |
185 compare = Comparable.compare(error1.source.fullName.toLowerCase(), | 106 compare = Comparable.compare(error1.source.fullName.toLowerCase(), |
186 error2.source.fullName.toLowerCase()); | 107 error2.source.fullName.toLowerCase()); |
187 if (compare != 0) { | 108 if (compare != 0) { |
188 return compare; | 109 return compare; |
189 } | 110 } |
190 // Offset. | 111 // Offset. |
191 return error1.offset - error2.offset; | 112 return error1.offset - error2.offset; |
192 }); | 113 }); |
193 // Format errors. | 114 // Format errors. |
| 115 int errorCount = 0; |
| 116 int warnCount = 0; |
| 117 int hintCount = 0; |
| 118 int lintCount = 0; |
194 for (AnalysisError error in errors) { | 119 for (AnalysisError error in errors) { |
195 ProcessedSeverity processedSeverity = processSeverity(error); | 120 ProcessedSeverity processedSeverity = processSeverity(error); |
196 ErrorSeverity severity = processedSeverity.severity; | 121 ErrorSeverity severity = processedSeverity.severity; |
197 if (severity == ErrorSeverity.ERROR) { | 122 if (severity == ErrorSeverity.ERROR) { |
198 stats.errorCount++; | 123 errorCount++; |
199 } else if (severity == ErrorSeverity.WARNING) { | 124 } else if (severity == ErrorSeverity.WARNING) { |
200 /// Only treat a warning as an error if it's not been set by a | 125 /// Only treat a warning as an error if it's not been set by a |
201 /// proccesser. | 126 /// proccesser. |
202 if (!processedSeverity.overridden && options.warningsAreFatal) { | 127 if (!processedSeverity.overridden && options.warningsAreFatal) { |
203 stats.errorCount++; | 128 errorCount++; |
204 } else { | 129 } else { |
205 stats.warnCount++; | 130 warnCount++; |
206 } | 131 } |
207 } else if (error.errorCode.type == ErrorType.HINT) { | 132 } else if (error.errorCode.type == ErrorType.HINT) { |
208 stats.hintCount++; | 133 hintCount++; |
209 } else if (error.errorCode.type == ErrorType.LINT) { | 134 } else if (error.errorCode.type == ErrorType.LINT) { |
210 stats.lintCount++; | 135 lintCount++; |
211 } | 136 } |
212 formatError(errorToLine, error); | 137 formatError(errorToLine, error); |
213 } | 138 } |
| 139 // Print statistics. |
| 140 if (!options.machineFormat) { |
| 141 var hasErrors = errorCount != 0; |
| 142 var hasWarns = warnCount != 0; |
| 143 var hasHints = hintCount != 0; |
| 144 var hasLints = lintCount != 0; |
| 145 bool hasContent = false; |
| 146 if (hasErrors) { |
| 147 out.write(errorCount); |
| 148 out.write(' '); |
| 149 out.write(pluralize("error", errorCount)); |
| 150 hasContent = true; |
| 151 } |
| 152 if (hasWarns) { |
| 153 if (hasContent) { |
| 154 if (!hasHints && !hasLints) { |
| 155 out.write(' and '); |
| 156 } else { |
| 157 out.write(", "); |
| 158 } |
| 159 } |
| 160 out.write(warnCount); |
| 161 out.write(' '); |
| 162 out.write(pluralize("warning", warnCount)); |
| 163 hasContent = true; |
| 164 } |
| 165 if (hasHints) { |
| 166 if (hasContent) { |
| 167 if (!hasLints) { |
| 168 out.write(' and '); |
| 169 } else { |
| 170 out.write(", "); |
| 171 } |
| 172 } |
| 173 out.write(hintCount); |
| 174 out.write(' '); |
| 175 out.write(pluralize("hint", hintCount)); |
| 176 hasContent = true; |
| 177 } |
| 178 if (hasLints) { |
| 179 if (hasContent) { |
| 180 out.write(" and "); |
| 181 } |
| 182 out.write(lintCount); |
| 183 out.write(' '); |
| 184 out.write(pluralize("lint", lintCount)); |
| 185 hasContent = true; |
| 186 } |
| 187 if (hasContent) { |
| 188 out.writeln(" found."); |
| 189 } else { |
| 190 out.writeln("No issues found"); |
| 191 } |
| 192 } |
214 } | 193 } |
215 | 194 |
216 static String escapePipe(String input) { | 195 static String escapePipe(String input) { |
217 var result = new StringBuffer(); | 196 var result = new StringBuffer(); |
218 for (var c in input.codeUnits) { | 197 for (var c in input.codeUnits) { |
219 if (c == '\\' || c == '|') { | 198 if (c == '\\' || c == '|') { |
220 result.write('\\'); | 199 result.write('\\'); |
221 } | 200 } |
222 result.writeCharCode(c); | 201 result.writeCharCode(c); |
223 } | 202 } |
224 return result.toString(); | 203 return result.toString(); |
225 } | 204 } |
| 205 |
| 206 static String pluralize(String word, int count) { |
| 207 if (count == 1) { |
| 208 return word; |
| 209 } else { |
| 210 return word + "s"; |
| 211 } |
| 212 } |
226 } | 213 } |
227 | 214 |
228 /// A severity with awareness of whether it was overridden by a processor. | 215 /// A severity with awareness of whether it was overriden by a processor. |
229 class ProcessedSeverity { | 216 class ProcessedSeverity { |
230 ErrorSeverity severity; | 217 ErrorSeverity severity; |
231 bool overridden; | 218 bool overridden; |
232 ProcessedSeverity(this.severity, [this.overridden = false]); | 219 ProcessedSeverity(this.severity, [this.overridden = false]); |
233 } | 220 } |
OLD | NEW |