Index: pkg/analyzer/test/src/task/strong/strong_test_helper.dart |
diff --git a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart |
index 93763cb7aaaf5a2a09be729109b3cc6f3c33f8db..e858a37fcee5865fc99b97b8cd5f91b370b9485b 100644 |
--- a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart |
+++ b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart |
@@ -7,12 +7,13 @@ |
library analyzer.test.src.task.strong.strong_test_helper; |
import 'package:analyzer/dart/ast/ast.dart'; |
+import 'package:analyzer/dart/ast/token.dart'; |
import 'package:analyzer/dart/element/element.dart'; |
import 'package:analyzer/file_system/file_system.dart'; |
import 'package:analyzer/file_system/memory_file_system.dart'; |
+import 'package:analyzer/src/dart/ast/token.dart'; |
import 'package:analyzer/src/generated/engine.dart'; |
import 'package:analyzer/src/generated/error.dart'; |
-import 'package:analyzer/src/generated/scanner.dart'; |
import 'package:analyzer/src/generated/source.dart'; |
import 'package:analyzer/src/generated/type_system.dart'; |
import 'package:analyzer/src/task/strong/checker.dart'; |
@@ -25,26 +26,6 @@ import '../../context/mock_sdk.dart'; |
MemoryResourceProvider files; |
bool _checkCalled; |
-initStrongModeTests() { |
- setUp(() { |
- AnalysisEngine.instance.processRequiredPlugins(); |
- files = new MemoryResourceProvider(); |
- _checkCalled = false; |
- }); |
- |
- tearDown(() { |
- // This is a sanity check, in case only addFile is called. |
- expect(_checkCalled, true, reason: 'must call check() method in test case'); |
- files = null; |
- }); |
-} |
- |
-/// Adds a file using [addFile] and calls [check]. |
-void checkFile(String content) { |
- addFile(content); |
- check(); |
-} |
- |
/// Adds a file to check. The file should contain: |
/// |
/// * all expected failures are listed in the source code using comments |
@@ -84,10 +65,8 @@ void check() { |
var context = AnalysisEngine.instance.createAnalysisContext(); |
context.analysisOptions.strongMode = true; |
context.analysisOptions.strongModeHints = true; |
- context.sourceFactory = new SourceFactory([ |
- new DartUriResolver(new MockSdk()), |
- uriResolver |
- ]); |
+ context.sourceFactory = |
+ new SourceFactory([new DartUriResolver(new MockSdk()), uriResolver]); |
// Run the checker on /main.dart. |
Source mainSource = uriResolver.resolveAbsolute(new Uri.file('/main.dart')); |
@@ -120,6 +99,12 @@ void check() { |
} |
} |
+/// Adds a file using [addFile] and calls [check]. |
+void checkFile(String content) { |
+ addFile(content); |
+ check(); |
+} |
+ |
SourceSpanWithContext createSpanHelper( |
LineInfo lineInfo, int start, Source source, String content, |
{int end}) { |
@@ -158,6 +143,20 @@ String errorCodeName(ErrorCode errorCode) { |
} |
} |
+initStrongModeTests() { |
+ setUp(() { |
+ AnalysisEngine.instance.processRequiredPlugins(); |
+ files = new MemoryResourceProvider(); |
+ _checkCalled = false; |
+ }); |
+ |
+ tearDown(() { |
+ // This is a sanity check, in case only addFile is called. |
+ expect(_checkCalled, true, reason: 'must call check() method in test case'); |
+ files = null; |
+ }); |
+} |
+ |
// TODO(jmesserly): can we reuse the same mock SDK as Analyzer tests? |
SourceLocation locationForOffset(LineInfo lineInfo, Uri uri, int offset) { |
var loc = lineInfo.getLocation(offset); |
@@ -180,85 +179,12 @@ List<LibraryElement> reachableLibraries(LibraryElement start) { |
return results; |
} |
-class _TestUriResolver extends ResourceUriResolver { |
- final MemoryResourceProvider provider; |
- _TestUriResolver(provider) |
- : provider = provider, |
- super(provider); |
- |
- @override |
- Source resolveAbsolute(Uri uri, [Uri actualUri]) { |
- if (uri.scheme == 'package') { |
- return (provider.getResource('/packages/' + uri.path) as File) |
- .createSource(uri); |
- } |
- return super.resolveAbsolute(uri, actualUri); |
- } |
-} |
- |
-class _ErrorCollector implements AnalysisErrorListener { |
- List<AnalysisError> errors; |
- final bool hints; |
- |
- _ErrorCollector({this.hints: true}); |
- |
- void onError(AnalysisError error) { |
- // Unless DDC hints are requested, filter them out. |
- var HINT = ErrorSeverity.INFO.ordinal; |
- if (hints || error.errorCode.errorSeverity.ordinal > HINT) { |
- errors.add(error); |
- } |
- } |
-} |
- |
-/// Describes an expected message that should be produced by the checker. |
-class _ErrorExpectation { |
- final int offset; |
- final Level level; |
- final String typeName; |
- |
- _ErrorExpectation(this.offset, this.level, this.typeName); |
- |
- String toString() => |
- '@$offset ${level.toString().toLowerCase()}: [$typeName]'; |
- |
- static _ErrorExpectation parse(int offset, String descriptor) { |
- descriptor = descriptor.trim(); |
- var tokens = descriptor.split(' '); |
- if (tokens.length == 1) return _parse(offset, tokens[0]); |
- expect(tokens.length, 4, reason: 'invalid error descriptor'); |
- expect(tokens[1], "should", reason: 'invalid error descriptor'); |
- expect(tokens[2], "be", reason: 'invalid error descriptor'); |
- if (tokens[0] == "pass") return null; |
- // TODO(leafp) For now, we just use whatever the current expectation is, |
- // eventually we could do more automated reporting here. |
- return _parse(offset, tokens[0]); |
- } |
- |
- static _ErrorExpectation _parse(offset, String descriptor) { |
- var tokens = descriptor.split(':'); |
- expect(tokens.length, 2, reason: 'invalid error descriptor'); |
- var name = tokens[0].toUpperCase(); |
- var typeName = tokens[1]; |
- |
- var level = |
- Level.LEVELS.firstWhere((l) => l.name == name, orElse: () => null); |
- expect(level, isNotNull, |
- reason: 'invalid level in error descriptor: `${tokens[0]}`'); |
- expect(typeName, isNotNull, |
- reason: 'invalid type in error descriptor: ${tokens[1]}'); |
- return new _ErrorExpectation(offset, level, typeName); |
- } |
- |
- AnalysisError _removeMatchingActual(List<AnalysisError> actualErrors) { |
- for (var actual in actualErrors) { |
- if (actual.offset == offset) { |
- actualErrors.remove(actual); |
- return actual; |
- } |
- } |
- return null; |
- } |
+Level _actualErrorLevel(AnalysisError actual) { |
+ return const <ErrorSeverity, Level>{ |
+ ErrorSeverity.ERROR: Level.SEVERE, |
+ ErrorSeverity.WARNING: Level.WARNING, |
+ ErrorSeverity.INFO: Level.INFO |
+ }[actual.errorCode.errorSeverity]; |
} |
void _expectErrors(CompilationUnit unit, List<AnalysisError> actualErrors) { |
@@ -288,12 +214,37 @@ void _expectErrors(CompilationUnit unit, List<AnalysisError> actualErrors) { |
} |
} |
+List<_ErrorExpectation> _findExpectedErrors(Token beginToken) { |
+ var expectedErrors = <_ErrorExpectation>[]; |
+ |
+ // Collect expectations like "severe:STATIC_TYPE_ERROR" from comment tokens. |
+ for (Token t = beginToken; t.type != TokenType.EOF; t = t.next) { |
+ for (CommentToken c = t.precedingComments; c != null; c = c.next) { |
+ if (c.type == TokenType.MULTI_LINE_COMMENT) { |
+ String value = c.lexeme.substring(2, c.lexeme.length - 2); |
+ if (value.contains(':')) { |
+ var offset = c.end; |
+ if (c.next?.type == TokenType.GENERIC_METHOD_TYPE_LIST) { |
+ offset += 2; |
+ } |
+ for (var expectCode in value.split(',')) { |
+ var expected = _ErrorExpectation.parse(offset, expectCode); |
+ if (expected != null) { |
+ expectedErrors.add(expected); |
+ } |
+ } |
+ } |
+ } |
+ } |
+ } |
+ return expectedErrors; |
+} |
+ |
void _reportFailure( |
CompilationUnit unit, |
List<_ErrorExpectation> unreported, |
List<AnalysisError> unexpected, |
Map<_ErrorExpectation, AnalysisError> different) { |
- |
// Get the source code. This reads the data again, but it's safe because |
// all tests use memory file system. |
var sourceCode = unit.element.source.contents.data; |
@@ -339,36 +290,83 @@ void _reportFailure( |
fail('Checker errors do not match expected errors:\n\n$message'); |
} |
-List<_ErrorExpectation> _findExpectedErrors(Token beginToken) { |
- var expectedErrors = <_ErrorExpectation>[]; |
+class _ErrorCollector implements AnalysisErrorListener { |
+ List<AnalysisError> errors; |
+ final bool hints; |
- // Collect expectations like "severe:STATIC_TYPE_ERROR" from comment tokens. |
- for (Token t = beginToken; t.type != TokenType.EOF; t = t.next) { |
- for (CommentToken c = t.precedingComments; c != null; c = c.next) { |
- if (c.type == TokenType.MULTI_LINE_COMMENT) { |
- String value = c.lexeme.substring(2, c.lexeme.length - 2); |
- if (value.contains(':')) { |
- var offset = c.end; |
- if (c.next?.type == TokenType.GENERIC_METHOD_TYPE_LIST) { |
- offset += 2; |
- } |
- for (var expectCode in value.split(',')) { |
- var expected = _ErrorExpectation.parse(offset, expectCode); |
- if (expected != null) { |
- expectedErrors.add(expected); |
- } |
- } |
- } |
+ _ErrorCollector({this.hints: true}); |
+ |
+ void onError(AnalysisError error) { |
+ // Unless DDC hints are requested, filter them out. |
+ var HINT = ErrorSeverity.INFO.ordinal; |
+ if (hints || error.errorCode.errorSeverity.ordinal > HINT) { |
+ errors.add(error); |
+ } |
+ } |
+} |
+ |
+/// Describes an expected message that should be produced by the checker. |
+class _ErrorExpectation { |
+ final int offset; |
+ final Level level; |
+ final String typeName; |
+ |
+ _ErrorExpectation(this.offset, this.level, this.typeName); |
+ |
+ String toString() => |
+ '@$offset ${level.toString().toLowerCase()}: [$typeName]'; |
+ |
+ AnalysisError _removeMatchingActual(List<AnalysisError> actualErrors) { |
+ for (var actual in actualErrors) { |
+ if (actual.offset == offset) { |
+ actualErrors.remove(actual); |
+ return actual; |
} |
} |
+ return null; |
+ } |
+ |
+ static _ErrorExpectation parse(int offset, String descriptor) { |
+ descriptor = descriptor.trim(); |
+ var tokens = descriptor.split(' '); |
+ if (tokens.length == 1) return _parse(offset, tokens[0]); |
+ expect(tokens.length, 4, reason: 'invalid error descriptor'); |
+ expect(tokens[1], "should", reason: 'invalid error descriptor'); |
+ expect(tokens[2], "be", reason: 'invalid error descriptor'); |
+ if (tokens[0] == "pass") return null; |
+ // TODO(leafp) For now, we just use whatever the current expectation is, |
+ // eventually we could do more automated reporting here. |
+ return _parse(offset, tokens[0]); |
+ } |
+ |
+ static _ErrorExpectation _parse(offset, String descriptor) { |
+ var tokens = descriptor.split(':'); |
+ expect(tokens.length, 2, reason: 'invalid error descriptor'); |
+ var name = tokens[0].toUpperCase(); |
+ var typeName = tokens[1]; |
+ |
+ var level = |
+ Level.LEVELS.firstWhere((l) => l.name == name, orElse: () => null); |
+ expect(level, isNotNull, |
+ reason: 'invalid level in error descriptor: `${tokens[0]}`'); |
+ expect(typeName, isNotNull, |
+ reason: 'invalid type in error descriptor: ${tokens[1]}'); |
+ return new _ErrorExpectation(offset, level, typeName); |
} |
- return expectedErrors; |
} |
-Level _actualErrorLevel(AnalysisError actual) { |
- return const <ErrorSeverity, Level>{ |
- ErrorSeverity.ERROR: Level.SEVERE, |
- ErrorSeverity.WARNING: Level.WARNING, |
- ErrorSeverity.INFO: Level.INFO |
- }[actual.errorCode.errorSeverity]; |
+class _TestUriResolver extends ResourceUriResolver { |
+ final MemoryResourceProvider provider; |
+ _TestUriResolver(provider) |
+ : provider = provider, |
+ super(provider); |
+ |
+ @override |
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) { |
+ if (uri.scheme == 'package') { |
+ return (provider.getResource('/packages/' + uri.path) as File) |
+ .createSource(uri); |
+ } |
+ return super.resolveAbsolute(uri, actualUri); |
+ } |
} |