OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 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:analyzer/source/error_processor.dart'; | |
10 | |
11 final _checkerLogger = new Logger('dev_compiler.checker'); | |
12 | |
13 /// Collects errors, and then sorts them and sends them | |
14 class ErrorCollector implements AnalysisErrorListener { | |
15 final AnalysisContext _context; | |
16 final AnalysisErrorListener listener; | |
17 final List<AnalysisError> _errors = []; | |
18 | |
19 ErrorCollector(this._context, this.listener); | |
20 | |
21 /// Flushes errors to the log. Until this is called, errors are buffered. | |
22 void flush() { | |
23 // TODO(jmesserly): this code was taken from analyzer_cli. | |
24 // sort errors | |
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 | |
32 // path | |
33 compare = Comparable.compare(error1.source.fullName.toLowerCase(), | |
34 error2.source.fullName.toLowerCase()); | |
35 if (compare != 0) return compare; | |
36 | |
37 // offset | |
38 compare = error1.offset - error2.offset; | |
39 if (compare != 0) return compare; | |
40 | |
41 // compare message, in worst case. | |
42 return error1.message.compareTo(error2.message); | |
43 }); | |
44 | |
45 _errors.forEach(listener.onError); | |
46 _errors.clear(); | |
47 } | |
48 | |
49 void onError(AnalysisError error) { | |
50 _errors.add(error); | |
51 } | |
52 } | |
53 | |
54 ErrorSeverity errorSeverity(AnalysisContext context, AnalysisError error) { | |
55 var code = error.errorCode; | |
56 if (code is StaticWarningCode) { | |
57 // 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 // of these, or we rely on them to produce valid optimizations. | |
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 } | |
170 } | |
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; | |
182 } | |
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 |