Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(258)

Side by Side Diff: pkg/analyzer_cli/lib/src/error_formatter.dart

Issue 2933753002: Run the sorter to reduce code churn (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pkg/analyzer_cli/lib/src/ansi.dart ('k') | pkg/analyzer_cli/lib/src/error_severity.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/error/error.dart'; 7 import 'package:analyzer/error/error.dart';
8 import 'package:analyzer/src/generated/engine.dart'; 8 import 'package:analyzer/src/generated/engine.dart';
9 import 'package:analyzer/src/generated/source.dart'; 9 import 'package:analyzer/src/generated/source.dart';
10 import 'package:analyzer_cli/src/ansi.dart'; 10 import 'package:analyzer_cli/src/ansi.dart';
11 import 'package:analyzer_cli/src/options.dart'; 11 import 'package:analyzer_cli/src/options.dart';
12 import 'package:path/path.dart' as path; 12 import 'package:path/path.dart' as path;
13 13
14 final Map<String, int> _severityCompare = {
15 'error': 5,
16 'warning': 4,
17 'info': 3,
18 'lint': 2,
19 'hint': 1,
20 };
21
22 String _pluralize(String word, int count) => count == 1 ? word : word + "s";
23
24 /// Given an absolute path, return a relative path if the file is contained in
25 /// the current directory; return the original path otherwise.
26 String _relative(String file) {
27 return file.startsWith(path.current) ? path.relative(file) : file;
28 }
29
14 /// Returns the given error's severity. 30 /// Returns the given error's severity.
15 ErrorSeverity _severityIdentity(AnalysisError error) => 31 ErrorSeverity _severityIdentity(AnalysisError error) =>
16 error.errorCode.errorSeverity; 32 error.errorCode.errorSeverity;
17 33
18 String _pluralize(String word, int count) => count == 1 ? word : word + "s";
19
20 /// Returns desired severity for the given [error] (or `null` if it's to be 34 /// Returns desired severity for the given [error] (or `null` if it's to be
21 /// suppressed). 35 /// suppressed).
22 typedef ErrorSeverity SeverityProcessor(AnalysisError error); 36 typedef ErrorSeverity SeverityProcessor(AnalysisError error);
23 37
24 /// Analysis statistics counter. 38 /// Analysis statistics counter.
25 class AnalysisStats { 39 class AnalysisStats {
26 /// The total number of diagnostics sent to [formatErrors]. 40 /// The total number of diagnostics sent to [formatErrors].
27 int unfilteredCount = 0; 41 int unfilteredCount = 0;
28 42
29 int errorCount = 0; 43 int errorCount = 0;
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 hasContent = true; 95 hasContent = true;
82 } 96 }
83 if (hasContent) { 97 if (hasContent) {
84 out.writeln(" found."); 98 out.writeln(" found.");
85 } else { 99 } else {
86 out.writeln("No issues found!"); 100 out.writeln("No issues found!");
87 } 101 }
88 } 102 }
89 } 103 }
90 104
105 /// An [AnalysisError] with line and column information.
106 class CLIError implements Comparable<CLIError> {
107 final String severity;
108 final String sourcePath;
109 final int offset;
110 final int line;
111 final int column;
112 final String message;
113 final String errorCode;
114 final String correction;
115
116 CLIError({
117 this.severity,
118 this.sourcePath,
119 this.offset,
120 this.line,
121 this.column,
122 this.message,
123 this.errorCode,
124 this.correction,
125 });
126
127 @override
128 int get hashCode =>
129 severity.hashCode ^ sourcePath.hashCode ^ errorCode.hashCode ^ offset;
130 bool get isError => severity == 'error';
131 bool get isHint => severity == 'hint';
132 bool get isLint => severity == 'lint';
133
134 bool get isWarning => severity == 'warning';
135
136 @override
137 bool operator ==(other) {
138 if (other is! CLIError) return false;
139
140 return severity == other.severity &&
141 sourcePath == other.sourcePath &&
142 errorCode == other.errorCode &&
143 offset == other.offset;
144 }
145
146 @override
147 int compareTo(CLIError other) {
148 // severity
149 int compare =
150 _severityCompare[other.severity] - _severityCompare[this.severity];
151 if (compare != 0) return compare;
152
153 // path
154 compare = Comparable.compare(
155 this.sourcePath.toLowerCase(), other.sourcePath.toLowerCase());
156 if (compare != 0) return compare;
157
158 // offset
159 return this.offset - other.offset;
160 }
161 }
162
91 /// Helper for formatting [AnalysisError]s. 163 /// Helper for formatting [AnalysisError]s.
92 /// 164 ///
93 /// The two format options are a user consumable format and a machine consumable 165 /// The two format options are a user consumable format and a machine consumable
94 /// format. 166 /// format.
95 abstract class ErrorFormatter { 167 abstract class ErrorFormatter {
96 final StringSink out; 168 final StringSink out;
97 final CommandLineOptions options; 169 final CommandLineOptions options;
98 final AnalysisStats stats; 170 final AnalysisStats stats;
99 SeverityProcessor _severityProcessor; 171 SeverityProcessor _severityProcessor;
100 172
101 ErrorFormatter(this.out, this.options, this.stats, 173 ErrorFormatter(this.out, this.options, this.stats,
102 {SeverityProcessor severityProcessor}) { 174 {SeverityProcessor severityProcessor}) {
103 _severityProcessor = 175 _severityProcessor =
104 severityProcessor == null ? _severityIdentity : severityProcessor; 176 severityProcessor == null ? _severityIdentity : severityProcessor;
105 } 177 }
106 178
107 /// Compute the severity for this [error] or `null` if this error should be 179 /// Call to write any batched up errors from [formatErrors].
108 /// filtered. 180 void flush();
109 ErrorSeverity _computeSeverity(AnalysisError error) => 181
110 _severityProcessor(error); 182 void formatError(
183 Map<AnalysisError, LineInfo> errorToLine, AnalysisError error);
111 184
112 void formatErrors(List<AnalysisErrorInfo> errorInfos) { 185 void formatErrors(List<AnalysisErrorInfo> errorInfos) {
113 stats.unfilteredCount += errorInfos.length; 186 stats.unfilteredCount += errorInfos.length;
114 187
115 List<AnalysisError> errors = new List<AnalysisError>(); 188 List<AnalysisError> errors = new List<AnalysisError>();
116 Map<AnalysisError, LineInfo> errorToLine = 189 Map<AnalysisError, LineInfo> errorToLine =
117 new Map<AnalysisError, LineInfo>(); 190 new Map<AnalysisError, LineInfo>();
118 for (AnalysisErrorInfo errorInfo in errorInfos) { 191 for (AnalysisErrorInfo errorInfo in errorInfos) {
119 for (AnalysisError error in errorInfo.errors) { 192 for (AnalysisError error in errorInfo.errors) {
120 if (_computeSeverity(error) != null) { 193 if (_computeSeverity(error) != null) {
121 errors.add(error); 194 errors.add(error);
122 errorToLine[error] = errorInfo.lineInfo; 195 errorToLine[error] = errorInfo.lineInfo;
123 } 196 }
124 } 197 }
125 } 198 }
126 199
127 for (AnalysisError error in errors) { 200 for (AnalysisError error in errors) {
128 formatError(errorToLine, error); 201 formatError(errorToLine, error);
129 } 202 }
130 } 203 }
131 204
132 void formatError( 205 /// Compute the severity for this [error] or `null` if this error should be
133 Map<AnalysisError, LineInfo> errorToLine, AnalysisError error); 206 /// filtered.
134 207 ErrorSeverity _computeSeverity(AnalysisError error) =>
135 /// Call to write any batched up errors from [formatErrors]. 208 _severityProcessor(error);
136 void flush();
137 }
138
139 class MachineErrorFormatter extends ErrorFormatter {
140 static final int _pipeCodeUnit = '|'.codeUnitAt(0);
141 static final int _slashCodeUnit = '\\'.codeUnitAt(0);
142 static final int _newline = '\n'.codeUnitAt(0);
143 static final int _return = '\r'.codeUnitAt(0);
144
145 MachineErrorFormatter(
146 StringSink out, CommandLineOptions options, AnalysisStats stats,
147 {SeverityProcessor severityProcessor})
148 : super(out, options, stats, severityProcessor: severityProcessor);
149
150 void formatError(
151 Map<AnalysisError, LineInfo> errorToLine, AnalysisError error) {
152 Source source = error.source;
153 LineInfo_Location location = errorToLine[error].getLocation(error.offset);
154 int length = error.length;
155
156 ErrorSeverity severity = _severityProcessor(error);
157
158 if (severity == ErrorSeverity.ERROR) {
159 stats.errorCount++;
160 } else if (severity == ErrorSeverity.WARNING) {
161 stats.warnCount++;
162 } else if (error.errorCode.type == ErrorType.HINT) {
163 stats.hintCount++;
164 } else if (error.errorCode.type == ErrorType.LINT) {
165 stats.lintCount++;
166 }
167
168 out.write(severity);
169 out.write('|');
170 out.write(error.errorCode.type);
171 out.write('|');
172 out.write(error.errorCode.name);
173 out.write('|');
174 out.write(_escapeForMachineMode(source.fullName));
175 out.write('|');
176 out.write(location.lineNumber);
177 out.write('|');
178 out.write(location.columnNumber);
179 out.write('|');
180 out.write(length);
181 out.write('|');
182 out.write(_escapeForMachineMode(error.message));
183 out.writeln();
184 }
185
186 static String _escapeForMachineMode(String input) {
187 StringBuffer result = new StringBuffer();
188 for (int c in input.codeUnits) {
189 if (c == _newline) {
190 result.write(r'\n');
191 } else if (c == _return) {
192 result.write(r'\r');
193 } else {
194 if (c == _slashCodeUnit || c == _pipeCodeUnit) {
195 result.write('\\');
196 }
197 result.writeCharCode(c);
198 }
199 }
200 return result.toString();
201 }
202
203 void flush() {}
204 } 209 }
205 210
206 class HumanErrorFormatter extends ErrorFormatter { 211 class HumanErrorFormatter extends ErrorFormatter {
207 AnsiLogger ansi; 212 AnsiLogger ansi;
208 213
209 // This is a Set in order to de-dup CLI errors. 214 // This is a Set in order to de-dup CLI errors.
210 Set<CLIError> batchedErrors = new Set(); 215 Set<CLIError> batchedErrors = new Set();
211 216
212 HumanErrorFormatter( 217 HumanErrorFormatter(
213 StringSink out, CommandLineOptions options, AnalysisStats stats, 218 StringSink out, CommandLineOptions options, AnalysisStats stats,
214 {SeverityProcessor severityProcessor}) 219 {SeverityProcessor severityProcessor})
215 : super(out, options, stats, severityProcessor: severityProcessor) { 220 : super(out, options, stats, severityProcessor: severityProcessor) {
216 ansi = new AnsiLogger(this.options.color); 221 ansi = new AnsiLogger(this.options.color);
217 } 222 }
218 223
224 void flush() {
225 // sort
226 List<CLIError> sortedErrors = batchedErrors.toList()..sort();
227
228 // print
229 for (CLIError error in sortedErrors) {
230 if (error.isError) {
231 stats.errorCount++;
232 } else if (error.isWarning) {
233 stats.warnCount++;
234 } else if (error.isLint) {
235 stats.lintCount++;
236 } else if (error.isHint) {
237 stats.hintCount++;
238 }
239
240 // warning • 'foo' is not a bar at lib/foo.dart:1:2 • foo_warning
241 String issueColor = (error.isError == ErrorSeverity.ERROR ||
242 error.isWarning == ErrorSeverity.WARNING)
243 ? ansi.red
244 : '';
245 out.write(' $issueColor${error.severity}${ansi.none} '
246 '${ansi.bullet} ${ansi.bold}${error.message}${ansi.none} ');
247 out.write('at ${error.sourcePath}');
248 out.write(':${error.line}:${error.column} ');
249 out.write('${ansi.bullet} ${error.errorCode}');
250 out.writeln();
251
252 // If verbose, also print any associated correction.
253 if (options.verbose && error.correction != null) {
254 out.writeln(
255 '${' '.padLeft(error.severity.length + 2)}${error.correction}');
256 }
257 }
258
259 // clear out batched errors
260 batchedErrors.clear();
261 }
262
219 void formatError( 263 void formatError(
220 Map<AnalysisError, LineInfo> errorToLine, AnalysisError error) { 264 Map<AnalysisError, LineInfo> errorToLine, AnalysisError error) {
221 Source source = error.source; 265 Source source = error.source;
222 LineInfo_Location location = errorToLine[error].getLocation(error.offset); 266 LineInfo_Location location = errorToLine[error].getLocation(error.offset);
223 267
224 ErrorSeverity severity = _severityProcessor(error); 268 ErrorSeverity severity = _severityProcessor(error);
225 269
226 // Get display name; translate INFOs into LINTS and HINTS. 270 // Get display name; translate INFOs into LINTS and HINTS.
227 String errorType = severity.displayName; 271 String errorType = severity.displayName;
228 if (severity == ErrorSeverity.INFO) { 272 if (severity == ErrorSeverity.INFO) {
(...skipping 26 matching lines...) Expand all
255 severity: errorType, 299 severity: errorType,
256 sourcePath: sourcePath, 300 sourcePath: sourcePath,
257 offset: error.offset, 301 offset: error.offset,
258 line: location.lineNumber, 302 line: location.lineNumber,
259 column: location.columnNumber, 303 column: location.columnNumber,
260 message: message, 304 message: message,
261 errorCode: error.errorCode.name.toLowerCase(), 305 errorCode: error.errorCode.name.toLowerCase(),
262 correction: error.correction, 306 correction: error.correction,
263 )); 307 ));
264 } 308 }
309 }
265 310
266 void flush() { 311 class MachineErrorFormatter extends ErrorFormatter {
267 // sort 312 static final int _pipeCodeUnit = '|'.codeUnitAt(0);
268 List<CLIError> sortedErrors = batchedErrors.toList()..sort(); 313 static final int _slashCodeUnit = '\\'.codeUnitAt(0);
314 static final int _newline = '\n'.codeUnitAt(0);
315 static final int _return = '\r'.codeUnitAt(0);
269 316
270 // print 317 MachineErrorFormatter(
271 for (CLIError error in sortedErrors) { 318 StringSink out, CommandLineOptions options, AnalysisStats stats,
272 if (error.isError) { 319 {SeverityProcessor severityProcessor})
273 stats.errorCount++; 320 : super(out, options, stats, severityProcessor: severityProcessor);
274 } else if (error.isWarning) {
275 stats.warnCount++;
276 } else if (error.isLint) {
277 stats.lintCount++;
278 } else if (error.isHint) {
279 stats.hintCount++;
280 }
281 321
282 // warning • 'foo' is not a bar at lib/foo.dart:1:2 • foo_warning 322 void flush() {}
283 String issueColor = (error.isError == ErrorSeverity.ERROR ||
284 error.isWarning == ErrorSeverity.WARNING)
285 ? ansi.red
286 : '';
287 out.write(' $issueColor${error.severity}${ansi.none} '
288 '${ansi.bullet} ${ansi.bold}${error.message}${ansi.none} ');
289 out.write('at ${error.sourcePath}');
290 out.write(':${error.line}:${error.column} ');
291 out.write('${ansi.bullet} ${error.errorCode}');
292 out.writeln();
293 323
294 // If verbose, also print any associated correction. 324 void formatError(
295 if (options.verbose && error.correction != null) { 325 Map<AnalysisError, LineInfo> errorToLine, AnalysisError error) {
296 out.writeln( 326 Source source = error.source;
297 '${' '.padLeft(error.severity.length + 2)}${error.correction}'); 327 LineInfo_Location location = errorToLine[error].getLocation(error.offset);
328 int length = error.length;
329
330 ErrorSeverity severity = _severityProcessor(error);
331
332 if (severity == ErrorSeverity.ERROR) {
333 stats.errorCount++;
334 } else if (severity == ErrorSeverity.WARNING) {
335 stats.warnCount++;
336 } else if (error.errorCode.type == ErrorType.HINT) {
337 stats.hintCount++;
338 } else if (error.errorCode.type == ErrorType.LINT) {
339 stats.lintCount++;
340 }
341
342 out.write(severity);
343 out.write('|');
344 out.write(error.errorCode.type);
345 out.write('|');
346 out.write(error.errorCode.name);
347 out.write('|');
348 out.write(_escapeForMachineMode(source.fullName));
349 out.write('|');
350 out.write(location.lineNumber);
351 out.write('|');
352 out.write(location.columnNumber);
353 out.write('|');
354 out.write(length);
355 out.write('|');
356 out.write(_escapeForMachineMode(error.message));
357 out.writeln();
358 }
359
360 static String _escapeForMachineMode(String input) {
361 StringBuffer result = new StringBuffer();
362 for (int c in input.codeUnits) {
363 if (c == _newline) {
364 result.write(r'\n');
365 } else if (c == _return) {
366 result.write(r'\r');
367 } else {
368 if (c == _slashCodeUnit || c == _pipeCodeUnit) {
369 result.write('\\');
370 }
371 result.writeCharCode(c);
298 } 372 }
299 } 373 }
300 374 return result.toString();
301 // clear out batched errors
302 batchedErrors.clear();
303 } 375 }
304 } 376 }
305
306 final Map<String, int> _severityCompare = {
307 'error': 5,
308 'warning': 4,
309 'info': 3,
310 'lint': 2,
311 'hint': 1,
312 };
313
314 /// An [AnalysisError] with line and column information.
315 class CLIError implements Comparable<CLIError> {
316 final String severity;
317 final String sourcePath;
318 final int offset;
319 final int line;
320 final int column;
321 final String message;
322 final String errorCode;
323 final String correction;
324
325 CLIError({
326 this.severity,
327 this.sourcePath,
328 this.offset,
329 this.line,
330 this.column,
331 this.message,
332 this.errorCode,
333 this.correction,
334 });
335
336 bool get isError => severity == 'error';
337 bool get isWarning => severity == 'warning';
338 bool get isLint => severity == 'lint';
339 bool get isHint => severity == 'hint';
340
341 @override
342 int get hashCode =>
343 severity.hashCode ^ sourcePath.hashCode ^ errorCode.hashCode ^ offset;
344
345 @override
346 bool operator ==(other) {
347 if (other is! CLIError) return false;
348
349 return severity == other.severity &&
350 sourcePath == other.sourcePath &&
351 errorCode == other.errorCode &&
352 offset == other.offset;
353 }
354
355 @override
356 int compareTo(CLIError other) {
357 // severity
358 int compare =
359 _severityCompare[other.severity] - _severityCompare[this.severity];
360 if (compare != 0) return compare;
361
362 // path
363 compare = Comparable.compare(
364 this.sourcePath.toLowerCase(), other.sourcePath.toLowerCase());
365 if (compare != 0) return compare;
366
367 // offset
368 return this.offset - other.offset;
369 }
370 }
371
372 /// Given an absolute path, return a relative path if the file is contained in
373 /// the current directory; return the original path otherwise.
374 String _relative(String file) {
375 return file.startsWith(path.current) ? path.relative(file) : file;
376 }
OLDNEW
« no previous file with comments | « pkg/analyzer_cli/lib/src/ansi.dart ('k') | pkg/analyzer_cli/lib/src/error_severity.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698