Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(82)

Side by Side Diff: pkg/analyzer/test/src/task/strong/strong_test_helper.dart

Issue 2062793003: Revert "Revert "Refactor strong mode to use standard Analyzer errors"" (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pkg/analyzer/test/src/task/strong/inferred_type_test.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 // TODO(jmesserly): this file needs to be refactored, it's a port from 5 // TODO(jmesserly): this file needs to be refactored, it's a port from
6 // package:dev_compiler's tests 6 // package:dev_compiler's tests
7 library analyzer.test.src.task.strong.strong_test_helper; 7 library analyzer.test.src.task.strong.strong_test_helper;
8 8
9 import 'package:analyzer/dart/ast/ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/ast/token.dart'; 10 import 'package:analyzer/dart/ast/token.dart';
11 import 'package:analyzer/dart/element/element.dart'; 11 import 'package:analyzer/dart/element/element.dart';
12 import 'package:analyzer/file_system/file_system.dart'; 12 import 'package:analyzer/file_system/file_system.dart';
13 import 'package:analyzer/file_system/memory_file_system.dart'; 13 import 'package:analyzer/file_system/memory_file_system.dart';
14 import 'package:analyzer/source/error_processor.dart';
14 import 'package:analyzer/src/dart/ast/token.dart'; 15 import 'package:analyzer/src/dart/ast/token.dart';
15 import 'package:analyzer/src/generated/engine.dart'; 16 import 'package:analyzer/src/generated/engine.dart';
16 import 'package:analyzer/src/generated/error.dart'; 17 import 'package:analyzer/src/generated/error.dart';
17 import 'package:analyzer/src/generated/source.dart'; 18 import 'package:analyzer/src/generated/source.dart';
18 import 'package:logging/logging.dart'; 19 import 'package:logging/logging.dart';
19 import 'package:source_span/source_span.dart'; 20 import 'package:source_span/source_span.dart';
20 import 'package:unittest/unittest.dart'; 21 import 'package:unittest/unittest.dart';
21 22
22 import '../../context/mock_sdk.dart'; 23 import '../../context/mock_sdk.dart';
23 24
24 MemoryResourceProvider files; 25 MemoryResourceProvider files;
25 bool _checkCalled; 26 bool _checkCalled;
26 27
27 /// Adds a file to check. The file should contain: 28 /// Adds a file to check. The file should contain:
28 /// 29 ///
29 /// * all expected failures are listed in the source code using comments 30 /// * all expected failures are listed in the source code using comments
30 /// immediately in front of the AST node that should contain the error. 31 /// immediately in front of the AST node that should contain the error.
31 /// 32 ///
32 /// * errors are formatted as a token `level:Type`, where `level` is the 33 /// * errors are formatted as a token `severity:ErrorCode`, where
33 /// logging level were the error would be reported at, and `Type` is the 34 /// `severity` is the ErrorSeverity the error would be reported at, and
34 /// concrete subclass of [StaticInfo] that denotes the error. 35 /// `ErrorCode` is the error code's name.
35 /// 36 ///
36 /// For example to check that an assignment produces a type error, you can 37 /// For example to check that an assignment produces a type error, you can
37 /// create a file like: 38 /// create a file like:
38 /// 39 ///
39 /// addFile(''' 40 /// addFile('''
40 /// String x = /*severe:STATIC_TYPE_ERROR*/3; 41 /// String x = /*severe:STATIC_TYPE_ERROR*/3;
41 /// '''); 42 /// ''');
42 /// check(); 43 /// check();
43 /// 44 ///
44 /// For a single file, you may also use [checkFile]. 45 /// For a single file, you may also use [checkFile].
(...skipping 24 matching lines...) Expand all
69 options.implicitCasts = implicitCasts; 70 options.implicitCasts = implicitCasts;
70 var mockSdk = new MockSdk(); 71 var mockSdk = new MockSdk();
71 mockSdk.context.analysisOptions.strongMode = true; 72 mockSdk.context.analysisOptions.strongMode = true;
72 context.sourceFactory = 73 context.sourceFactory =
73 new SourceFactory([new DartUriResolver(mockSdk), uriResolver]); 74 new SourceFactory([new DartUriResolver(mockSdk), uriResolver]);
74 75
75 // Run the checker on /main.dart. 76 // Run the checker on /main.dart.
76 Source mainSource = uriResolver.resolveAbsolute(new Uri.file('/main.dart')); 77 Source mainSource = uriResolver.resolveAbsolute(new Uri.file('/main.dart'));
77 var initialLibrary = context.resolveCompilationUnit2(mainSource, mainSource); 78 var initialLibrary = context.resolveCompilationUnit2(mainSource, mainSource);
78 79
79 var collector = new _ErrorCollector(); 80 var collector = new _ErrorCollector(context);
80 81
81 // Extract expectations from the comments in the test files, and 82 // Extract expectations from the comments in the test files, and
82 // check that all errors we emit are included in the expected map. 83 // check that all errors we emit are included in the expected map.
83 var allLibraries = _reachableLibraries(initialLibrary.element.library); 84 var allLibraries = _reachableLibraries(initialLibrary.element.library);
84 for (var lib in allLibraries) { 85 for (var lib in allLibraries) {
85 for (var unit in lib.units) { 86 for (var unit in lib.units) {
86 var errors = <AnalysisError>[]; 87 var errors = <AnalysisError>[];
87 collector.errors = errors; 88 collector.errors = errors;
88 89
89 var source = unit.source; 90 var source = unit.source;
90 if (source.uri.scheme == 'dart') continue; 91 if (source.uri.scheme == 'dart') continue;
91 92
92 var librarySource = context.getLibrariesContaining(source).single; 93 var librarySource = context.getLibrariesContaining(source).single;
93 var resolved = context.resolveCompilationUnit2(source, librarySource); 94 var resolved = context.resolveCompilationUnit2(source, librarySource);
94 95
95 errors.addAll(context.computeErrors(source).where((e) => 96 errors.addAll(context.computeErrors(source).where((e) =>
96 // TODO(jmesserly): these are usually intentional dynamic calls. 97 // TODO(jmesserly): these are usually intentional dynamic calls.
97 e.errorCode.name != 'UNDEFINED_METHOD' && 98 e.errorCode.name != 'UNDEFINED_METHOD' &&
98 // We don't care about any of these: 99 // We don't care about any of these:
99 e.errorCode != HintCode.UNNECESSARY_CAST && 100 e.errorCode != HintCode.UNNECESSARY_CAST &&
100 e.errorCode != HintCode.UNUSED_ELEMENT && 101 e.errorCode != HintCode.UNUSED_ELEMENT &&
101 e.errorCode != HintCode.UNUSED_FIELD && 102 e.errorCode != HintCode.UNUSED_FIELD &&
102 e.errorCode != HintCode.UNUSED_IMPORT && 103 e.errorCode != HintCode.UNUSED_IMPORT &&
103 e.errorCode != HintCode.UNUSED_LOCAL_VARIABLE && 104 e.errorCode != HintCode.UNUSED_LOCAL_VARIABLE &&
104 e.errorCode != TodoCode.TODO)); 105 e.errorCode != TodoCode.TODO));
105 _expectErrors(resolved, errors); 106 _expectErrors(context, resolved, errors);
106 } 107 }
107 } 108 }
108 109
109 return initialLibrary; 110 return initialLibrary;
110 } 111 }
111 112
112 /// Adds a file using [addFile] and calls [check]. 113 /// Adds a file using [addFile] and calls [check].
113 /// 114 ///
114 /// Also returns the resolved compilation unit. 115 /// Also returns the resolved compilation unit.
115 CompilationUnit checkFile(String content) { 116 CompilationUnit checkFile(String content) {
116 addFile(content); 117 addFile(content);
117 return check(); 118 return check();
118 } 119 }
119 120
120 void initStrongModeTests() { 121 void initStrongModeTests() {
121 setUp(() { 122 setUp(() {
122 AnalysisEngine.instance.processRequiredPlugins(); 123 AnalysisEngine.instance.processRequiredPlugins();
123 files = new MemoryResourceProvider(); 124 files = new MemoryResourceProvider();
124 _checkCalled = false; 125 _checkCalled = false;
125 }); 126 });
126 127
127 tearDown(() { 128 tearDown(() {
128 // This is a sanity check, in case only addFile is called. 129 // This is a sanity check, in case only addFile is called.
129 expect(_checkCalled, true, reason: 'must call check() method in test case'); 130 expect(_checkCalled, true, reason: 'must call check() method in test case');
130 files = null; 131 files = null;
131 }); 132 });
132 } 133 }
133 134
134 Level _actualErrorLevel(AnalysisError actual) { 135 Level _actualErrorLevel(AnalysisContext context, AnalysisError actual) {
135 return const <ErrorSeverity, Level>{ 136 return const <ErrorSeverity, Level>{
136 ErrorSeverity.ERROR: Level.SEVERE, 137 ErrorSeverity.ERROR: Level.SEVERE,
137 ErrorSeverity.WARNING: Level.WARNING, 138 ErrorSeverity.WARNING: Level.WARNING,
138 ErrorSeverity.INFO: Level.INFO 139 ErrorSeverity.INFO: Level.INFO
139 }[actual.errorCode.errorSeverity]; 140 }[_errorSeverity(context, actual)];
140 } 141 }
141 142
142 SourceSpanWithContext _createSpanHelper( 143 SourceSpanWithContext _createSpanHelper(
143 LineInfo lineInfo, int start, Source source, String content, 144 LineInfo lineInfo, int start, Source source, String content,
144 {int end}) { 145 {int end}) {
145 var startLoc = _locationForOffset(lineInfo, source.uri, start); 146 var startLoc = _locationForOffset(lineInfo, source.uri, start);
146 var endLoc = _locationForOffset(lineInfo, source.uri, end ?? start); 147 var endLoc = _locationForOffset(lineInfo, source.uri, end ?? start);
147 148
148 var lineStart = startLoc.offset - startLoc.column; 149 var lineStart = startLoc.offset - startLoc.column;
149 // Find the end of the line. This is not exposed directly on LineInfo, but 150 // Find the end of the line. This is not exposed directly on LineInfo, but
(...skipping 18 matching lines...) Expand all
168 String _errorCodeName(ErrorCode errorCode) { 169 String _errorCodeName(ErrorCode errorCode) {
169 var name = errorCode.name; 170 var name = errorCode.name;
170 final prefix = 'STRONG_MODE_'; 171 final prefix = 'STRONG_MODE_';
171 if (name.startsWith(prefix)) { 172 if (name.startsWith(prefix)) {
172 return name.substring(prefix.length); 173 return name.substring(prefix.length);
173 } else { 174 } else {
174 return name; 175 return name;
175 } 176 }
176 } 177 }
177 178
178 void _expectErrors(CompilationUnit unit, List<AnalysisError> actualErrors) { 179 ErrorSeverity _errorSeverity(AnalysisContext context, AnalysisError error) {
180 // Attempt to process severity in a similar way to analyzer_cli and server.
181 return ErrorProcessor.getProcessor(context, error)?.severity ??
182 error.errorCode.errorSeverity;
183 }
184
185 void _expectErrors(AnalysisContext context, CompilationUnit unit,
186 List<AnalysisError> actualErrors) {
179 var expectedErrors = _findExpectedErrors(unit.beginToken); 187 var expectedErrors = _findExpectedErrors(unit.beginToken);
180 188
181 // Sort both lists: by offset, then level, then name. 189 // Sort both lists: by offset, then level, then name.
182 actualErrors.sort((x, y) { 190 actualErrors.sort((x, y) {
183 int delta = x.offset.compareTo(y.offset); 191 int delta = x.offset.compareTo(y.offset);
184 if (delta != 0) return delta; 192 if (delta != 0) return delta;
185 193
186 delta = x.errorCode.errorSeverity.compareTo(y.errorCode.errorSeverity); 194 delta = _errorSeverity(context, x).compareTo(_errorSeverity(context, y));
187 if (delta != 0) return delta; 195 if (delta != 0) return delta;
188 196
189 return _errorCodeName(x.errorCode).compareTo(_errorCodeName(y.errorCode)); 197 return _errorCodeName(x.errorCode).compareTo(_errorCodeName(y.errorCode));
190 }); 198 });
191 expectedErrors.sort((x, y) { 199 expectedErrors.sort((x, y) {
192 int delta = x.offset.compareTo(y.offset); 200 int delta = x.offset.compareTo(y.offset);
193 if (delta != 0) return delta; 201 if (delta != 0) return delta;
194 202
195 delta = x.level.compareTo(y.level); 203 delta = x.level.compareTo(y.level);
196 if (delta != 0) return delta; 204 if (delta != 0) return delta;
197 205
198 return x.typeName.compareTo(y.typeName); 206 return x.typeName.compareTo(y.typeName);
199 }); 207 });
200 208
201 // Categorize the differences, if any. 209 // Categorize the differences, if any.
202 var unreported = <_ErrorExpectation>[]; 210 var unreported = <_ErrorExpectation>[];
203 var different = <_ErrorExpectation, AnalysisError>{}; 211 var different = <_ErrorExpectation, AnalysisError>{};
204 212
205 for (var expected in expectedErrors) { 213 for (var expected in expectedErrors) {
206 AnalysisError actual = expected._removeMatchingActual(actualErrors); 214 AnalysisError actual = expected._removeMatchingActual(actualErrors);
207 if (actual != null) { 215 if (actual != null) {
208 if (_actualErrorLevel(actual) != expected.level || 216 if (_actualErrorLevel(context, actual) != expected.level ||
209 _errorCodeName(actual.errorCode) != expected.typeName) { 217 _errorCodeName(actual.errorCode) != expected.typeName) {
210 different[expected] = actual; 218 different[expected] = actual;
211 } 219 }
212 } else { 220 } else {
213 unreported.add(expected); 221 unreported.add(expected);
214 } 222 }
215 } 223 }
216 224
217 // Whatever is left was an unexpected error. 225 // Whatever is left was an unexpected error.
218 List<AnalysisError> unexpected = actualErrors; 226 List<AnalysisError> unexpected = actualErrors;
219 227
220 if (unreported.isNotEmpty || unexpected.isNotEmpty || different.isNotEmpty) { 228 if (unreported.isNotEmpty || unexpected.isNotEmpty || different.isNotEmpty) {
221 _reportFailure(unit, unreported, unexpected, different); 229 _reportFailure(context, unit, unreported, unexpected, different);
222 } 230 }
223 } 231 }
224 232
225 List<_ErrorExpectation> _findExpectedErrors(Token beginToken) { 233 List<_ErrorExpectation> _findExpectedErrors(Token beginToken) {
226 var expectedErrors = <_ErrorExpectation>[]; 234 var expectedErrors = <_ErrorExpectation>[];
227 235
228 // Collect expectations like "severe:STATIC_TYPE_ERROR" from comment tokens. 236 // Collect expectations like "severe:STATIC_TYPE_ERROR" from comment tokens.
229 for (Token t = beginToken; t.type != TokenType.EOF; t = t.next) { 237 for (Token t = beginToken; t.type != TokenType.EOF; t = t.next) {
230 for (CommentToken c = t.precedingComments; c != null; c = c.next) { 238 for (CommentToken c = t.precedingComments; c != null; c = c.next) {
231 if (c.type == TokenType.MULTI_LINE_COMMENT) { 239 if (c.type == TokenType.MULTI_LINE_COMMENT) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 seen.add(lib); 273 seen.add(lib);
266 results.add(lib); 274 results.add(lib);
267 lib.importedLibraries.forEach(find); 275 lib.importedLibraries.forEach(find);
268 lib.exportedLibraries.forEach(find); 276 lib.exportedLibraries.forEach(find);
269 } 277 }
270 find(start); 278 find(start);
271 return results; 279 return results;
272 } 280 }
273 281
274 void _reportFailure( 282 void _reportFailure(
283 AnalysisContext context,
275 CompilationUnit unit, 284 CompilationUnit unit,
276 List<_ErrorExpectation> unreported, 285 List<_ErrorExpectation> unreported,
277 List<AnalysisError> unexpected, 286 List<AnalysisError> unexpected,
278 Map<_ErrorExpectation, AnalysisError> different) { 287 Map<_ErrorExpectation, AnalysisError> different) {
279 // Get the source code. This reads the data again, but it's safe because 288 // Get the source code. This reads the data again, but it's safe because
280 // all tests use memory file system. 289 // all tests use memory file system.
281 var sourceCode = unit.element.source.contents.data; 290 var sourceCode = unit.element.source.contents.data;
282 291
283 String formatActualError(AnalysisError error) { 292 String formatActualError(AnalysisError error) {
284 int offset = error.offset; 293 int offset = error.offset;
285 int length = error.length; 294 int length = error.length;
286 var span = _createSpanHelper( 295 var span = _createSpanHelper(
287 unit.lineInfo, offset, unit.element.source, sourceCode, 296 unit.lineInfo, offset, unit.element.source, sourceCode,
288 end: offset + length); 297 end: offset + length);
289 var levelName = _actualErrorLevel(error).name.toLowerCase(); 298 var levelName = _actualErrorLevel(context, error).name.toLowerCase();
290 return '@$offset $levelName:${_errorCodeName(error.errorCode)}\n' + 299 return '@$offset $levelName:${_errorCodeName(error.errorCode)}\n' +
291 span.message(error.message); 300 span.message(error.message);
292 } 301 }
293 302
294 String formatExpectedError(_ErrorExpectation error) { 303 String formatExpectedError(_ErrorExpectation error) {
295 int offset = error.offset; 304 int offset = error.offset;
296 var span = _createSpanHelper( 305 var span = _createSpanHelper(
297 unit.lineInfo, offset, unit.element.source, sourceCode); 306 unit.lineInfo, offset, unit.element.source, sourceCode);
298 var levelName = error.level.toString().toLowerCase(); 307 var levelName = error.level.toString().toLowerCase();
299 return '@$offset $levelName:${error.typeName}\n' + span.message(''); 308 return '@$offset $levelName:${error.typeName}\n' + span.message('');
(...skipping 15 matching lines...) Expand all
315 different.forEach((expected, actual) { 324 different.forEach((expected, actual) {
316 message.writeln('Expected: ' + formatExpectedError(expected)); 325 message.writeln('Expected: ' + formatExpectedError(expected));
317 message.writeln('Actual: ' + formatActualError(actual)); 326 message.writeln('Actual: ' + formatActualError(actual));
318 }); 327 });
319 message.writeln(); 328 message.writeln();
320 } 329 }
321 fail('Checker errors do not match expected errors:\n\n$message'); 330 fail('Checker errors do not match expected errors:\n\n$message');
322 } 331 }
323 332
324 class _ErrorCollector implements AnalysisErrorListener { 333 class _ErrorCollector implements AnalysisErrorListener {
334 final AnalysisContext _context;
325 List<AnalysisError> errors; 335 List<AnalysisError> errors;
326 final bool hints; 336 final bool hints;
327 337
328 _ErrorCollector({this.hints: true}); 338 _ErrorCollector(this._context, {this.hints: true});
329 339
330 void onError(AnalysisError error) { 340 void onError(AnalysisError error) {
331 // Unless DDC hints are requested, filter them out. 341 // Unless DDC hints are requested, filter them out.
332 var HINT = ErrorSeverity.INFO.ordinal; 342 var HINT = ErrorSeverity.INFO.ordinal;
333 if (hints || error.errorCode.errorSeverity.ordinal > HINT) { 343 if (hints || _errorSeverity(_context, error).ordinal > HINT) {
334 errors.add(error); 344 errors.add(error);
335 } 345 }
336 } 346 }
337 } 347 }
338 348
339 /// Describes an expected message that should be produced by the checker. 349 /// Describes an expected message that should be produced by the checker.
340 class _ErrorExpectation { 350 class _ErrorExpectation {
341 final int offset; 351 final int offset;
342 final Level level; 352 final Level level;
343 final String typeName; 353 final String typeName;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
394 404
395 @override 405 @override
396 Source resolveAbsolute(Uri uri, [Uri actualUri]) { 406 Source resolveAbsolute(Uri uri, [Uri actualUri]) {
397 if (uri.scheme == 'package') { 407 if (uri.scheme == 'package') {
398 return (provider.getResource('/packages/' + uri.path) as File) 408 return (provider.getResource('/packages/' + uri.path) as File)
399 .createSource(uri); 409 .createSource(uri);
400 } 410 }
401 return super.resolveAbsolute(uri, actualUri); 411 return super.resolveAbsolute(uri, actualUri);
402 } 412 }
403 } 413 }
OLDNEW
« no previous file with comments | « pkg/analyzer/test/src/task/strong/inferred_type_test.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698