| Index: pkg/analyzer/test/generated/incremental_resolver_test.dart
|
| diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e3605f7dc7a56e161c450759260d5f340caa1146
|
| --- /dev/null
|
| +++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
|
| @@ -0,0 +1,2411 @@
|
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +library analyzer.test.generated.incremental_resolver_test;
|
| +
|
| +import 'package:analyzer/dart/ast/ast.dart';
|
| +import 'package:analyzer/dart/ast/token.dart';
|
| +import 'package:analyzer/dart/element/element.dart';
|
| +import 'package:analyzer/error/error.dart';
|
| +import 'package:analyzer/error/listener.dart';
|
| +import 'package:analyzer/exception/exception.dart';
|
| +import 'package:analyzer/src/context/cache.dart';
|
| +import 'package:analyzer/src/dart/ast/utilities.dart';
|
| +import 'package:analyzer/src/dart/element/element.dart';
|
| +import 'package:analyzer/src/dart/scanner/reader.dart';
|
| +import 'package:analyzer/src/dart/scanner/scanner.dart';
|
| +import 'package:analyzer/src/generated/engine.dart';
|
| +import 'package:analyzer/src/generated/incremental_logger.dart' as logging;
|
| +import 'package:analyzer/src/generated/incremental_resolution_validator.dart';
|
| +import 'package:analyzer/src/generated/incremental_resolver.dart';
|
| +import 'package:analyzer/src/generated/java_engine.dart';
|
| +import 'package:analyzer/src/generated/parser.dart';
|
| +import 'package:analyzer/src/generated/resolver.dart';
|
| +import 'package:analyzer/src/generated/source_io.dart';
|
| +import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
|
| +import 'package:analyzer/src/generated/testing/element_factory.dart';
|
| +import 'package:analyzer/src/generated/utilities_collection.dart';
|
| +import 'package:analyzer/src/task/dart.dart';
|
| +import 'package:analyzer/task/dart.dart';
|
| +import 'package:analyzer/task/model.dart';
|
| +import 'package:test/test.dart';
|
| +import 'package:test_reflective_loader/test_reflective_loader.dart';
|
| +
|
| +import 'analysis_context_factory.dart';
|
| +import 'resolver_test_case.dart';
|
| +import 'test_support.dart';
|
| +
|
| +main() {
|
| + initializeTestEnvironment();
|
| + defineReflectiveSuite(() {
|
| + defineReflectiveTests(IncrementalResolverTest);
|
| + defineReflectiveTests(PoorMansIncrementalResolutionTest);
|
| + defineReflectiveTests(ResolutionContextBuilderTest);
|
| + });
|
| +}
|
| +
|
| +void initializeTestEnvironment() {}
|
| +
|
| +void _assertEqualError(AnalysisError incError, AnalysisError fullError) {
|
| + if (incError.errorCode != fullError.errorCode ||
|
| + incError.source != fullError.source ||
|
| + incError.offset != fullError.offset ||
|
| + incError.length != fullError.length ||
|
| + incError.message != fullError.message) {
|
| + StringBuffer buffer = new StringBuffer();
|
| + buffer.writeln('Found error does not match expected error:');
|
| + if (incError.errorCode == fullError.errorCode) {
|
| + buffer.write(' errorCode = ');
|
| + buffer.write(fullError.errorCode.uniqueName);
|
| + } else {
|
| + buffer.write(' Expected errorCode = ');
|
| + buffer.write(fullError.errorCode.uniqueName);
|
| + buffer.write(' found ');
|
| + buffer.write(incError.errorCode.uniqueName);
|
| + }
|
| + buffer.writeln();
|
| + if (incError.source == fullError.source) {
|
| + buffer.write(' source = ');
|
| + buffer.write(fullError.source);
|
| + } else {
|
| + buffer.write(' Expected source = ');
|
| + buffer.write(fullError.source);
|
| + buffer.write(' found ');
|
| + buffer.write(incError.source);
|
| + }
|
| + buffer.writeln();
|
| + if (incError.offset == fullError.offset) {
|
| + buffer.write(' offset = ');
|
| + buffer.write(fullError.offset);
|
| + } else {
|
| + buffer.write(' Expected offset = ');
|
| + buffer.write(fullError.offset);
|
| + buffer.write(' found ');
|
| + buffer.write(incError.offset);
|
| + }
|
| + buffer.writeln();
|
| + if (incError.length == fullError.length) {
|
| + buffer.write(' length = ');
|
| + buffer.write(fullError.length);
|
| + } else {
|
| + buffer.write(' Expected length = ');
|
| + buffer.write(fullError.length);
|
| + buffer.write(' found ');
|
| + buffer.write(incError.length);
|
| + }
|
| + buffer.writeln();
|
| + if (incError.message == fullError.message) {
|
| + buffer.write(' message = ');
|
| + buffer.write(fullError.message);
|
| + } else {
|
| + buffer.write(' Expected message = ');
|
| + buffer.write(fullError.message);
|
| + buffer.write(' found ');
|
| + buffer.write(incError.message);
|
| + }
|
| + fail(buffer.toString());
|
| + }
|
| +}
|
| +
|
| +void _assertEqualErrors(
|
| + List<AnalysisError> incErrors, List<AnalysisError> fullErrors) {
|
| + expect(incErrors, hasLength(fullErrors.length));
|
| + if (incErrors.isNotEmpty) {
|
| + incErrors.sort((a, b) => a.offset - b.offset);
|
| + }
|
| + if (fullErrors.isNotEmpty) {
|
| + fullErrors.sort((a, b) => a.offset - b.offset);
|
| + }
|
| + int length = incErrors.length;
|
| + for (int i = 0; i < length; i++) {
|
| + AnalysisError incError = incErrors[i];
|
| + AnalysisError fullError = fullErrors[i];
|
| + _assertEqualError(incError, fullError);
|
| + }
|
| +}
|
| +
|
| +void _checkCacheEntries(AnalysisCache cache) {
|
| + Set seen = new Set();
|
| + MapIterator<AnalysisTarget, CacheEntry> it = cache.iterator();
|
| + while (it.moveNext()) {
|
| + AnalysisTarget key = it.key;
|
| + if (cache.get(key) == null) {
|
| + fail("cache corrupted: value of $key changed to null");
|
| + }
|
| + if (!seen.add(key)) {
|
| + fail("cache corrupted: $key appears more than once");
|
| + }
|
| + }
|
| +}
|
| +
|
| +@reflectiveTest
|
| +class IncrementalResolverTest extends ResolverTestCase {
|
| + Source source;
|
| + String code;
|
| + LibraryElement library;
|
| + CompilationUnit unit;
|
| +
|
| + void setUp() {
|
| + super.setUp();
|
| + logging.logger = logging.NULL_LOGGER;
|
| + }
|
| +
|
| + void test_classMemberAccessor_body() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + int get test {
|
| + return 1 + 2;
|
| + }
|
| +}''');
|
| + _resolve(_editString('+', '*'), _isFunctionBody);
|
| + }
|
| +
|
| + void test_computeConstants_offsetChanged() {
|
| + _resolveUnit(r'''
|
| +int f() => 0;
|
| +main() {
|
| + const x1 = f();
|
| + const x2 = f();
|
| + const x3 = f();
|
| + const x4 = f();
|
| + const x5 = f();
|
| + print(x1 + x2 + x3 + x4 + x5 + 1);
|
| +}
|
| +''');
|
| + _resolve(_editString('x1', ' x1'), _isFunctionBody);
|
| + }
|
| +
|
| + void test_constructor_body() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + int f;
|
| + A(int a, int b) {
|
| + f = a + b;
|
| + }
|
| +}''');
|
| + _resolve(_editString('+', '*'), _isFunctionBody);
|
| + }
|
| +
|
| + void test_constructor_label_add() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + A() {
|
| + return 42;
|
| + }
|
| +}
|
| +''');
|
| + _resolve(_editString('return', 'label: return'), _isBlock);
|
| + }
|
| +
|
| + void test_constructor_localVariable_add() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + A() {
|
| + 42;
|
| + }
|
| +}
|
| +''');
|
| + _resolve(_editString('42;', 'var res = 42;'), _isBlock);
|
| + }
|
| +
|
| + void test_function_localFunction_add() {
|
| + _resolveUnit(r'''
|
| +int main() {
|
| + return 0;
|
| +}
|
| +callIt(f) {}
|
| +''');
|
| + _resolve(_editString('return 0;', 'callIt((p) {});'), _isBlock);
|
| + }
|
| +
|
| + void test_functionBody_body() {
|
| + _resolveUnit(r'''
|
| +main(int a, int b) {
|
| + return a + b;
|
| +}''');
|
| + _resolve(_editString('+', '*'), _isFunctionBody);
|
| + }
|
| +
|
| + void test_functionBody_statement() {
|
| + _resolveUnit(r'''
|
| +main(int a, int b) {
|
| + return a + b;
|
| +}''');
|
| + _resolve(_editString('+', '*'), _isStatement);
|
| + }
|
| +
|
| + void test_method_body() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + m(int a, int b) {
|
| + return a + b;
|
| + }
|
| +}''');
|
| + _resolve(_editString('+', '*'), _isFunctionBody);
|
| + }
|
| +
|
| + void test_method_label_add() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + int m(int a, int b) {
|
| + return a + b;
|
| + }
|
| +}
|
| +''');
|
| + _resolve(_editString('return', 'label: return'), _isBlock);
|
| + }
|
| +
|
| + void test_method_localFunction_add() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + int m() {
|
| + return 0;
|
| + }
|
| +}
|
| +callIt(f) {}
|
| +''');
|
| + _resolve(_editString('return 0;', 'callIt((p) {});'), _isBlock);
|
| + }
|
| +
|
| + void test_method_localVariable_add() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + int m(int a, int b) {
|
| + return a + b;
|
| + }
|
| +}
|
| +''');
|
| + _resolve(
|
| + _editString(
|
| + ' return a + b;',
|
| + r'''
|
| + int res = a + b;
|
| + return res;
|
| +'''),
|
| + _isBlock);
|
| + }
|
| +
|
| + void test_superInvocation() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + foo(p) {}
|
| +}
|
| +class B extends A {
|
| + bar() {
|
| + super.foo(1 + 2);
|
| + }
|
| +}''');
|
| + _resolve(_editString('+', '*'), _isFunctionBody);
|
| + }
|
| +
|
| + void test_topLevelAccessor_body() {
|
| + _resolveUnit(r'''
|
| +int get test {
|
| + return 1 + 2;
|
| +}''');
|
| + _resolve(_editString('+', '*'), _isFunctionBody);
|
| + }
|
| +
|
| + void test_topLevelFunction_label_add() {
|
| + _resolveUnit(r'''
|
| +int main(int a, int b) {
|
| + return a + b;
|
| +}
|
| +''');
|
| + _resolve(_editString(' return', 'label: return a + b;'), _isBlock);
|
| + }
|
| +
|
| + void test_topLevelFunction_label_remove() {
|
| + _resolveUnit(r'''
|
| +int main(int a, int b) {
|
| + label: return a + b;
|
| +}
|
| +''');
|
| + _resolve(_editString('label: ', ''), _isBlock);
|
| + }
|
| +
|
| + void test_topLevelFunction_localVariable_add() {
|
| + _resolveUnit(r'''
|
| +int main(int a, int b) {
|
| + return a + b;
|
| +}
|
| +''');
|
| + _resolve(
|
| + _editString(
|
| + ' return a + b;',
|
| + r'''
|
| + int res = a + b;
|
| + return res;
|
| +'''),
|
| + _isBlock);
|
| + }
|
| +
|
| + void test_topLevelFunction_localVariable_remove() {
|
| + _resolveUnit(r'''
|
| +int main(int a, int b) {
|
| + int res = a * b;
|
| + return a + b;
|
| +}
|
| +''');
|
| + _resolve(_editString('int res = a * b;', ''), _isBlock);
|
| + }
|
| +
|
| + void test_updateElementOffset() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + int am(String ap) {
|
| + int av = 1;
|
| + return av;
|
| + }
|
| +}
|
| +main(int a, int b) {
|
| + return a + b;
|
| +}
|
| +class B {
|
| + int bm(String bp) {
|
| + int bv = 1;
|
| + return bv;
|
| + }
|
| +}
|
| +''');
|
| + _resolve(_editString('+', ' + '), _isStatement);
|
| + }
|
| +
|
| + _Edit _editString(String search, String replacement, [int length]) {
|
| + int offset = code.indexOf(search);
|
| + expect(offset, isNot(-1));
|
| + if (length == null) {
|
| + length = search.length;
|
| + }
|
| + return new _Edit(offset, length, replacement);
|
| + }
|
| +
|
| + /**
|
| + * Applies [edit] to [code], find the [AstNode] specified by [predicate]
|
| + * and incrementally resolves it.
|
| + *
|
| + * Then resolves the new code from scratch and validates that results of
|
| + * the incremental resolution and non-incremental resolutions are the same.
|
| + */
|
| + void _resolve(_Edit edit, Predicate<AstNode> predicate) {
|
| + int offset = edit.offset;
|
| + // parse "newCode"
|
| + String newCode = code.substring(0, offset) +
|
| + edit.replacement +
|
| + code.substring(offset + edit.length);
|
| + CompilationUnit newUnit = _parseUnit(newCode);
|
| + AnalysisCache cache = analysisContext2.analysisCache;
|
| + _checkCacheEntries(cache);
|
| +
|
| + // replace the node
|
| + AstNode oldNode = _findNodeAt(unit, offset, predicate);
|
| + AstNode newNode = _findNodeAt(newUnit, offset, predicate);
|
| + {
|
| + bool success = NodeReplacer.replace(oldNode, newNode);
|
| + expect(success, isTrue);
|
| + }
|
| + // update tokens
|
| + {
|
| + int delta = edit.replacement.length - edit.length;
|
| + _shiftTokens(unit.beginToken, offset, delta);
|
| + Token oldBeginToken = oldNode.beginToken;
|
| + Token oldEndTokenNext = oldNode.endToken.next;
|
| + oldBeginToken.previous.setNext(newNode.beginToken);
|
| + newNode.endToken.setNext(oldEndTokenNext);
|
| + }
|
| + // do incremental resolution
|
| + int updateOffset = edit.offset;
|
| + int updateEndOld = updateOffset + edit.length;
|
| + int updateOldNew = updateOffset + edit.replacement.length;
|
| + IncrementalResolver resolver;
|
| + LibrarySpecificUnit lsu = new LibrarySpecificUnit(source, source);
|
| + resolver = new IncrementalResolver(cache, cache.get(source), cache.get(lsu),
|
| + unit.element, updateOffset, updateEndOld, updateOldNew);
|
| +
|
| + BlockFunctionBody body = newNode.getAncestor((n) => n is BlockFunctionBody);
|
| + expect(body, isNotNull);
|
| +
|
| + resolver.resolve(body);
|
| + _checkCacheEntries(cache);
|
| +
|
| + List<AnalysisError> newErrors = analysisContext.computeErrors(source);
|
| + // resolve "newCode" from scratch
|
| + CompilationUnit fullNewUnit;
|
| + {
|
| + source = addSource(newCode);
|
| + _runTasks();
|
| + LibraryElement library = resolve2(source);
|
| + fullNewUnit = resolveCompilationUnit(source, library);
|
| + }
|
| + _checkCacheEntries(cache);
|
| +
|
| + assertSameResolution(unit, fullNewUnit);
|
| + // errors
|
| + List<AnalysisError> newFullErrors =
|
| + analysisContext.getErrors(source).errors;
|
| + _assertEqualErrors(newErrors, newFullErrors);
|
| + // prepare for the next cycle
|
| + code = newCode;
|
| + }
|
| +
|
| + void _resolveUnit(String code) {
|
| + this.code = code;
|
| + source = addSource(code);
|
| + library = resolve2(source);
|
| + unit = resolveCompilationUnit(source, library);
|
| + _runTasks();
|
| + _checkCacheEntries(analysisContext2.analysisCache);
|
| + }
|
| +
|
| + void _runTasks() {
|
| + AnalysisResult result = analysisContext.performAnalysisTask();
|
| + while (result.changeNotices != null) {
|
| + result = analysisContext.performAnalysisTask();
|
| + }
|
| + }
|
| +
|
| + static AstNode _findNodeAt(
|
| + CompilationUnit oldUnit, int offset, Predicate<AstNode> predicate) {
|
| + NodeLocator locator = new NodeLocator(offset);
|
| + AstNode node = locator.searchWithin(oldUnit);
|
| + return node.getAncestor(predicate);
|
| + }
|
| +
|
| + static bool _isBlock(AstNode node) => node is Block;
|
| +
|
| + static bool _isFunctionBody(AstNode node) => node is FunctionBody;
|
| +
|
| + static bool _isStatement(AstNode node) => node is Statement;
|
| +
|
| + static CompilationUnit _parseUnit(String code) {
|
| + var errorListener = new BooleanErrorListener();
|
| + var reader = new CharSequenceReader(code);
|
| + var scanner = new Scanner(null, reader, errorListener);
|
| + var token = scanner.tokenize();
|
| + var parser = new Parser(null, errorListener);
|
| + return parser.parseCompilationUnit(token);
|
| + }
|
| +
|
| + static void _shiftTokens(Token token, int afterOffset, int delta) {
|
| + while (true) {
|
| + if (token.offset > afterOffset) {
|
| + token.applyDelta(delta);
|
| + }
|
| + if (token.type == TokenType.EOF) {
|
| + break;
|
| + }
|
| + token = token.next;
|
| + }
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * The test for [poorMansIncrementalResolution] function and its integration
|
| + * into [AnalysisContext].
|
| + */
|
| +@reflectiveTest
|
| +class PoorMansIncrementalResolutionTest extends ResolverTestCase {
|
| + final _TestLogger logger = new _TestLogger();
|
| +
|
| + Source source;
|
| + String code;
|
| + LibraryElement oldLibrary;
|
| + CompilationUnit oldUnit;
|
| + CompilationUnitElement oldUnitElement;
|
| +
|
| + @override
|
| + void setUp() {
|
| + super.setUp();
|
| + _resetWithIncremental(true);
|
| + }
|
| +
|
| + void test_computeConstants() {
|
| + _resolveUnit(r'''
|
| +int f() => 0;
|
| +main() {
|
| + const x = f();
|
| + print(x + 1);
|
| +}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +int f() => 0;
|
| +main() {
|
| + const x = f();
|
| + print(x + 2);
|
| +}
|
| +''',
|
| + expectCachePostConstantsValid: false);
|
| + }
|
| +
|
| + void test_dartDoc_beforeField() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + /**
|
| + * A field [field] of type [int] in class [A].
|
| + */
|
| + int field;
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +class A {
|
| + /**
|
| + * A field [field] of the type [int] in the class [A].
|
| + * Updated, with a reference to the [String] type.
|
| + */
|
| + int field;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_dartDoc_beforeTopLevelVariable() {
|
| + _resolveUnit(r'''
|
| +/**
|
| + * Variables [V1] and [V2] of type [int].
|
| + */
|
| +int V1, V2;
|
| +''');
|
| + _updateAndValidate(r'''
|
| +/**
|
| + * Variables [V1] and [V2] of type [int].
|
| + * Updated, with a reference to the [String] type.
|
| + */
|
| +int V1, V2;
|
| +''');
|
| + }
|
| +
|
| + void test_dartDoc_clumsy_addReference() {
|
| + _resolveUnit(r'''
|
| +/**
|
| + * aaa bbbb
|
| + */
|
| +main() {
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +/**
|
| + * aaa [main] bbbb
|
| + */
|
| +main() {
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_dartDoc_clumsy_removeReference() {
|
| + _resolveUnit(r'''
|
| +/**
|
| + * aaa [main] bbbb
|
| + */
|
| +main() {
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +/**
|
| + * aaa bbbb
|
| + */
|
| +main() {
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_dartDoc_clumsy_updateText_beforeKeywordToken() {
|
| + _resolveUnit(r'''
|
| +/**
|
| + * A comment with the [int] type reference.
|
| + */
|
| +class A {}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +/**
|
| + * A comment with the [int] type reference.
|
| + * Plus reference to [A] itself.
|
| + */
|
| +class A {}
|
| +''');
|
| + }
|
| +
|
| + void test_dartDoc_clumsy_updateText_insert() {
|
| + _resolveUnit(r'''
|
| +/**
|
| + * A function [main] with a parameter [p] of type [int].
|
| + */
|
| +main(int p) {
|
| + unresolvedFunctionProblem();
|
| +}
|
| +/**
|
| + * Other comment with [int] reference.
|
| + */
|
| +foo() {}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +/**
|
| + * A function [main] with a parameter [p] of type [int].
|
| + * Inserted text with [String] reference.
|
| + */
|
| +main(int p) {
|
| + unresolvedFunctionProblem();
|
| +}
|
| +/**
|
| + * Other comment with [int] reference.
|
| + */
|
| +foo() {}
|
| +''');
|
| + }
|
| +
|
| + void test_dartDoc_clumsy_updateText_remove() {
|
| + _resolveUnit(r'''
|
| +/**
|
| + * A function [main] with a parameter [p] of type [int].
|
| + * Some text with [String] reference to remove.
|
| + */
|
| +main(int p) {
|
| +}
|
| +/**
|
| + * Other comment with [int] reference.
|
| + */
|
| +foo() {}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +/**
|
| + * A function [main] with a parameter [p] of type [int].
|
| + */
|
| +main(int p) {
|
| +}
|
| +/**
|
| + * Other comment with [int] reference.
|
| + */
|
| +foo() {}
|
| +''');
|
| + }
|
| +
|
| + void test_dartDoc_elegant_addReference() {
|
| + _resolveUnit(r'''
|
| +/// aaa bbb
|
| +main() {
|
| + return 1;
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +/// aaa [main] bbb
|
| +/// ccc [int] ddd
|
| +main() {
|
| + return 1;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_dartDoc_elegant_removeReference() {
|
| + _resolveUnit(r'''
|
| +/// aaa [main] bbb
|
| +/// ccc [int] ddd
|
| +main() {
|
| + return 1;
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +/// aaa bbb
|
| +main() {
|
| + return 1;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_dartDoc_elegant_updateText_insertToken() {
|
| + _resolveUnit(r'''
|
| +/// A
|
| +/// [int]
|
| +class Test {
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +/// A
|
| +///
|
| +/// [int]
|
| +class Test {
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_dartDoc_elegant_updateText_removeToken() {
|
| + _resolveUnit(r'''
|
| +/// A
|
| +///
|
| +/// [int]
|
| +class Test {
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +/// A
|
| +/// [int]
|
| +class Test {
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_endOfLineComment_add_beforeKeywordToken() {
|
| + _resolveUnit(r'''
|
| +main() {
|
| + var v = 42;
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +main() {
|
| + // some comment
|
| + var v = 42;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_endOfLineComment_add_beforeStringToken() {
|
| + _resolveUnit(r'''
|
| +main() {
|
| + print(0);
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +main() {
|
| + // some comment
|
| + print(0);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_endOfLineComment_edit() {
|
| + _resolveUnit(r'''
|
| +main() {
|
| + // some comment
|
| + print(0);
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +main() {
|
| + // edited comment text
|
| + print(0);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_endOfLineComment_outBody_add() {
|
| + _resolveUnit(r'''
|
| +main() {
|
| + Object x;
|
| + x.foo();
|
| +}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +// 000
|
| +main() {
|
| + Object x;
|
| + x.foo();
|
| +}
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_endOfLineComment_outBody_remove() {
|
| + _resolveUnit(r'''
|
| +// 000
|
| +main() {
|
| + Object x;
|
| + x.foo();
|
| +}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +main() {
|
| + Object x;
|
| + x.foo();
|
| +}
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_endOfLineComment_outBody_update() {
|
| + _resolveUnit(r'''
|
| +// 000
|
| +main() {
|
| + Object x;
|
| + x.foo();
|
| +}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +// 10
|
| +main() {
|
| + Object x;
|
| + x.foo();
|
| +}
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_endOfLineComment_remove() {
|
| + _resolveUnit(r'''
|
| +main() {
|
| + // some comment
|
| + print(0);
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +main() {
|
| + print(0);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_endOfLineComment_toDartDoc() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + // text
|
| + main() {
|
| + print(42);
|
| + }
|
| +}''');
|
| + _updateAndValidate(
|
| + r'''
|
| +class A {
|
| + /// text
|
| + main() {
|
| + print(42);
|
| + }
|
| +}''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_constConstructor_initializer() {
|
| + _resolveUnit(r'''
|
| +class C {
|
| + final int x;
|
| + const C(this.x);
|
| + const C.foo() : x = 0;
|
| +}
|
| +main() {
|
| + const {const C(0): 0, const C.foo(): 1};
|
| +}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +class C {
|
| + final int x;
|
| + const C(this.x);
|
| + const C.foo() : x = 1;
|
| +}
|
| +main() {
|
| + const {const C(0): 0, const C.foo(): 1};
|
| +}
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_constructor_initializer_damage() {
|
| + _resolveUnit(r'''
|
| +class Problem {
|
| + final Map location;
|
| + final String message;
|
| +
|
| + Problem(Map json)
|
| + : location = json["location"],
|
| + message = json["message"];
|
| +}''');
|
| + _updateAndValidate(
|
| + r'''
|
| +class Problem {
|
| + final Map location;
|
| + final String message;
|
| +
|
| + Problem(Map json)
|
| + : location = json["location],
|
| + message = json["message"];
|
| +}''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_constructor_initializer_remove() {
|
| + _resolveUnit(r'''
|
| +class Problem {
|
| + final String severity;
|
| + final Map location;
|
| + final String message;
|
| +
|
| + Problem(Map json)
|
| + : severity = json["severity"],
|
| + location = json["location"],
|
| + message = json["message"];
|
| +}''');
|
| + _updateAndValidate(
|
| + r'''
|
| +class Problem {
|
| + final String severity;
|
| + final Map location;
|
| + final String message;
|
| +
|
| + Problem(Map json)
|
| + : severity = json["severity"],
|
| + message = json["message"];
|
| +}''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_endOfLineComment_localFunction_inTopLevelVariable() {
|
| + _resolveUnit(r'''
|
| +typedef int Binary(one, two, three);
|
| +
|
| +int Global = f((a, b, c) {
|
| + return 0; // Some comment
|
| +});
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +typedef int Binary(one, two, three);
|
| +
|
| +int Global = f((a, b, c) {
|
| + return 0; // Some comment
|
| +});
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_expressionBody() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + final f = (() => 1)();
|
| +}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +class A {
|
| + final f = (() => 2)();
|
| +}
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_expressionBody2() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + int m() => 10 * 10;
|
| +}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +class A {
|
| + int m() => 10 * 100;
|
| +}
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_inBody_addAsync() {
|
| + _resolveUnit(r'''
|
| +class C {
|
| + test() {}
|
| +}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +class C {
|
| + test() async {}
|
| +}
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_inBody_async_addStar() {
|
| + _resolveUnit(r'''
|
| +import 'dart:async';
|
| +class C {
|
| + Stream test() async {}
|
| +}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +import 'dart:async';
|
| +class C {
|
| + Stream test() async* {}
|
| +}
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_inBody_async_removeStar() {
|
| + _resolveUnit(r'''
|
| +import 'dart:async';
|
| +class C {
|
| + Stream test() async* {}
|
| +}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +import 'dart:async';
|
| +class C {
|
| + Stream test() async {}
|
| +}
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_inBody_functionExpression() {
|
| + _resolveUnit(r'''
|
| +class C extends D {
|
| + static final f = () {
|
| + var x = 0;
|
| + }();
|
| +}
|
| +
|
| +class D {}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +class C extends D {
|
| + static final f = () {
|
| + var x = 01;
|
| + }();
|
| +}
|
| +
|
| +class D {}
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_inBody_removeAsync() {
|
| + _resolveUnit(r'''
|
| +class C {
|
| + test() async {}
|
| +}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +class C {
|
| + test() {}
|
| +}
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_inBody_sync_addStar() {
|
| + _resolveUnit(r'''
|
| +class C {
|
| + test() {}
|
| +}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +class C {
|
| + test() sync* {}
|
| +}
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_topLevelFunction_name() {
|
| + _resolveUnit(r'''
|
| +a() {}
|
| +b() {}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +a() {}
|
| +bb() {}
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_unbalancedCurlyBrackets_inNew() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + aaa() {
|
| + if (true) {
|
| + 1;
|
| + }
|
| + }
|
| +
|
| + bbb() {
|
| + print(0123456789);
|
| + }
|
| +}''');
|
| + _updateAndValidate(
|
| + r'''
|
| +class A {
|
| + aaa() {
|
| + 1;
|
| + }
|
| + }
|
| +
|
| + bbb() {
|
| + print(0123456789);
|
| + }
|
| +}''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_unbalancedCurlyBrackets_inOld() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + aaa() {
|
| + 1;
|
| + }
|
| + }
|
| +
|
| + bbb() {
|
| + print(0123456789);
|
| + }
|
| +}''');
|
| + _updateAndValidate(
|
| + r'''
|
| +class A {
|
| + aaa() {
|
| + if (true) {
|
| + 1;
|
| + }
|
| + }
|
| +
|
| + bbb() {
|
| + print(0123456789);
|
| + }
|
| +}''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_wholeConstructor() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + A(int a) {
|
| + print(a);
|
| + }
|
| +}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +class A {
|
| + A(int b) {
|
| + print(b);
|
| + }
|
| +}
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_wholeConstructor_addInitializer() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + int field;
|
| + A();
|
| +}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +class A {
|
| + int field;
|
| + A() : field = 5;
|
| +}
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_wholeFunction() {
|
| + _resolveUnit(r'''
|
| +foo() {}
|
| +main(int a) {
|
| + print(a);
|
| +}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +foo() {}
|
| +main(int b) {
|
| + print(b);
|
| +}
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_false_wholeMethod() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + main(int a) {
|
| + print(a);
|
| + }
|
| +}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +class A {
|
| + main(int b) {
|
| + print(b);
|
| + }
|
| +}
|
| +''',
|
| + expectedSuccess: false);
|
| + }
|
| +
|
| + void test_fieldClassField_propagatedType() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + static const A b = const B();
|
| + const A();
|
| +}
|
| +
|
| +class B extends A {
|
| + const B();
|
| +}
|
| +
|
| +main() {
|
| + print(12);
|
| + A.b;
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +class A {
|
| + static const A b = const B();
|
| + const A();
|
| +}
|
| +
|
| +class B extends A {
|
| + const B();
|
| +}
|
| +
|
| +main() {
|
| + print(123);
|
| + A.b;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_hasElementAfter_defaultParameter() {
|
| + _resolveUnit(r'''
|
| +main() {
|
| + print(1);
|
| +}
|
| +otherFunction([p = 0]) {}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +main() {
|
| + print(2);
|
| +}
|
| +otherFunction([p = 0]) {}
|
| +''');
|
| + }
|
| +
|
| + void test_inBody_expression() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + m() {
|
| + print(1);
|
| + }
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +class A {
|
| + m() {
|
| + print(2 + 3);
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_inBody_insertStatement() {
|
| + _resolveUnit(r'''
|
| +main() {
|
| + print(1);
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +main() {
|
| + print(0);
|
| + print(1);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_inBody_tokenToNode() {
|
| + _resolveUnit(r'''
|
| +main() {
|
| + var v = 42;
|
| + print(v);
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +main() {
|
| + int v = 42;
|
| + print(v);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_multiple_emptyLine() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + m() {
|
| + return true;
|
| + }
|
| +}''');
|
| + for (int i = 0; i < 6; i++) {
|
| + if (i.isEven) {
|
| + _updateAndValidate(
|
| + r'''
|
| +class A {
|
| + m() {
|
| + return true;
|
| +
|
| + }
|
| +}''',
|
| + compareWithFull: false);
|
| + } else {
|
| + _updateAndValidate(
|
| + r'''
|
| +class A {
|
| + m() {
|
| + return true;
|
| + }
|
| +}''',
|
| + compareWithFull: false);
|
| + }
|
| + }
|
| + }
|
| +
|
| + void test_multiple_expression() {
|
| + _resolveUnit(r'''
|
| +main() {
|
| + print(1);
|
| +}''');
|
| + for (int i = 0; i < 6; i++) {
|
| + if (i.isEven) {
|
| + _updateAndValidate(
|
| + r'''
|
| +main() {
|
| + print(12);
|
| +}''',
|
| + compareWithFull: false);
|
| + } else {
|
| + _updateAndValidate(
|
| + r'''
|
| +main() {
|
| + print(1);
|
| +}''',
|
| + compareWithFull: false);
|
| + }
|
| + }
|
| + }
|
| +
|
| + void test_strongMode_typeComments_insertWhitespace() {
|
| + _resolveUnit(r'''
|
| +import 'dart:async';
|
| +
|
| +void fadeIn(int milliseconds) {
|
| + Future<String> f;
|
| + f.then/*<String>*/((e) {print("hello");});
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +import 'dart:async';
|
| +
|
| +void fadeIn(int milliseconds) {
|
| + Future<String> f;
|
| + f.then/*<String>*/((e) {print("hello") ;});
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_true_emptyLine_betweenClassMembers_insert() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + a() {}
|
| + b() {}
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +class A {
|
| + a() {}
|
| +
|
| + b() {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_true_emptyLine_betweenClassMembers_insert_beforeComment() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + a() {}
|
| + /// BBB
|
| + b() {}
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +class A {
|
| + a() {}
|
| +
|
| + /// BBB
|
| + b() {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_true_emptyLine_betweenClassMembers_remove() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + a() {}
|
| +
|
| + b() {}
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +class A {
|
| + a() {}
|
| + b() {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_true_emptyLine_betweenClassMembers_remove_beforeComment() {
|
| + _resolveUnit(r'''
|
| +class A {
|
| + a() {}
|
| +
|
| + /// BBB
|
| + b() {}
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +class A {
|
| + a() {}
|
| + /// BBB
|
| + b() {}
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_true_emptyLine_betweenUnitMembers_insert() {
|
| + _resolveUnit(r'''
|
| +a() {}
|
| +b() {}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +a() {}
|
| +
|
| +b() {}
|
| +''');
|
| + }
|
| +
|
| + void test_true_emptyLine_betweenUnitMembers_insert_beforeComment() {
|
| + _resolveUnit(r'''
|
| +a() {}
|
| +
|
| +// BBB
|
| +b() {}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +a() {}
|
| +
|
| +
|
| +// BBB
|
| +b() {}
|
| +''');
|
| + }
|
| +
|
| + void test_true_emptyLine_betweenUnitMembers_remove() {
|
| + _resolveUnit(r'''
|
| +a() {
|
| + print(1)
|
| +}
|
| +
|
| +b() {
|
| + foo(42);
|
| +}
|
| +foo(String p) {}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +a() {
|
| + print(1)
|
| +}
|
| +b() {
|
| + foo(42);
|
| +}
|
| +foo(String p) {}
|
| +''');
|
| + }
|
| +
|
| + void test_true_emptyLine_betweenUnitMembers_remove_beforeComment() {
|
| + _resolveUnit(r'''
|
| +a() {}
|
| +
|
| +// BBB
|
| +b() {}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +a() {}
|
| +// BBB
|
| +b() {}
|
| +''');
|
| + }
|
| +
|
| + void test_true_todoHint() {
|
| + _resolveUnit(r'''
|
| +main() {
|
| + print(1);
|
| +}
|
| +foo() {
|
| + // TODO
|
| +}
|
| +''');
|
| + List<AnalysisError> oldErrors = analysisContext.computeErrors(source);
|
| + _updateAndValidate(r'''
|
| +main() {
|
| + print(2);
|
| +}
|
| +foo() {
|
| + // TODO
|
| +}
|
| +''');
|
| + List<AnalysisError> newErrors = analysisContext.computeErrors(source);
|
| + _assertEqualErrors(newErrors, oldErrors);
|
| + }
|
| +
|
| + void test_unusedHint_add_wasUsedOnlyInPart() {
|
| + Source partSource = addNamedSource(
|
| + '/my_unit.dart',
|
| + r'''
|
| +part of lib;
|
| +
|
| +f(A a) {
|
| + a._foo();
|
| +}
|
| +''');
|
| + _resolveUnit(r'''
|
| +library lib;
|
| +part 'my_unit.dart';
|
| +class A {
|
| + _foo() {
|
| + print(1);
|
| + }
|
| +}
|
| +''');
|
| + _runTasks();
|
| + // perform incremental resolution
|
| + _resetWithIncremental(true);
|
| + analysisContext2.setContents(
|
| + partSource,
|
| + r'''
|
| +part of lib;
|
| +
|
| +f(A a) {
|
| +// a._foo();
|
| +}
|
| +''');
|
| + // no hints right now, because we delay hints computing
|
| + {
|
| + List<AnalysisError> errors = analysisContext.getErrors(source).errors;
|
| + expect(errors, isEmpty);
|
| + }
|
| + // a new hint should be added
|
| + List<AnalysisError> errors = analysisContext.computeErrors(source);
|
| + expect(errors, hasLength(1));
|
| + expect(errors[0].errorCode.type, ErrorType.HINT);
|
| + // the same hint should be reported using a ChangeNotice
|
| + bool noticeFound = false;
|
| + AnalysisResult result = analysisContext2.performAnalysisTask();
|
| + for (ChangeNotice notice in result.changeNotices) {
|
| + if (notice.source == source) {
|
| + expect(notice.errors, contains(errors[0]));
|
| + noticeFound = true;
|
| + }
|
| + }
|
| + expect(noticeFound, isTrue);
|
| + }
|
| +
|
| + void test_unusedHint_false_stillUsedInPart() {
|
| + addNamedSource(
|
| + '/my_unit.dart',
|
| + r'''
|
| +part of lib;
|
| +
|
| +f(A a) {
|
| + a._foo();
|
| +}
|
| +''');
|
| + _resolveUnit(r'''
|
| +library lib;
|
| +part 'my_unit.dart';
|
| +class A {
|
| + _foo() {
|
| + print(1);
|
| + }
|
| +}
|
| +''');
|
| + // perform incremental resolution
|
| + _resetWithIncremental(true);
|
| + analysisContext2.setContents(
|
| + source,
|
| + r'''
|
| +library lib;
|
| +part 'my_unit.dart';
|
| +class A {
|
| + _foo() {
|
| + print(12);
|
| + }
|
| +}
|
| +''');
|
| + // no hints
|
| + List<AnalysisError> errors = analysisContext.getErrors(source).errors;
|
| + expect(errors, isEmpty);
|
| + }
|
| +
|
| + void test_updateConstantInitializer() {
|
| + _resolveUnit(r'''
|
| +main() {
|
| + const v = const [Unknown];
|
| +}
|
| +''');
|
| + _updateAndValidate(
|
| + r'''
|
| +main() {
|
| + const v = const [Unknown];
|
| +}
|
| +''',
|
| + expectCachePostConstantsValid: false);
|
| + }
|
| +
|
| + void test_updateErrors_addNew_hint1() {
|
| + _resolveUnit(r'''
|
| +int main() {
|
| + return 42;
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +int main() {
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_updateErrors_addNew_hint2() {
|
| + _resolveUnit(r'''
|
| +main() {
|
| + int v = 0;
|
| + print(v);
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +main() {
|
| + int v = 0;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_updateErrors_addNew_parse() {
|
| + _resolveUnit(r'''
|
| +main() {
|
| + print(42);
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +main() {
|
| + print(42)
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_updateErrors_addNew_resolve() {
|
| + _resolveUnit(r'''
|
| +main() {
|
| + foo();
|
| +}
|
| +foo() {}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +main() {
|
| + bar();
|
| +}
|
| +foo() {}
|
| +''');
|
| + }
|
| +
|
| + void test_updateErrors_addNew_resolve2() {
|
| + _resolveUnit(r'''
|
| +// this comment is important to reproduce the problem
|
| +main() {
|
| + int vvv = 42;
|
| + print(vvv);
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +// this comment is important to reproduce the problem
|
| +main() {
|
| + int vvv = 42;
|
| + print(vvv2);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_updateErrors_addNew_scan() {
|
| + _resolveUnit(r'''
|
| +main() {
|
| + 1;
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +main() {
|
| + 1e;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_updateErrors_addNew_verify() {
|
| + _resolveUnit(r'''
|
| +main() {
|
| + foo(0);
|
| +}
|
| +foo(int p) {}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +main() {
|
| + foo('abc');
|
| +}
|
| +foo(int p) {}
|
| +''');
|
| + }
|
| +
|
| + void test_updateErrors_invalidVerifyErrors() {
|
| + _resolveUnit(r'''
|
| +main() {
|
| + foo('aaa');
|
| +}
|
| +main2() {
|
| + foo('bbb');
|
| +}
|
| +foo(int p) {}
|
| +''');
|
| + // Complete analysis, e.g. compute VERIFY_ERRORS.
|
| + _runTasks();
|
| + // Invalidate VERIFY_ERRORS.
|
| + AnalysisCache cache = analysisContext2.analysisCache;
|
| + LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
|
| + CacheEntry cacheEntry = cache.get(target);
|
| + expect(cacheEntry.getValue(VERIFY_ERRORS), hasLength(2));
|
| + cacheEntry.setState(VERIFY_ERRORS, CacheState.INVALID);
|
| + // Perform incremental resolution.
|
| + _resetWithIncremental(true);
|
| + analysisContext2.setContents(
|
| + source,
|
| + r'''
|
| +main() {
|
| + foo(0);
|
| +}
|
| +main2() {
|
| + foo('bbb');
|
| +}
|
| +foo(int p) {}
|
| +''');
|
| + // VERIFY_ERRORS is still invalid.
|
| + expect(cacheEntry.getState(VERIFY_ERRORS), CacheState.INVALID);
|
| + // Continue analysis - run tasks, so recompute VERIFY_ERRORS.
|
| + _runTasks();
|
| + expect(cacheEntry.getState(VERIFY_ERRORS), CacheState.VALID);
|
| + expect(cacheEntry.getValue(VERIFY_ERRORS), hasLength(1));
|
| + }
|
| +
|
| + void test_updateErrors_removeExisting_hint() {
|
| + _resolveUnit(r'''
|
| +int main() {
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +int main() {
|
| + return 42;
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_updateErrors_removeExisting_verify() {
|
| + _resolveUnit(r'''
|
| +f1() {
|
| + print(1)
|
| +}
|
| +f2() {
|
| + print(22)
|
| +}
|
| +f3() {
|
| + print(333)
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +f1() {
|
| + print(1)
|
| +}
|
| +f2() {
|
| + print(22);
|
| +}
|
| +f3() {
|
| + print(333)
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_updateErrors_shiftExisting() {
|
| + _resolveUnit(r'''
|
| +f1() {
|
| + print(1)
|
| +}
|
| +f2() {
|
| + print(2);
|
| +}
|
| +f3() {
|
| + print(333)
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +f1() {
|
| + print(1)
|
| +}
|
| +f2() {
|
| + print(22);
|
| +}
|
| +f3() {
|
| + print(333)
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_updateFunctionToForLoop() {
|
| + _resolveUnit(r'''
|
| +class PlayDrag {
|
| + final List<num> times = new List<num>();
|
| +
|
| + PlayDrag.start() {}
|
| +
|
| + void update(num pos) {
|
| + fo (int i = times.length - 2; i >= 0; i--) {}
|
| + }
|
| +}
|
| +''');
|
| +
|
| + _updateAndValidate(
|
| + r'''
|
| +class PlayDrag {
|
| + final List<num> times = new List<num>();
|
| +
|
| + PlayDrag.start() {}
|
| +
|
| + void update(num pos) {
|
| + for (int i = times.length - 2; i >= 0; i--) {}
|
| + }
|
| +}
|
| +''',
|
| + expectLibraryUnchanged: false);
|
| + }
|
| +
|
| + void test_visibleRange() {
|
| + _resolveUnit(r'''
|
| +class Test {
|
| + method1(p1) {
|
| + var v1;
|
| + f1() {}
|
| + return 1;
|
| + }
|
| + method2(p2) {
|
| + var v2;
|
| + f2() {}
|
| + return 2;
|
| + }
|
| + method3(p3) {
|
| + var v3;
|
| + f3() {}
|
| + return 3;
|
| + }
|
| +}
|
| +''');
|
| + _updateAndValidate(r'''
|
| +class Test {
|
| + method1(p1) {
|
| + var v1;
|
| + f1() {}
|
| + return 1;
|
| + }
|
| + method2(p2) {
|
| + var v2;
|
| + f2() {}
|
| + return 2222;
|
| + }
|
| + method3(p3) {
|
| + var v3;
|
| + f3() {}
|
| + return 3;
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_whitespace_getElementAt() {
|
| + _resolveUnit(r'''
|
| +class A {}
|
| +class B extends A {}
|
| +''');
|
| + {
|
| + ClassElement typeA = oldUnitElement.getType('A');
|
| + expect(oldUnitElement.getElementAt(typeA.nameOffset), typeA);
|
| + }
|
| + {
|
| + ClassElement typeB = oldUnitElement.getType('B');
|
| + expect(oldUnitElement.getElementAt(typeB.nameOffset), typeB);
|
| + }
|
| + _updateAndValidate(r'''
|
| +class A {}
|
| +
|
| +class B extends A {}
|
| +''');
|
| + // getElementAt() caches results, it should be notified when offset
|
| + // are changed.
|
| + {
|
| + ClassElement typeA = oldUnitElement.getType('A');
|
| + expect(oldUnitElement.getElementAt(typeA.nameOffset), typeA);
|
| + }
|
| + {
|
| + ClassElement typeB = oldUnitElement.getType('B');
|
| + expect(oldUnitElement.getElementAt(typeB.nameOffset), typeB);
|
| + }
|
| + }
|
| +
|
| + void _assertCacheResults(
|
| + {bool expectLibraryUnchanged: true,
|
| + bool expectCachePostConstantsValid: true}) {
|
| + _assertCacheSourceResult(TOKEN_STREAM);
|
| + _assertCacheSourceResult(SCAN_ERRORS);
|
| + _assertCacheSourceResult(PARSED_UNIT);
|
| + _assertCacheSourceResult(PARSE_ERRORS);
|
| + if (!expectLibraryUnchanged) {
|
| + return;
|
| + }
|
| + _assertCacheSourceResult(LIBRARY_ELEMENT1);
|
| + _assertCacheSourceResult(LIBRARY_ELEMENT2);
|
| + _assertCacheSourceResult(LIBRARY_ELEMENT3);
|
| + _assertCacheSourceResult(LIBRARY_ELEMENT4);
|
| + _assertCacheSourceResult(LIBRARY_ELEMENT5);
|
| + _assertCacheSourceResult(LIBRARY_ELEMENT6);
|
| + _assertCacheSourceResult(LIBRARY_ELEMENT7);
|
| + _assertCacheSourceResult(LIBRARY_ELEMENT8);
|
| + _assertCacheSourceResult(LIBRARY_ELEMENT9);
|
| + if (expectCachePostConstantsValid) {
|
| + _assertCacheSourceResult(LIBRARY_ELEMENT);
|
| + }
|
| + _assertCacheUnitResult(RESOLVED_UNIT1);
|
| + _assertCacheUnitResult(RESOLVED_UNIT2);
|
| + _assertCacheUnitResult(RESOLVED_UNIT3);
|
| + _assertCacheUnitResult(RESOLVED_UNIT4);
|
| + _assertCacheUnitResult(RESOLVED_UNIT5);
|
| + _assertCacheUnitResult(RESOLVED_UNIT6);
|
| + _assertCacheUnitResult(RESOLVED_UNIT7);
|
| + _assertCacheUnitResult(RESOLVED_UNIT8);
|
| + _assertCacheUnitResult(RESOLVED_UNIT9);
|
| + _assertCacheUnitResult(RESOLVED_UNIT10);
|
| + _assertCacheUnitResult(RESOLVED_UNIT11);
|
| + if (expectCachePostConstantsValid) {
|
| + _assertCacheUnitResult(RESOLVED_UNIT12);
|
| + _assertCacheUnitResult(RESOLVED_UNIT);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Assert that the [result] of [source] is not INVALID.
|
| + */
|
| + void _assertCacheSourceResult(ResultDescriptor result) {
|
| + AnalysisCache cache = analysisContext2.analysisCache;
|
| + CacheState state = cache.getState(source, result);
|
| + expect(state, isNot(CacheState.INVALID), reason: result.toString());
|
| + }
|
| +
|
| + /**
|
| + * Assert that the [result] of the defining unit [source] is not INVALID.
|
| + */
|
| + void _assertCacheUnitResult(ResultDescriptor result) {
|
| + AnalysisCache cache = analysisContext2.analysisCache;
|
| + LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
|
| + CacheState state = cache.getState(target, result);
|
| + expect(state, isNot(CacheState.INVALID), reason: result.toString());
|
| + }
|
| +
|
| + void _assertEqualLineInfo(LineInfo incLineInfo, LineInfo fullLineInfo) {
|
| + for (int offset = 0; offset < 1000; offset++) {
|
| + LineInfo_Location incLocation = incLineInfo.getLocation(offset);
|
| + LineInfo_Location fullLocation = fullLineInfo.getLocation(offset);
|
| + if (incLocation.lineNumber != fullLocation.lineNumber ||
|
| + incLocation.columnNumber != fullLocation.columnNumber) {
|
| + fail('At offset $offset ' +
|
| + '(${incLocation.lineNumber}, ${incLocation.columnNumber})' +
|
| + ' != ' +
|
| + '(${fullLocation.lineNumber}, ${fullLocation.columnNumber})');
|
| + }
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Reset the analysis context to have the 'incremental' option set to the
|
| + * given value.
|
| + */
|
| + void _resetWithIncremental(bool enable) {
|
| + AnalysisOptionsImpl analysisOptions = new AnalysisOptionsImpl();
|
| + analysisOptions.strongMode = true;
|
| + analysisOptions.incremental = enable;
|
| + analysisOptions.incrementalApi = enable;
|
| + logging.logger = logger;
|
| + analysisContext2.analysisOptions = analysisOptions;
|
| + }
|
| +
|
| + void _resolveUnit(String code) {
|
| + this.code = code;
|
| + source = addSource(code);
|
| + oldLibrary = resolve2(source);
|
| + oldUnit = resolveCompilationUnit(source, oldLibrary);
|
| + oldUnitElement = oldUnit.element;
|
| + }
|
| +
|
| + void _runTasks() {
|
| + AnalysisResult result = analysisContext.performAnalysisTask();
|
| + while (result.changeNotices != null) {
|
| + result = analysisContext.performAnalysisTask();
|
| + }
|
| + }
|
| +
|
| + void _updateAndValidate(String newCode,
|
| + {bool expectedSuccess: true,
|
| + bool expectLibraryUnchanged: true,
|
| + bool expectCachePostConstantsValid: true,
|
| + bool compareWithFull: true,
|
| + bool runTasksBeforeIncremental: true}) {
|
| + // Run any pending tasks tasks.
|
| + if (runTasksBeforeIncremental) {
|
| + _runTasks();
|
| + }
|
| + // Update the source - currently this may cause incremental resolution.
|
| + // Then request the updated resolved unit.
|
| + _resetWithIncremental(true);
|
| + analysisContext2.setContents(source, newCode);
|
| + CompilationUnit newUnit = resolveCompilationUnit(source, oldLibrary);
|
| + logger.expectNoErrors();
|
| + List<AnalysisError> newErrors = analysisContext.computeErrors(source);
|
| + LineInfo newLineInfo = analysisContext.getLineInfo(source);
|
| + // check for expected failure
|
| + if (!expectedSuccess) {
|
| + expect(newUnit.element, isNot(same(oldUnitElement)));
|
| + return;
|
| + }
|
| + // The cache must still have enough results to make the incremental
|
| + // resolution useful.
|
| + _assertCacheResults(
|
| + expectLibraryUnchanged: expectLibraryUnchanged,
|
| + expectCachePostConstantsValid: expectCachePostConstantsValid);
|
| + // The existing CompilationUnit[Element] should be updated.
|
| + expect(newUnit, same(oldUnit));
|
| + expect(newUnit.element, same(oldUnitElement));
|
| + expect(analysisContext.getResolvedCompilationUnit(source, oldLibrary),
|
| + same(oldUnit));
|
| + // The only expected pending task should return the same resolved
|
| + // "newUnit", so all clients will get it using the usual way.
|
| + AnalysisResult analysisResult = analysisContext.performAnalysisTask();
|
| + ChangeNotice notice = analysisResult.changeNotices[0];
|
| + expect(notice.resolvedDartUnit, same(newUnit));
|
| + // Resolve "newCode" from scratch.
|
| + if (compareWithFull) {
|
| + _resetWithIncremental(false);
|
| + changeSource(source, '');
|
| + changeSource(source, newCode);
|
| + _runTasks();
|
| + LibraryElement library = resolve2(source);
|
| + CompilationUnit fullNewUnit = resolveCompilationUnit(source, library);
|
| + // Validate tokens.
|
| + _assertEqualTokens(newUnit, fullNewUnit);
|
| + // Validate LineInfo
|
| + _assertEqualLineInfo(newLineInfo, analysisContext.getLineInfo(source));
|
| + // Validate that "incremental" and "full" units have the same resolution.
|
| + try {
|
| + assertSameResolution(newUnit, fullNewUnit, validateTypes: true);
|
| + } on IncrementalResolutionMismatch catch (mismatch) {
|
| + fail(mismatch.message);
|
| + }
|
| + List<AnalysisError> newFullErrors =
|
| + analysisContext.getErrors(source).errors;
|
| + _assertEqualErrors(newErrors, newFullErrors);
|
| + }
|
| + _checkCacheEntries(analysisContext2.analysisCache);
|
| + }
|
| +
|
| + static void _assertEqualToken(Token incToken, Token fullToken) {
|
| +// print('[${incToken.offset}] |$incToken| vs. [${fullToken.offset}] |$fullToken|');
|
| + expect(incToken.type, fullToken.type);
|
| + expect(incToken.offset, fullToken.offset);
|
| + expect(incToken.length, fullToken.length);
|
| + expect(incToken.lexeme, fullToken.lexeme);
|
| + }
|
| +
|
| + static void _assertEqualTokens(
|
| + CompilationUnit incUnit, CompilationUnit fullUnit) {
|
| + Token incToken = incUnit.beginToken;
|
| + Token fullToken = fullUnit.beginToken;
|
| + while (incToken.type != TokenType.EOF && fullToken.type != TokenType.EOF) {
|
| + _assertEqualToken(incToken, fullToken);
|
| + // comments
|
| + {
|
| + Token incComment = incToken.precedingComments;
|
| + Token fullComment = fullToken.precedingComments;
|
| + while (true) {
|
| + if (fullComment == null) {
|
| + expect(incComment, isNull);
|
| + break;
|
| + }
|
| + expect(incComment, isNotNull);
|
| + _assertEqualToken(incComment, fullComment);
|
| + incComment = incComment.next;
|
| + fullComment = fullComment.next;
|
| + }
|
| + }
|
| + // next tokens
|
| + incToken = incToken.next;
|
| + fullToken = fullToken.next;
|
| + }
|
| + }
|
| +}
|
| +
|
| +@reflectiveTest
|
| +class ResolutionContextBuilderTest extends EngineTestCase {
|
| + void test_scopeFor_ClassDeclaration() {
|
| + Scope scope = _scopeFor(_createResolvedClassDeclaration());
|
| + EngineTestCase.assertInstanceOf(
|
| + (obj) => obj is LibraryScope, LibraryScope, scope);
|
| + }
|
| +
|
| + void test_scopeFor_ClassTypeAlias() {
|
| + Scope scope = _scopeFor(_createResolvedClassTypeAlias());
|
| + EngineTestCase.assertInstanceOf(
|
| + (obj) => obj is LibraryScope, LibraryScope, scope);
|
| + }
|
| +
|
| + void test_scopeFor_CompilationUnit() {
|
| + Scope scope = _scopeFor(_createResolvedCompilationUnit());
|
| + EngineTestCase.assertInstanceOf(
|
| + (obj) => obj is LibraryScope, LibraryScope, scope);
|
| + }
|
| +
|
| + void test_scopeFor_ConstructorDeclaration() {
|
| + Scope scope = _scopeFor(_createResolvedConstructorDeclaration());
|
| + EngineTestCase.assertInstanceOf(
|
| + (obj) => obj is ClassScope, ClassScope, scope);
|
| + }
|
| +
|
| + void test_scopeFor_ConstructorDeclaration_parameters() {
|
| + Scope scope = _scopeFor(_createResolvedConstructorDeclaration().parameters);
|
| + EngineTestCase.assertInstanceOf(
|
| + (obj) => obj is FunctionScope, FunctionScope, scope);
|
| + }
|
| +
|
| + void test_scopeFor_FunctionDeclaration() {
|
| + Scope scope = _scopeFor(_createResolvedFunctionDeclaration());
|
| + EngineTestCase.assertInstanceOf(
|
| + (obj) => obj is LibraryScope, LibraryScope, scope);
|
| + }
|
| +
|
| + void test_scopeFor_FunctionDeclaration_parameters() {
|
| + Scope scope = _scopeFor(
|
| + _createResolvedFunctionDeclaration().functionExpression.parameters);
|
| + EngineTestCase.assertInstanceOf(
|
| + (obj) => obj is FunctionScope, FunctionScope, scope);
|
| + }
|
| +
|
| + void test_scopeFor_FunctionTypeAlias() {
|
| + Scope scope = _scopeFor(_createResolvedFunctionTypeAlias());
|
| + EngineTestCase.assertInstanceOf(
|
| + (obj) => obj is LibraryScope, LibraryScope, scope);
|
| + }
|
| +
|
| + void test_scopeFor_FunctionTypeAlias_parameters() {
|
| + Scope scope = _scopeFor(_createResolvedFunctionTypeAlias().parameters);
|
| + EngineTestCase.assertInstanceOf(
|
| + (obj) => obj is FunctionTypeScope, FunctionTypeScope, scope);
|
| + }
|
| +
|
| + void test_scopeFor_MethodDeclaration() {
|
| + Scope scope = _scopeFor(_createResolvedMethodDeclaration());
|
| + EngineTestCase.assertInstanceOf(
|
| + (obj) => obj is ClassScope, ClassScope, scope);
|
| + }
|
| +
|
| + void test_scopeFor_MethodDeclaration_body() {
|
| + Scope scope = _scopeFor(_createResolvedMethodDeclaration().body);
|
| + EngineTestCase.assertInstanceOf(
|
| + (obj) => obj is FunctionScope, FunctionScope, scope);
|
| + }
|
| +
|
| + void test_scopeFor_notInCompilationUnit() {
|
| + try {
|
| + _scopeFor(AstTestFactory.identifier3("x"));
|
| + fail("Expected AnalysisException");
|
| + } on AnalysisException {
|
| + // Expected
|
| + }
|
| + }
|
| +
|
| + void test_scopeFor_null() {
|
| + try {
|
| + _scopeFor(null);
|
| + fail("Expected AnalysisException");
|
| + } on AnalysisException {
|
| + // Expected
|
| + }
|
| + }
|
| +
|
| + void test_scopeFor_unresolved() {
|
| + try {
|
| + _scopeFor(AstTestFactory.compilationUnit());
|
| + fail("Expected AnalysisException");
|
| + } on AnalysisException {
|
| + // Expected
|
| + }
|
| + }
|
| +
|
| + ClassDeclaration _createResolvedClassDeclaration() {
|
| + CompilationUnit unit = _createResolvedCompilationUnit();
|
| + String className = "C";
|
| + ClassDeclaration classNode = AstTestFactory.classDeclaration(
|
| + null, className, AstTestFactory.typeParameterList(), null, null, null);
|
| + unit.declarations.add(classNode);
|
| + ClassElement classElement = ElementFactory.classElement2(className);
|
| + classNode.name.staticElement = classElement;
|
| + (unit.element as CompilationUnitElementImpl).types = <ClassElement>[
|
| + classElement
|
| + ];
|
| + return classNode;
|
| + }
|
| +
|
| + ClassTypeAlias _createResolvedClassTypeAlias() {
|
| + CompilationUnit unit = _createResolvedCompilationUnit();
|
| + String className = "C";
|
| + ClassTypeAlias classNode = AstTestFactory.classTypeAlias(
|
| + className, AstTestFactory.typeParameterList(), null, null, null, null);
|
| + unit.declarations.add(classNode);
|
| + ClassElement classElement = ElementFactory.classElement2(className);
|
| + classNode.name.staticElement = classElement;
|
| + (unit.element as CompilationUnitElementImpl).types = <ClassElement>[
|
| + classElement
|
| + ];
|
| + return classNode;
|
| + }
|
| +
|
| + CompilationUnit _createResolvedCompilationUnit() {
|
| + CompilationUnit unit = AstTestFactory.compilationUnit();
|
| + LibraryElementImpl library =
|
| + ElementFactory.library(AnalysisContextFactory.contextWithCore(), "lib");
|
| + unit.element = library.definingCompilationUnit;
|
| + return unit;
|
| + }
|
| +
|
| + ConstructorDeclaration _createResolvedConstructorDeclaration() {
|
| + ClassDeclaration classNode = _createResolvedClassDeclaration();
|
| + String constructorName = "f";
|
| + ConstructorDeclaration constructorNode =
|
| + AstTestFactory.constructorDeclaration(
|
| + AstTestFactory.identifier3(constructorName),
|
| + null,
|
| + AstTestFactory.formalParameterList(),
|
| + null);
|
| + classNode.members.add(constructorNode);
|
| + ConstructorElement constructorElement =
|
| + ElementFactory.constructorElement2(classNode.element, null);
|
| + constructorNode.element = constructorElement;
|
| + (classNode.element as ClassElementImpl).constructors = <ConstructorElement>[
|
| + constructorElement
|
| + ];
|
| + return constructorNode;
|
| + }
|
| +
|
| + FunctionDeclaration _createResolvedFunctionDeclaration() {
|
| + CompilationUnit unit = _createResolvedCompilationUnit();
|
| + String functionName = "f";
|
| + FunctionDeclaration functionNode = AstTestFactory.functionDeclaration(
|
| + null, null, functionName, AstTestFactory.functionExpression());
|
| + unit.declarations.add(functionNode);
|
| + FunctionElement functionElement =
|
| + ElementFactory.functionElement(functionName);
|
| + functionNode.name.staticElement = functionElement;
|
| + (unit.element as CompilationUnitElementImpl).functions = <FunctionElement>[
|
| + functionElement
|
| + ];
|
| + return functionNode;
|
| + }
|
| +
|
| + FunctionTypeAlias _createResolvedFunctionTypeAlias() {
|
| + CompilationUnit unit = _createResolvedCompilationUnit();
|
| + FunctionTypeAlias aliasNode = AstTestFactory.typeAlias(
|
| + AstTestFactory.typeName4("A"),
|
| + "F",
|
| + AstTestFactory.typeParameterList(),
|
| + AstTestFactory.formalParameterList());
|
| + unit.declarations.add(aliasNode);
|
| + SimpleIdentifier aliasName = aliasNode.name;
|
| + FunctionTypeAliasElement aliasElement =
|
| + new FunctionTypeAliasElementImpl.forNode(aliasName);
|
| + aliasName.staticElement = aliasElement;
|
| + (unit.element as CompilationUnitElementImpl).typeAliases =
|
| + <FunctionTypeAliasElement>[aliasElement];
|
| + return aliasNode;
|
| + }
|
| +
|
| + MethodDeclaration _createResolvedMethodDeclaration() {
|
| + ClassDeclaration classNode = _createResolvedClassDeclaration();
|
| + String methodName = "f";
|
| + MethodDeclaration methodNode = AstTestFactory.methodDeclaration(
|
| + null,
|
| + null,
|
| + null,
|
| + null,
|
| + AstTestFactory.identifier3(methodName),
|
| + AstTestFactory.formalParameterList());
|
| + classNode.members.add(methodNode);
|
| + MethodElement methodElement =
|
| + ElementFactory.methodElement(methodName, null);
|
| + methodNode.name.staticElement = methodElement;
|
| + (classNode.element as ClassElementImpl).methods = <MethodElement>[
|
| + methodElement
|
| + ];
|
| + return methodNode;
|
| + }
|
| +
|
| + Scope _scopeFor(AstNode node) {
|
| + return ResolutionContextBuilder.contextFor(node).scope;
|
| + }
|
| +}
|
| +
|
| +class _Edit {
|
| + final int offset;
|
| + final int length;
|
| + final String replacement;
|
| + _Edit(this.offset, this.length, this.replacement);
|
| +}
|
| +
|
| +class _TestLogger implements logging.Logger {
|
| + Object lastException;
|
| + Object lastStackTrace;
|
| +
|
| + @override
|
| + void enter(String name) {}
|
| +
|
| + @override
|
| + void exit() {}
|
| +
|
| + void expectNoErrors() {
|
| + if (lastException != null) {
|
| + fail("logged an exception:\n$lastException\n$lastStackTrace\n");
|
| + }
|
| + }
|
| +
|
| + @override
|
| + void log(Object obj) {}
|
| +
|
| + @override
|
| + void logException(Object exception, [Object stackTrace]) {
|
| + lastException = exception;
|
| + lastStackTrace = stackTrace;
|
| + }
|
| +
|
| + @override
|
| + logging.LoggingTimer startTimer() {
|
| + return new logging.LoggingTimer(this);
|
| + }
|
| +}
|
|
|