| 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 // 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/src/dart/ast/token.dart'; | 14 import 'package:analyzer/src/dart/ast/token.dart'; |
| 15 import 'package:analyzer/src/generated/engine.dart'; | 15 import 'package:analyzer/src/generated/engine.dart'; |
| 16 import 'package:analyzer/src/generated/error.dart'; | 16 import 'package:analyzer/src/generated/error.dart'; |
| 17 import 'package:analyzer/src/generated/source.dart'; | 17 import 'package:analyzer/src/generated/source.dart'; |
| 18 import 'package:analyzer/src/generated/type_system.dart'; | |
| 19 import 'package:analyzer/src/task/strong/checker.dart'; | |
| 20 import 'package:logging/logging.dart'; | 18 import 'package:logging/logging.dart'; |
| 21 import 'package:source_span/source_span.dart'; | 19 import 'package:source_span/source_span.dart'; |
| 22 import 'package:unittest/unittest.dart'; | 20 import 'package:unittest/unittest.dart'; |
| 23 | 21 |
| 24 import '../../context/mock_sdk.dart'; | 22 import '../../context/mock_sdk.dart'; |
| 25 | 23 |
| 26 MemoryResourceProvider files; | 24 MemoryResourceProvider files; |
| 27 bool _checkCalled; | 25 bool _checkCalled; |
| 28 | 26 |
| 29 /// Adds a file to check. The file should contain: | 27 /// Adds a file to check. The file should contain: |
| (...skipping 27 matching lines...) Expand all Loading... |
| 57 void check() { | 55 void check() { |
| 58 _checkCalled = true; | 56 _checkCalled = true; |
| 59 | 57 |
| 60 expect(files.getFile('/main.dart').exists, true, | 58 expect(files.getFile('/main.dart').exists, true, |
| 61 reason: '`/main.dart` is missing'); | 59 reason: '`/main.dart` is missing'); |
| 62 | 60 |
| 63 var uriResolver = new _TestUriResolver(files); | 61 var uriResolver = new _TestUriResolver(files); |
| 64 // Enable task model strong mode | 62 // Enable task model strong mode |
| 65 var context = AnalysisEngine.instance.createAnalysisContext(); | 63 var context = AnalysisEngine.instance.createAnalysisContext(); |
| 66 context.analysisOptions.strongMode = true; | 64 context.analysisOptions.strongMode = true; |
| 67 context.analysisOptions.strongModeHints = true; | 65 (context.analysisOptions as AnalysisOptionsImpl).strongModeHints = true; |
| 68 context.sourceFactory = | 66 context.sourceFactory = |
| 69 new SourceFactory([new DartUriResolver(new MockSdk()), uriResolver]); | 67 new SourceFactory([new DartUriResolver(new MockSdk()), uriResolver]); |
| 70 | 68 |
| 71 // Run the checker on /main.dart. | 69 // Run the checker on /main.dart. |
| 72 Source mainSource = uriResolver.resolveAbsolute(new Uri.file('/main.dart')); | 70 Source mainSource = uriResolver.resolveAbsolute(new Uri.file('/main.dart')); |
| 73 var initialLibrary = context.resolveCompilationUnit2(mainSource, mainSource); | 71 var initialLibrary = context.resolveCompilationUnit2(mainSource, mainSource); |
| 74 | 72 |
| 75 var collector = new _ErrorCollector(); | 73 var collector = new _ErrorCollector(); |
| 76 var checker = new CodeChecker( | |
| 77 context.typeProvider, new StrongTypeSystemImpl(), collector, | |
| 78 hints: true); | |
| 79 | 74 |
| 80 // Extract expectations from the comments in the test files, and | 75 // Extract expectations from the comments in the test files, and |
| 81 // check that all errors we emit are included in the expected map. | 76 // check that all errors we emit are included in the expected map. |
| 82 var allLibraries = reachableLibraries(initialLibrary.element.library); | 77 var allLibraries = reachableLibraries(initialLibrary.element.library); |
| 83 for (var lib in allLibraries) { | 78 for (var lib in allLibraries) { |
| 84 for (var unit in lib.units) { | 79 for (var unit in lib.units) { |
| 85 var errors = <AnalysisError>[]; | 80 var errors = <AnalysisError>[]; |
| 86 collector.errors = errors; | 81 collector.errors = errors; |
| 87 | 82 |
| 88 var source = unit.source; | 83 var source = unit.source; |
| 89 if (source.uri.scheme == 'dart') continue; | 84 if (source.uri.scheme == 'dart') continue; |
| 90 | 85 |
| 91 var librarySource = context.getLibrariesContaining(source).single; | 86 var librarySource = context.getLibrariesContaining(source).single; |
| 92 var resolved = context.resolveCompilationUnit2(source, librarySource); | 87 var resolved = context.resolveCompilationUnit2(source, librarySource); |
| 93 errors.addAll(context.getErrors(source).errors.where((error) => | 88 errors.addAll(context.getErrors(source).errors.where((e) => |
| 94 error.errorCode.name.startsWith('STRONG_MODE_INFERRED_TYPE'))); | 89 e.errorCode != HintCode.UNUSED_LOCAL_VARIABLE && |
| 95 checker.visitCompilationUnit(resolved); | 90 // TODO(jmesserly): these are usually intentional dynamic calls. |
| 91 e.errorCode.name != 'UNDEFINED_METHOD')); |
| 96 | 92 |
| 97 _expectErrors(resolved, errors); | 93 _expectErrors(resolved, errors); |
| 98 } | 94 } |
| 99 } | 95 } |
| 100 } | 96 } |
| 101 | 97 |
| 102 /// Adds a file using [addFile] and calls [check]. | 98 /// Adds a file using [addFile] and calls [check]. |
| 103 void checkFile(String content) { | 99 void checkFile(String content) { |
| 104 addFile(content); | 100 addFile(content); |
| 105 check(); | 101 check(); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 124 if (end == null) { | 120 if (end == null) { |
| 125 end = lineEnd; | 121 end = lineEnd; |
| 126 endLoc = locationForOffset(lineInfo, source.uri, lineEnd); | 122 endLoc = locationForOffset(lineInfo, source.uri, lineEnd); |
| 127 } | 123 } |
| 128 | 124 |
| 129 var text = content.substring(start, end); | 125 var text = content.substring(start, end); |
| 130 var lineText = content.substring(lineStart, lineEnd); | 126 var lineText = content.substring(lineStart, lineEnd); |
| 131 return new SourceSpanWithContext(startLoc, endLoc, text, lineText); | 127 return new SourceSpanWithContext(startLoc, endLoc, text, lineText); |
| 132 } | 128 } |
| 133 | 129 |
| 134 String errorCodeName(ErrorCode errorCode) { | 130 String _errorCodeName(ErrorCode errorCode) { |
| 135 var name = errorCode.name; | 131 var name = errorCode.name; |
| 136 final prefix = 'STRONG_MODE_'; | 132 final prefix = 'STRONG_MODE_'; |
| 137 if (name.startsWith(prefix)) { | 133 if (name.startsWith(prefix)) { |
| 138 return name.substring(prefix.length); | 134 return name.substring(prefix.length); |
| 139 } else { | 135 } else { |
| 140 // TODO(jmesserly): this is for backwards compat, but not sure it's very | 136 return name; |
| 141 // useful to log this. | |
| 142 return 'AnalyzerMessage'; | |
| 143 } | 137 } |
| 144 } | 138 } |
| 145 | 139 |
| 146 initStrongModeTests() { | 140 initStrongModeTests() { |
| 147 setUp(() { | 141 setUp(() { |
| 148 AnalysisEngine.instance.processRequiredPlugins(); | 142 AnalysisEngine.instance.processRequiredPlugins(); |
| 149 files = new MemoryResourceProvider(); | 143 files = new MemoryResourceProvider(); |
| 150 _checkCalled = false; | 144 _checkCalled = false; |
| 151 }); | 145 }); |
| 152 | 146 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 183 return const <ErrorSeverity, Level>{ | 177 return const <ErrorSeverity, Level>{ |
| 184 ErrorSeverity.ERROR: Level.SEVERE, | 178 ErrorSeverity.ERROR: Level.SEVERE, |
| 185 ErrorSeverity.WARNING: Level.WARNING, | 179 ErrorSeverity.WARNING: Level.WARNING, |
| 186 ErrorSeverity.INFO: Level.INFO | 180 ErrorSeverity.INFO: Level.INFO |
| 187 }[actual.errorCode.errorSeverity]; | 181 }[actual.errorCode.errorSeverity]; |
| 188 } | 182 } |
| 189 | 183 |
| 190 void _expectErrors(CompilationUnit unit, List<AnalysisError> actualErrors) { | 184 void _expectErrors(CompilationUnit unit, List<AnalysisError> actualErrors) { |
| 191 var expectedErrors = _findExpectedErrors(unit.beginToken); | 185 var expectedErrors = _findExpectedErrors(unit.beginToken); |
| 192 | 186 |
| 187 // Sort both lists: by offset, then level, then name. |
| 188 actualErrors.sort((x, y) { |
| 189 int delta = x.offset.compareTo(y.offset); |
| 190 if (delta != 0) return delta; |
| 191 |
| 192 delta = x.errorCode.errorSeverity.compareTo(y.errorCode.errorSeverity); |
| 193 if (delta != 0) return delta; |
| 194 |
| 195 return _errorCodeName(x.errorCode).compareTo(_errorCodeName(y.errorCode)); |
| 196 }); |
| 197 expectedErrors.sort((x, y) { |
| 198 int delta = x.offset.compareTo(y.offset); |
| 199 if (delta != 0) return delta; |
| 200 |
| 201 delta = x.level.compareTo(y.level); |
| 202 if (delta != 0) return delta; |
| 203 |
| 204 return x.typeName.compareTo(y.typeName); |
| 205 }); |
| 206 |
| 193 // Categorize the differences, if any. | 207 // Categorize the differences, if any. |
| 194 var unreported = <_ErrorExpectation>[]; | 208 var unreported = <_ErrorExpectation>[]; |
| 195 var different = <_ErrorExpectation, AnalysisError>{}; | 209 var different = <_ErrorExpectation, AnalysisError>{}; |
| 196 | 210 |
| 197 for (var expected in expectedErrors) { | 211 for (var expected in expectedErrors) { |
| 198 AnalysisError actual = expected._removeMatchingActual(actualErrors); | 212 AnalysisError actual = expected._removeMatchingActual(actualErrors); |
| 199 if (actual != null) { | 213 if (actual != null) { |
| 200 if (_actualErrorLevel(actual) != expected.level || | 214 if (_actualErrorLevel(actual) != expected.level || |
| 201 errorCodeName(actual.errorCode) != expected.typeName) { | 215 _errorCodeName(actual.errorCode) != expected.typeName) { |
| 202 different[expected] = actual; | 216 different[expected] = actual; |
| 203 } | 217 } |
| 204 } else { | 218 } else { |
| 205 unreported.add(expected); | 219 unreported.add(expected); |
| 206 } | 220 } |
| 207 } | 221 } |
| 208 | 222 |
| 209 // Whatever is left was an unexpected error. | 223 // Whatever is left was an unexpected error. |
| 210 List<AnalysisError> unexpected = actualErrors; | 224 List<AnalysisError> unexpected = actualErrors; |
| 211 | 225 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 249 // all tests use memory file system. | 263 // all tests use memory file system. |
| 250 var sourceCode = unit.element.source.contents.data; | 264 var sourceCode = unit.element.source.contents.data; |
| 251 | 265 |
| 252 String formatActualError(AnalysisError error) { | 266 String formatActualError(AnalysisError error) { |
| 253 int offset = error.offset; | 267 int offset = error.offset; |
| 254 int length = error.length; | 268 int length = error.length; |
| 255 var span = createSpanHelper( | 269 var span = createSpanHelper( |
| 256 unit.lineInfo, offset, unit.element.source, sourceCode, | 270 unit.lineInfo, offset, unit.element.source, sourceCode, |
| 257 end: offset + length); | 271 end: offset + length); |
| 258 var levelName = _actualErrorLevel(error).name.toLowerCase(); | 272 var levelName = _actualErrorLevel(error).name.toLowerCase(); |
| 259 return '@$offset $levelName: [${errorCodeName(error.errorCode)}]\n' + | 273 return '@$offset $levelName:${_errorCodeName(error.errorCode)}\n' + |
| 260 span.message(error.message); | 274 span.message(error.message); |
| 261 } | 275 } |
| 262 | 276 |
| 263 String formatExpectedError(_ErrorExpectation error) { | 277 String formatExpectedError(_ErrorExpectation error) { |
| 264 int offset = error.offset; | 278 int offset = error.offset; |
| 265 var span = createSpanHelper( | 279 var span = createSpanHelper( |
| 266 unit.lineInfo, offset, unit.element.source, sourceCode); | 280 unit.lineInfo, offset, unit.element.source, sourceCode); |
| 267 var levelName = error.level.toString().toLowerCase(); | 281 var levelName = error.level.toString().toLowerCase(); |
| 268 return '@$offset $levelName: [${error.typeName}]\n' + span.message(''); | 282 return '@$offset $levelName:${error.typeName}\n' + span.message(''); |
| 269 } | 283 } |
| 270 | 284 |
| 271 var message = new StringBuffer(); | 285 var message = new StringBuffer(); |
| 272 if (unreported.isNotEmpty) { | 286 if (unreported.isNotEmpty) { |
| 273 message.writeln('Expected errors that were not reported:'); | 287 message.writeln('Expected errors that were not reported:'); |
| 274 unreported.map(formatExpectedError).forEach(message.writeln); | 288 unreported.map(formatExpectedError).forEach(message.writeln); |
| 275 message.writeln(); | 289 message.writeln(); |
| 276 } | 290 } |
| 277 if (unexpected.isNotEmpty) { | 291 if (unexpected.isNotEmpty) { |
| 278 message.writeln('Errors that were not expected:'); | 292 message.writeln('Errors that were not expected:'); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 | 377 |
| 364 @override | 378 @override |
| 365 Source resolveAbsolute(Uri uri, [Uri actualUri]) { | 379 Source resolveAbsolute(Uri uri, [Uri actualUri]) { |
| 366 if (uri.scheme == 'package') { | 380 if (uri.scheme == 'package') { |
| 367 return (provider.getResource('/packages/' + uri.path) as File) | 381 return (provider.getResource('/packages/' + uri.path) as File) |
| 368 .createSource(uri); | 382 .createSource(uri); |
| 369 } | 383 } |
| 370 return super.resolveAbsolute(uri, actualUri); | 384 return super.resolveAbsolute(uri, actualUri); |
| 371 } | 385 } |
| 372 } | 386 } |
| OLD | NEW |