| 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 /// Summarizes the information produced by the checker. | 5 /// Summarizes the information produced by the checker. |
| 6 library dev_compiler.src.report; | 6 library dev_compiler.src.report; |
| 7 | 7 |
| 8 import 'dart:math' show max; | 8 import 'dart:math' show max; |
| 9 import 'dart:io'; |
| 9 | 10 |
| 10 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; | 11 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; |
| 11 import 'package:analyzer/src/generated/error.dart'; | 12 import 'package:analyzer/src/generated/error.dart'; |
| 12 import 'package:logging/logging.dart'; | 13 import 'package:logging/logging.dart'; |
| 13 import 'package:path/path.dart' as path; | 14 import 'package:path/path.dart' as path; |
| 14 import 'package:source_span/source_span.dart'; | 15 import 'package:source_span/source_span.dart'; |
| 15 | 16 |
| 16 import 'utils.dart'; | 17 import 'utils.dart'; |
| 17 import 'summary.dart'; | 18 import 'summary.dart'; |
| 18 | 19 |
| 19 final _checkerLogger = new Logger('dev_compiler.checker'); | 20 final _checkerLogger = new Logger('dev_compiler.checker'); |
| 20 | 21 |
| 21 /// Collects errors, and then sorts them and sends them | 22 /// Collects errors, and then sorts them and sends them |
| 22 class ErrorCollector implements AnalysisErrorListener { | 23 class ErrorCollector implements AnalysisErrorListener { |
| 24 final AnalysisContext context; |
| 23 final AnalysisErrorListener listener; | 25 final AnalysisErrorListener listener; |
| 24 final List<AnalysisError> _errors = []; | 26 final List<AnalysisError> _errors = []; |
| 27 final bool saveMessages; |
| 28 final Level logLevel; |
| 25 | 29 |
| 26 ErrorCollector(this.listener); | 30 ErrorCollector(this.context, AnalysisErrorListener listener, this.logLevel, |
| 31 {this.saveMessages: false}) |
| 32 : listener = listener ?? AnalysisErrorListener.NULL_LISTENER; |
| 27 | 33 |
| 28 /// Flushes errors to the log. Until this is called, errors are buffered. | 34 /// Flushes errors to the log. Until this is called, errors are buffered. |
| 29 void flush() { | 35 void flush(String messagePath) { |
| 30 // TODO(jmesserly): this code was taken from analyzer_cli. | 36 // TODO(jmesserly): this code was taken from analyzer_cli. |
| 31 // sort errors | 37 // sort errors |
| 32 _errors.sort((AnalysisError error1, AnalysisError error2) { | 38 _errors.sort((AnalysisError error1, AnalysisError error2) { |
| 33 // severity | 39 // severity |
| 34 var severity1 = _strongModeErrorSeverity(error1); | 40 var severity1 = _strongModeErrorSeverity(error1); |
| 35 var severity2 = _strongModeErrorSeverity(error2); | 41 var severity2 = _strongModeErrorSeverity(error2); |
| 36 int compare = severity2.compareTo(severity1); | 42 int compare = severity2.compareTo(severity1); |
| 37 if (compare != 0) return compare; | 43 if (compare != 0) return compare; |
| 38 | 44 |
| 39 // path | 45 // path |
| 40 compare = Comparable.compare(error1.source.fullName.toLowerCase(), | 46 compare = Comparable.compare(error1.source.fullName.toLowerCase(), |
| 41 error2.source.fullName.toLowerCase()); | 47 error2.source.fullName.toLowerCase()); |
| 42 if (compare != 0) return compare; | 48 if (compare != 0) return compare; |
| 43 | 49 |
| 44 // offset | 50 // offset |
| 45 compare = error1.offset - error2.offset; | 51 compare = error1.offset - error2.offset; |
| 46 if (compare != 0) return compare; | 52 if (compare != 0) return compare; |
| 47 | 53 |
| 48 // compare message, in worst case. | 54 // compare message, in worst case. |
| 49 return error1.message.compareTo(error2.message); | 55 return error1.message.compareTo(error2.message); |
| 50 }); | 56 }); |
| 51 | 57 |
| 52 _errors.forEach(listener.onError); | 58 if (saveMessages && messagePath != null) { |
| 59 var text = new StringBuffer(); |
| 60 for (var e in _errors) { |
| 61 // TODO(jmesserly): don't use log level for this. |
| 62 var level = _severityToLevel[_strongModeErrorSeverity(e)]; |
| 63 if (level >= logLevel) { |
| 64 text |
| 65 ..write(level.name.toLowerCase()) |
| 66 ..write(': ') |
| 67 ..writeln(_messageToString(context, e)); |
| 68 } |
| 69 } |
| 70 var messageFile = new File(messagePath); |
| 71 if (text.isNotEmpty) { |
| 72 messageFile.writeAsStringSync(text.toString()); |
| 73 } else if (messageFile.existsSync()) { |
| 74 messageFile.deleteSync(); |
| 75 } |
| 76 } else { |
| 77 _errors.forEach(listener.onError); |
| 78 } |
| 53 _errors.clear(); | 79 _errors.clear(); |
| 54 } | 80 } |
| 55 | 81 |
| 56 void onError(AnalysisError error) { | 82 void onError(AnalysisError error) { |
| 57 _errors.add(error); | 83 _errors.add(error); |
| 58 } | 84 } |
| 59 } | 85 } |
| 60 | 86 |
| 61 ErrorSeverity _strongModeErrorSeverity(AnalysisError error) { | 87 ErrorSeverity _strongModeErrorSeverity(AnalysisError error) { |
| 62 // Upgrade analyzer warnings to errors. | 88 // Upgrade analyzer warnings to errors. |
| 63 // TODO(jmesserly: reconcile this with analyzer_cli | 89 // TODO(jmesserly: reconcile this with analyzer_cli |
| 64 var severity = error.errorCode.errorSeverity; | 90 var severity = error.errorCode.errorSeverity; |
| 65 if (!error.errorCode.name.startsWith('dev_compiler.') && | 91 if (!error.errorCode.name.startsWith('dev_compiler.') && |
| 66 severity == ErrorSeverity.WARNING) { | 92 severity == ErrorSeverity.WARNING) { |
| 67 return ErrorSeverity.ERROR; | 93 return ErrorSeverity.ERROR; |
| 68 } | 94 } |
| 69 return severity; | 95 return severity; |
| 70 } | 96 } |
| 71 | 97 |
| 72 /// Simple reporter that logs checker messages as they are seen. | 98 /// Simple reporter that logs checker messages as they are seen. |
| 73 class LogReporter implements AnalysisErrorListener { | 99 class LogReporter implements AnalysisErrorListener { |
| 74 final AnalysisContext _context; | 100 final AnalysisContext _context; |
| 75 final bool useColors; | |
| 76 final List<AnalysisError> _errors = []; | |
| 77 | 101 |
| 78 LogReporter(this._context, {this.useColors: false}); | 102 LogReporter(this._context); |
| 79 | 103 |
| 80 void onError(AnalysisError error) { | 104 void onError(AnalysisError error) { |
| 81 var level = _severityToLevel[_strongModeErrorSeverity(error)]; | 105 var level = _severityToLevel[_strongModeErrorSeverity(error)]; |
| 82 | |
| 83 // TODO(jmesserly): figure out what to do with the error's name. | |
| 84 var lineInfo = _context.computeLineInfo(error.source); | |
| 85 var location = lineInfo.getLocation(error.offset); | |
| 86 | |
| 87 // [warning] 'foo' is not a... (/Users/.../tmp/foo.dart, line 1, col 2) | |
| 88 var text = new StringBuffer() | |
| 89 ..write('[${errorCodeName(error.errorCode)}] ') | |
| 90 ..write(error.message) | |
| 91 ..write(' (${path.prettyUri(error.source.uri)}') | |
| 92 ..write(', line ${location.lineNumber}, col ${location.columnNumber})'); | |
| 93 | |
| 94 // TODO(jmesserly): just print these instead of sending through logger? | 106 // TODO(jmesserly): just print these instead of sending through logger? |
| 95 _checkerLogger.log(level, text); | 107 _checkerLogger.log(level, _messageToString(_context, error)); |
| 96 } | 108 } |
| 97 } | 109 } |
| 98 | 110 |
| 111 String _messageToString(AnalysisContext context, AnalysisError error) { |
| 112 // TODO(jmesserly): figure out what to do with the error's name. |
| 113 var lineInfo = context.computeLineInfo(error.source); |
| 114 var location = lineInfo.getLocation(error.offset); |
| 115 |
| 116 // [warning] 'foo' is not a... (/Users/.../tmp/foo.dart, line 1, col 2) |
| 117 var text = new StringBuffer() |
| 118 ..write('[${errorCodeName(error.errorCode)}] ') |
| 119 ..write(error.message) |
| 120 ..write(' (${path.prettyUri(error.source.uri)}') |
| 121 ..write(', line ${location.lineNumber}, col ${location.columnNumber})'); |
| 122 |
| 123 return text.toString(); |
| 124 } |
| 125 |
| 99 // TODO(jmesserly): remove log levels, instead just use severity. | 126 // TODO(jmesserly): remove log levels, instead just use severity. |
| 100 const _severityToLevel = const { | 127 const _severityToLevel = const { |
| 101 ErrorSeverity.ERROR: Level.SEVERE, | 128 ErrorSeverity.ERROR: Level.SEVERE, |
| 102 ErrorSeverity.WARNING: Level.WARNING, | 129 ErrorSeverity.WARNING: Level.WARNING, |
| 103 ErrorSeverity.INFO: Level.INFO | 130 ErrorSeverity.INFO: Level.INFO |
| 104 }; | 131 }; |
| 105 | 132 |
| 106 /// A reporter that gathers all the information in a [GlobalSummary]. | 133 /// A reporter that gathers all the information in a [GlobalSummary]. |
| 107 class SummaryReporter implements AnalysisErrorListener { | 134 class SummaryReporter implements AnalysisErrorListener { |
| 108 GlobalSummary result = new GlobalSummary(); | 135 GlobalSummary result = new GlobalSummary(); |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 | 380 |
| 354 visitMessage(MessageSummary message) { | 381 visitMessage(MessageSummary message) { |
| 355 var kind = message.kind; | 382 var kind = message.kind; |
| 356 errorCount.putIfAbsent(currentPackage, () => <String, int>{}); | 383 errorCount.putIfAbsent(currentPackage, () => <String, int>{}); |
| 357 errorCount[currentPackage].putIfAbsent(kind, () => 0); | 384 errorCount[currentPackage].putIfAbsent(kind, () => 0); |
| 358 errorCount[currentPackage][kind]++; | 385 errorCount[currentPackage][kind]++; |
| 359 totals.putIfAbsent(kind, () => 0); | 386 totals.putIfAbsent(kind, () => 0); |
| 360 totals[kind]++; | 387 totals[kind]++; |
| 361 } | 388 } |
| 362 } | 389 } |
| OLD | NEW |