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 |