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 |
16 /// Returns desired severity for the given [error] (or `null` if it's to be | 18 /// Returns desired severity for the given [error] (or `null` if it's to be |
17 /// suppressed). | 19 /// suppressed). |
18 typedef ProcessedSeverity _SeverityProcessor(AnalysisError error); | 20 typedef ProcessedSeverity _SeverityProcessor(AnalysisError error); |
19 | 21 |
| 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 |
20 /// Helper for formatting [AnalysisError]s. | 97 /// Helper for formatting [AnalysisError]s. |
21 /// The two format options are a user consumable format and a machine consumable | 98 /// The two format options are a user consumable format and a machine consumable |
22 /// format. | 99 /// format. |
23 class ErrorFormatter { | 100 class ErrorFormatter { |
24 final StringSink out; | 101 final StringSink out; |
25 final CommandLineOptions options; | 102 final CommandLineOptions options; |
| 103 final AnalysisStats stats; |
26 final _SeverityProcessor processSeverity; | 104 final _SeverityProcessor processSeverity; |
27 | 105 |
28 ErrorFormatter(this.out, this.options, [this.processSeverity = _identity]); | 106 ErrorFormatter(this.out, this.options, this.stats, |
| 107 [this.processSeverity = _identity]); |
29 | 108 |
30 /// Compute the severity for this [error] or `null` if this error should be | 109 /// Compute the severity for this [error] or `null` if this error should be |
31 /// filtered. | 110 /// filtered. |
32 ErrorSeverity computeSeverity(AnalysisError error) => | 111 ErrorSeverity computeSeverity(AnalysisError error) => |
33 processSeverity(error)?.severity; | 112 processSeverity(error)?.severity; |
34 | 113 |
35 void formatError( | 114 void formatError( |
36 Map<AnalysisError, LineInfo> errorToLine, AnalysisError error) { | 115 Map<AnalysisError, LineInfo> errorToLine, AnalysisError error) { |
37 Source source = error.source; | 116 Source source = error.source; |
38 LineInfo_Location location = errorToLine[error].getLocation(error.offset); | 117 LineInfo_Location location = errorToLine[error].getLocation(error.offset); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 // Path. | 184 // Path. |
106 compare = Comparable.compare(error1.source.fullName.toLowerCase(), | 185 compare = Comparable.compare(error1.source.fullName.toLowerCase(), |
107 error2.source.fullName.toLowerCase()); | 186 error2.source.fullName.toLowerCase()); |
108 if (compare != 0) { | 187 if (compare != 0) { |
109 return compare; | 188 return compare; |
110 } | 189 } |
111 // Offset. | 190 // Offset. |
112 return error1.offset - error2.offset; | 191 return error1.offset - error2.offset; |
113 }); | 192 }); |
114 // Format errors. | 193 // Format errors. |
115 int errorCount = 0; | |
116 int warnCount = 0; | |
117 int hintCount = 0; | |
118 int lintCount = 0; | |
119 for (AnalysisError error in errors) { | 194 for (AnalysisError error in errors) { |
120 ProcessedSeverity processedSeverity = processSeverity(error); | 195 ProcessedSeverity processedSeverity = processSeverity(error); |
121 ErrorSeverity severity = processedSeverity.severity; | 196 ErrorSeverity severity = processedSeverity.severity; |
122 if (severity == ErrorSeverity.ERROR) { | 197 if (severity == ErrorSeverity.ERROR) { |
123 errorCount++; | 198 stats.errorCount++; |
124 } else if (severity == ErrorSeverity.WARNING) { | 199 } else if (severity == ErrorSeverity.WARNING) { |
125 /// Only treat a warning as an error if it's not been set by a | 200 /// Only treat a warning as an error if it's not been set by a |
126 /// proccesser. | 201 /// proccesser. |
127 if (!processedSeverity.overridden && options.warningsAreFatal) { | 202 if (!processedSeverity.overridden && options.warningsAreFatal) { |
128 errorCount++; | 203 stats.errorCount++; |
129 } else { | 204 } else { |
130 warnCount++; | 205 stats.warnCount++; |
131 } | 206 } |
132 } else if (error.errorCode.type == ErrorType.HINT) { | 207 } else if (error.errorCode.type == ErrorType.HINT) { |
133 hintCount++; | 208 stats.hintCount++; |
134 } else if (error.errorCode.type == ErrorType.LINT) { | 209 } else if (error.errorCode.type == ErrorType.LINT) { |
135 lintCount++; | 210 stats.lintCount++; |
136 } | 211 } |
137 formatError(errorToLine, error); | 212 formatError(errorToLine, error); |
138 } | 213 } |
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 } | |
193 } | 214 } |
194 | 215 |
195 static String escapePipe(String input) { | 216 static String escapePipe(String input) { |
196 var result = new StringBuffer(); | 217 var result = new StringBuffer(); |
197 for (var c in input.codeUnits) { | 218 for (var c in input.codeUnits) { |
198 if (c == '\\' || c == '|') { | 219 if (c == '\\' || c == '|') { |
199 result.write('\\'); | 220 result.write('\\'); |
200 } | 221 } |
201 result.writeCharCode(c); | 222 result.writeCharCode(c); |
202 } | 223 } |
203 return result.toString(); | 224 return result.toString(); |
204 } | 225 } |
205 | |
206 static String pluralize(String word, int count) { | |
207 if (count == 1) { | |
208 return word; | |
209 } else { | |
210 return word + "s"; | |
211 } | |
212 } | |
213 } | 226 } |
214 | 227 |
215 /// A severity with awareness of whether it was overriden by a processor. | 228 /// A severity with awareness of whether it was overridden by a processor. |
216 class ProcessedSeverity { | 229 class ProcessedSeverity { |
217 ErrorSeverity severity; | 230 ErrorSeverity severity; |
218 bool overridden; | 231 bool overridden; |
219 ProcessedSeverity(this.severity, [this.overridden = false]); | 232 ProcessedSeverity(this.severity, [this.overridden = false]); |
220 } | 233 } |
OLD | NEW |