Chromium Code Reviews| 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 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; | 5 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; |
| 6 import 'package:analyzer/src/generated/error.dart'; | 6 import 'package:analyzer/src/generated/error.dart'; |
| 7 import 'package:logging/logging.dart'; | 7 import 'package:logging/logging.dart'; |
| 8 import 'package:path/path.dart' as path; | 8 import 'package:path/path.dart' as path; |
| 9 import 'utils.dart'; | 9 import 'package:analyzer/source/error_processor.dart'; |
| 10 | 10 |
| 11 final _checkerLogger = new Logger('dev_compiler.checker'); | 11 final _checkerLogger = new Logger('dev_compiler.checker'); |
| 12 | 12 |
| 13 /// Collects errors, and then sorts them and sends them | 13 /// Collects errors, and then sorts them and sends them |
| 14 class ErrorCollector implements AnalysisErrorListener { | 14 class ErrorCollector implements AnalysisErrorListener { |
| 15 final AnalysisContext _context; | |
| 15 final AnalysisErrorListener listener; | 16 final AnalysisErrorListener listener; |
| 16 final List<AnalysisError> _errors = []; | 17 final List<AnalysisError> _errors = []; |
| 17 | 18 |
| 18 ErrorCollector(this.listener); | 19 ErrorCollector(this._context, this.listener); |
| 19 | 20 |
| 20 /// Flushes errors to the log. Until this is called, errors are buffered. | 21 /// Flushes errors to the log. Until this is called, errors are buffered. |
| 21 void flush() { | 22 void flush() { |
| 22 // TODO(jmesserly): this code was taken from analyzer_cli. | 23 // TODO(jmesserly): this code was taken from analyzer_cli. |
| 23 // sort errors | 24 // sort errors |
| 24 _errors.sort((AnalysisError error1, AnalysisError error2) { | 25 _errors.sort((AnalysisError error1, AnalysisError error2) { |
| 25 // severity | 26 // severity |
| 26 var severity1 = _strongModeErrorSeverity(error1); | 27 var severity1 = errorSeverity(_context, error1); |
| 27 var severity2 = _strongModeErrorSeverity(error2); | 28 var severity2 = errorSeverity(_context, error2); |
| 28 int compare = severity2.compareTo(severity1); | 29 int compare = severity2.compareTo(severity1); |
| 29 if (compare != 0) return compare; | 30 if (compare != 0) return compare; |
| 30 | 31 |
| 31 // path | 32 // path |
| 32 compare = Comparable.compare(error1.source.fullName.toLowerCase(), | 33 compare = Comparable.compare(error1.source.fullName.toLowerCase(), |
| 33 error2.source.fullName.toLowerCase()); | 34 error2.source.fullName.toLowerCase()); |
| 34 if (compare != 0) return compare; | 35 if (compare != 0) return compare; |
| 35 | 36 |
| 36 // offset | 37 // offset |
| 37 compare = error1.offset - error2.offset; | 38 compare = error1.offset - error2.offset; |
| 38 if (compare != 0) return compare; | 39 if (compare != 0) return compare; |
| 39 | 40 |
| 40 // compare message, in worst case. | 41 // compare message, in worst case. |
| 41 return error1.message.compareTo(error2.message); | 42 return error1.message.compareTo(error2.message); |
| 42 }); | 43 }); |
| 43 | 44 |
| 44 _errors.forEach(listener.onError); | 45 _errors.forEach(listener.onError); |
| 45 _errors.clear(); | 46 _errors.clear(); |
| 46 } | 47 } |
| 47 | 48 |
| 48 void onError(AnalysisError error) { | 49 void onError(AnalysisError error) { |
| 49 _errors.add(error); | 50 _errors.add(error); |
| 50 } | 51 } |
| 51 } | 52 } |
| 52 | 53 |
| 53 ErrorSeverity _strongModeErrorSeverity(AnalysisError error) { | 54 ErrorSeverity errorSeverity(AnalysisContext context, AnalysisError error) { |
| 54 // Upgrade analyzer warnings to errors. | 55 var code = error.errorCode; |
| 55 // TODO(jmesserly: reconcile this with analyzer_cli | 56 if (code is StaticWarningCode) { |
|
vsm
2016/03/29 22:10:54
Yikes! We should get these promoted / marked in t
Jennifer Messerly
2016/03/29 22:16:20
yeah, filed https://github.com/dart-lang/sdk/issue
| |
| 56 var severity = error.errorCode.errorSeverity; | 57 // TODO(jmesserly): many more warnings need to be promoted for soundness. |
| 57 if (!isStrongModeError(error.errorCode) && | 58 // Also code generation will blow up finding null types/elements for many |
| 58 severity == ErrorSeverity.WARNING) { | 59 // of these, or we rely on them to produce valid optimizations. |
| 59 return ErrorSeverity.ERROR; | 60 switch (code.name) { |
| 61 case 'AMBIGUOUS_IMPORT': | |
| 62 case 'ARGUMENT_TYPE_NOT_ASSIGNABLE': | |
| 63 case 'ARGUMENT_TYPE_NOT_ASSIGNABLE_STATIC_WARNING': | |
| 64 case 'ASSIGNMENT_TO_CONST': | |
| 65 case 'ASSIGNMENT_TO_FINAL': | |
| 66 case 'ASSIGNMENT_TO_FINAL_NO_SETTER': | |
| 67 case 'ASSIGNMENT_TO_FUNCTION': | |
| 68 case 'ASSIGNMENT_TO_METHOD': | |
| 69 case 'ASSIGNMENT_TO_TYPE': | |
| 70 case 'CASE_BLOCK_NOT_TERMINATED': | |
| 71 case 'CAST_TO_NON_TYPE': | |
| 72 case 'CONCRETE_CLASS_WITH_ABSTRACT_MEMBER': | |
| 73 case 'CONFLICTING_DART_IMPORT': | |
| 74 case 'CONFLICTING_INSTANCE_GETTER_AND_SUPERCLASS_MEMBER': | |
| 75 case 'CONFLICTING_INSTANCE_METHOD_SETTER': | |
| 76 case 'CONFLICTING_INSTANCE_SETTER_AND_SUPERCLASS_MEMBER': | |
| 77 case 'CONFLICTING_STATIC_GETTER_AND_INSTANCE_SETTER': | |
| 78 case 'CONFLICTING_STATIC_SETTER_AND_INSTANCE_MEMBER': | |
| 79 case 'CONST_WITH_ABSTRACT_CLASS': | |
| 80 case 'CONST_WITH_INVALID_TYPE_PARAMETERS': | |
| 81 case 'EQUAL_KEYS_IN_MAP': | |
| 82 case 'EXPORT_DUPLICATED_LIBRARY_NAMED': | |
| 83 case 'EXTRA_POSITIONAL_ARGUMENTS': | |
| 84 case 'FIELD_INITIALIZED_IN_INITIALIZER_AND_DECLARATION': | |
| 85 case 'FIELD_INITIALIZER_NOT_ASSIGNABLE': | |
| 86 case 'FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE': | |
| 87 case 'FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR': | |
| 88 case 'FUNCTION_WITHOUT_CALL': | |
| 89 case 'IMPORT_DUPLICATED_LIBRARY_NAMED': | |
| 90 case 'IMPORT_OF_NON_LIBRARY': | |
| 91 case 'INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD': | |
| 92 case 'INSTANCE_METHOD_NAME_COLLIDES_WITH_SUPERCLASS_STATIC': | |
| 93 case 'INVALID_GETTER_OVERRIDE_RETURN_TYPE': | |
| 94 case 'INVALID_METHOD_OVERRIDE_NAMED_PARAM_TYPE': | |
| 95 case 'INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE': | |
| 96 case 'INVALID_METHOD_OVERRIDE_OPTIONAL_PARAM_TYPE': | |
| 97 case 'INVALID_METHOD_OVERRIDE_RETURN_TYPE': | |
| 98 case 'INVALID_METHOD_OVERRIDE_TYPE_PARAMETERS': | |
| 99 case 'INVALID_METHOD_OVERRIDE_TYPE_PARAMETER_BOUND': | |
| 100 case 'INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_NAMED': | |
| 101 case 'INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSITIONAL': | |
| 102 case 'INVALID_OVERRIDE_NAMED': | |
| 103 case 'INVALID_OVERRIDE_POSITIONAL': | |
| 104 case 'INVALID_OVERRIDE_REQUIRED': | |
| 105 case 'INVALID_SETTER_OVERRIDE_NORMAL_PARAM_TYPE': | |
| 106 case 'LIST_ELEMENT_TYPE_NOT_ASSIGNABLE': | |
| 107 case 'MAP_KEY_TYPE_NOT_ASSIGNABLE': | |
| 108 case 'MAP_VALUE_TYPE_NOT_ASSIGNABLE': | |
| 109 case 'NEW_WITH_ABSTRACT_CLASS': | |
| 110 case 'NEW_WITH_INVALID_TYPE_PARAMETERS': | |
| 111 case 'NEW_WITH_NON_TYPE': | |
| 112 case 'NEW_WITH_UNDEFINED_CONSTRUCTOR': | |
| 113 case 'NEW_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT': | |
| 114 case 'NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS': | |
| 115 case 'NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR': | |
| 116 case 'NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE': | |
| 117 case 'NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE': | |
| 118 case 'NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO': | |
| 119 case 'NON_TYPE_IN_CATCH_CLAUSE': | |
| 120 case 'NOT_A_TYPE': | |
| 121 case 'NOT_ENOUGH_REQUIRED_ARGUMENTS': | |
| 122 case 'PART_OF_DIFFERENT_LIBRARY': | |
| 123 case 'REDIRECT_TO_INVALID_FUNCTION_TYPE': | |
| 124 case 'REDIRECT_TO_INVALID_RETURN_TYPE': | |
| 125 case 'REDIRECT_TO_MISSING_CONSTRUCTOR': | |
| 126 case 'REDIRECT_TO_NON_CLASS': | |
| 127 case 'STATIC_ACCESS_TO_INSTANCE_MEMBER': | |
| 128 case 'SWITCH_EXPRESSION_NOT_ASSIGNABLE': | |
| 129 case 'TYPE_ANNOTATION_DEFERRED_CLASS': | |
| 130 case 'TYPE_PARAMETER_REFERENCED_BY_STATIC': | |
| 131 case 'TYPE_TEST_WITH_NON_TYPE': | |
| 132 case 'TYPE_TEST_WITH_UNDEFINED_NAME': | |
| 133 case 'UNDEFINED_CLASS': | |
| 134 case 'UNDEFINED_CLASS_BOOLEAN': | |
| 135 case 'UNDEFINED_GETTER': | |
| 136 case 'UNDEFINED_GETTER_STATIC_WARNING': | |
| 137 case 'UNDEFINED_IDENTIFIER': | |
| 138 case 'UNDEFINED_NAMED_PARAMETER': | |
| 139 case 'UNDEFINED_SETTER': | |
| 140 case 'UNDEFINED_SETTER_STATIC_WARNING': | |
| 141 case 'UNDEFINED_STATIC_METHOD_OR_GETTER': | |
| 142 case 'UNDEFINED_SUPER_GETTER': | |
| 143 case 'UNDEFINED_SUPER_GETTER_STATIC_WARNING': | |
| 144 case 'UNDEFINED_SUPER_SETTER': | |
| 145 case 'UNDEFINED_SUPER_SETTER_STATIC_WARNING': | |
| 146 case 'WRONG_NUMBER_OF_TYPE_ARGUMENTS': | |
| 147 return ErrorSeverity.ERROR; | |
| 148 | |
| 149 // All of the following ones are okay as warnings. | |
| 150 case 'FINAL_NOT_INITIALIZED': | |
| 151 case 'FINAL_NOT_INITIALIZED_CONSTRUCTOR_': | |
| 152 | |
| 153 // We don't rely on these for override checking, AFAIK. | |
| 154 case 'MISMATCHED_GETTER_AND_SETTER_TYPES': | |
| 155 case 'MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE': | |
| 156 | |
| 157 case 'MISSING_ENUM_CONSTANT_IN_SWITCH': | |
| 158 case 'MIXED_RETURN_TYPES': | |
| 159 | |
| 160 // TODO(jmesserly): I think codegen already handles this for []=. | |
| 161 // Though we could simplify it if we didn't need to handle this case. | |
| 162 case 'NON_VOID_RETURN_FOR_OPERATOR': | |
| 163 | |
| 164 case 'NON_VOID_RETURN_FOR_SETTER': | |
| 165 case 'RETURN_WITHOUT_VALUE': | |
| 166 case 'STATIC_WARNING': | |
| 167 case 'VOID_RETURN_FOR_GETTER': | |
| 168 break; | |
| 169 } | |
| 60 } | 170 } |
| 61 return severity; | 171 |
| 172 // TODO(jmesserly): this Analyzer API totally bonkers, but it's what | |
| 173 // analyzer_cli and server use. | |
| 174 // | |
| 175 // Among the issues with ErrorProcessor.getProcessor: | |
| 176 // * it needs to be called per-error, so it's a performance trap. | |
| 177 // * it can return null | |
| 178 // * using AnalysisError directly is now suspect, it's a correctness trap | |
| 179 // * it requires an AnalysisContext | |
| 180 return ErrorProcessor.getProcessor(context, error)?.severity ?? | |
| 181 error.errorCode.errorSeverity; | |
| 62 } | 182 } |
| 63 | 183 |
| 64 /// Simple reporter that logs checker messages as they are seen. | 184 /// Simple reporter that logs checker messages as they are seen. |
| 65 class LogReporter implements AnalysisErrorListener { | 185 class LogReporter implements AnalysisErrorListener { |
| 66 final AnalysisContext _context; | 186 final AnalysisContext _context; |
| 67 final bool useColors; | 187 final bool useColors; |
| 68 final List<AnalysisError> _errors = []; | 188 final List<AnalysisError> _errors = []; |
| 69 | 189 |
| 70 LogReporter(this._context, {this.useColors: false}); | 190 LogReporter(this._context, {this.useColors: false}); |
| 71 | 191 |
| 72 void onError(AnalysisError error) { | 192 void onError(AnalysisError error) { |
| 73 var level = _severityToLevel[_strongModeErrorSeverity(error)]; | 193 var level = _severityToLevel[errorSeverity(_context, error)]; |
| 74 | 194 |
| 75 // TODO(jmesserly): figure out what to do with the error's name. | 195 // TODO(jmesserly): figure out what to do with the error's name. |
| 76 var lineInfo = _context.computeLineInfo(error.source); | 196 var lineInfo = _context.computeLineInfo(error.source); |
| 77 var location = lineInfo.getLocation(error.offset); | 197 var location = lineInfo.getLocation(error.offset); |
| 78 | 198 |
| 79 // [warning] 'foo' is not a... (/Users/.../tmp/foo.dart, line 1, col 2) | 199 // [warning] 'foo' is not a... (/Users/.../tmp/foo.dart, line 1, col 2) |
| 80 var text = new StringBuffer() | 200 var text = new StringBuffer() |
| 81 ..write('[${errorCodeName(error.errorCode)}] ') | 201 ..write('[${error.errorCode.name}] ') |
| 82 ..write(error.message) | 202 ..write(error.message) |
| 83 ..write(' (${path.prettyUri(error.source.uri)}') | 203 ..write(' (${path.prettyUri(error.source.uri)}') |
| 84 ..write(', line ${location.lineNumber}, col ${location.columnNumber})'); | 204 ..write(', line ${location.lineNumber}, col ${location.columnNumber})'); |
| 85 | 205 |
| 86 // TODO(jmesserly): just print these instead of sending through logger? | 206 // TODO(jmesserly): just print these instead of sending through logger? |
| 87 _checkerLogger.log(level, text); | 207 _checkerLogger.log(level, text); |
| 88 } | 208 } |
| 89 } | 209 } |
| 90 | 210 |
| 91 // TODO(jmesserly): remove log levels, instead just use severity. | 211 // TODO(jmesserly): remove log levels, instead just use severity. |
| 92 const _severityToLevel = const { | 212 const _severityToLevel = const { |
| 93 ErrorSeverity.ERROR: Level.SEVERE, | 213 ErrorSeverity.ERROR: Level.SEVERE, |
| 94 ErrorSeverity.WARNING: Level.WARNING, | 214 ErrorSeverity.WARNING: Level.WARNING, |
| 95 ErrorSeverity.INFO: Level.INFO | 215 ErrorSeverity.INFO: Level.INFO |
| 96 }; | 216 }; |
| OLD | NEW |