| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 import 'package:analyzer/analyzer.dart' |
| 6 show AnalysisError, ErrorSeverity, StaticWarningCode; |
| 7 import 'package:analyzer/source/error_processor.dart' show ErrorProcessor; |
| 5 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; | 8 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; |
| 6 import 'package:analyzer/src/generated/error.dart'; | |
| 7 import 'package:logging/logging.dart'; | |
| 8 import 'package:path/path.dart' as path; | 9 import 'package:path/path.dart' as path; |
| 9 import 'package:analyzer/source/error_processor.dart'; | |
| 10 | 10 |
| 11 final _checkerLogger = new Logger('dev_compiler.checker'); | 11 // TODO(jmesserly): this code was taken from analyzer_cli. |
| 12 // It really should be in some common place so we can share it. |
| 13 // TODO(jmesserly): this shouldn't depend on `context` but we need it to compute |
| 14 // `errorSeverity` due to some APIs that need fixing. |
| 15 void sortErrors(AnalysisContext context, List<AnalysisError> errors) { |
| 16 errors.sort((AnalysisError error1, AnalysisError error2) { |
| 17 // severity |
| 18 var severity1 = errorSeverity(context, error1); |
| 19 var severity2 = errorSeverity(context, error2); |
| 20 int compare = severity2.compareTo(severity1); |
| 21 if (compare != 0) return compare; |
| 12 | 22 |
| 13 /// Collects errors, and then sorts them and sends them | 23 // path |
| 14 class ErrorCollector implements AnalysisErrorListener { | 24 compare = Comparable.compare(error1.source.fullName.toLowerCase(), |
| 15 final AnalysisContext _context; | 25 error2.source.fullName.toLowerCase()); |
| 16 final AnalysisErrorListener listener; | 26 if (compare != 0) return compare; |
| 17 final List<AnalysisError> _errors = []; | |
| 18 | 27 |
| 19 ErrorCollector(this._context, this.listener); | 28 // offset |
| 29 compare = error1.offset - error2.offset; |
| 30 if (compare != 0) return compare; |
| 20 | 31 |
| 21 /// Flushes errors to the log. Until this is called, errors are buffered. | 32 // compare message, in worst case. |
| 22 void flush() { | 33 return error1.message.compareTo(error2.message); |
| 23 // TODO(jmesserly): this code was taken from analyzer_cli. | 34 }); |
| 24 // sort errors | 35 } |
| 25 _errors.sort((AnalysisError error1, AnalysisError error2) { | |
| 26 // severity | |
| 27 var severity1 = errorSeverity(_context, error1); | |
| 28 var severity2 = errorSeverity(_context, error2); | |
| 29 int compare = severity2.compareTo(severity1); | |
| 30 if (compare != 0) return compare; | |
| 31 | 36 |
| 32 // path | 37 // TODO(jmesserly): this was from analyzer_cli, we should factor it differently. |
| 33 compare = Comparable.compare(error1.source.fullName.toLowerCase(), | 38 String formatError(AnalysisContext context, AnalysisError error) { |
| 34 error2.source.fullName.toLowerCase()); | 39 var severity = errorSeverity(context, error); |
| 35 if (compare != 0) return compare; | 40 // Skip hints, some like TODOs are not useful. |
| 41 if (severity.ordinal <= ErrorSeverity.INFO.ordinal) return null; |
| 36 | 42 |
| 37 // offset | 43 var lineInfo = context.computeLineInfo(error.source); |
| 38 compare = error1.offset - error2.offset; | 44 var location = lineInfo.getLocation(error.offset); |
| 39 if (compare != 0) return compare; | |
| 40 | 45 |
| 41 // compare message, in worst case. | 46 // [warning] 'foo' is not a... (/Users/.../tmp/foo.dart, line 1, col 2) |
| 42 return error1.message.compareTo(error2.message); | 47 return (new StringBuffer() |
| 43 }); | 48 ..write('[${severity.displayName}] ') |
| 44 | 49 ..write(error.message) |
| 45 _errors.forEach(listener.onError); | 50 ..write(' (${path.prettyUri(error.source.uri)}') |
| 46 _errors.clear(); | 51 ..write(', line ${location.lineNumber}, col ${location.columnNumber})')) |
| 47 } | 52 .toString(); |
| 48 | |
| 49 void onError(AnalysisError error) { | |
| 50 _errors.add(error); | |
| 51 } | |
| 52 } | 53 } |
| 53 | 54 |
| 54 ErrorSeverity errorSeverity(AnalysisContext context, AnalysisError error) { | 55 ErrorSeverity errorSeverity(AnalysisContext context, AnalysisError error) { |
| 55 var code = error.errorCode; | 56 var code = error.errorCode; |
| 56 if (code is StaticWarningCode) { | 57 if (code is StaticWarningCode) { |
| 57 // TODO(jmesserly): many more warnings need to be promoted for soundness. | 58 // TODO(jmesserly): many more warnings need to be promoted for soundness. |
| 58 // Also code generation will blow up finding null types/elements for many | 59 // Also code generation will blow up finding null types/elements for many |
| 59 // of these, or we rely on them to produce valid optimizations. | 60 // of these, or we rely on them to produce valid optimizations. |
| 60 switch (code.name) { | 61 switch (code.name) { |
| 61 case 'AMBIGUOUS_IMPORT': | 62 case 'AMBIGUOUS_IMPORT': |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 // analyzer_cli and server use. | 174 // analyzer_cli and server use. |
| 174 // | 175 // |
| 175 // Among the issues with ErrorProcessor.getProcessor: | 176 // Among the issues with ErrorProcessor.getProcessor: |
| 176 // * it needs to be called per-error, so it's a performance trap. | 177 // * it needs to be called per-error, so it's a performance trap. |
| 177 // * it can return null | 178 // * it can return null |
| 178 // * using AnalysisError directly is now suspect, it's a correctness trap | 179 // * using AnalysisError directly is now suspect, it's a correctness trap |
| 179 // * it requires an AnalysisContext | 180 // * it requires an AnalysisContext |
| 180 return ErrorProcessor.getProcessor(context, error)?.severity ?? | 181 return ErrorProcessor.getProcessor(context, error)?.severity ?? |
| 181 error.errorCode.errorSeverity; | 182 error.errorCode.errorSeverity; |
| 182 } | 183 } |
| 183 | |
| 184 /// Simple reporter that logs checker messages as they are seen. | |
| 185 class LogReporter implements AnalysisErrorListener { | |
| 186 final AnalysisContext _context; | |
| 187 final bool useColors; | |
| 188 final List<AnalysisError> _errors = []; | |
| 189 | |
| 190 LogReporter(this._context, {this.useColors: false}); | |
| 191 | |
| 192 void onError(AnalysisError error) { | |
| 193 var level = _severityToLevel[errorSeverity(_context, error)]; | |
| 194 | |
| 195 // TODO(jmesserly): figure out what to do with the error's name. | |
| 196 var lineInfo = _context.computeLineInfo(error.source); | |
| 197 var location = lineInfo.getLocation(error.offset); | |
| 198 | |
| 199 // [warning] 'foo' is not a... (/Users/.../tmp/foo.dart, line 1, col 2) | |
| 200 var text = new StringBuffer() | |
| 201 ..write('[${error.errorCode.name}] ') | |
| 202 ..write(error.message) | |
| 203 ..write(' (${path.prettyUri(error.source.uri)}') | |
| 204 ..write(', line ${location.lineNumber}, col ${location.columnNumber})'); | |
| 205 | |
| 206 // TODO(jmesserly): just print these instead of sending through logger? | |
| 207 _checkerLogger.log(level, text); | |
| 208 } | |
| 209 } | |
| 210 | |
| 211 // TODO(jmesserly): remove log levels, instead just use severity. | |
| 212 const _severityToLevel = const { | |
| 213 ErrorSeverity.ERROR: Level.SEVERE, | |
| 214 ErrorSeverity.WARNING: Level.WARNING, | |
| 215 ErrorSeverity.INFO: Level.INFO | |
| 216 }; | |
| OLD | NEW |