| Index: packages/analyzer/test/src/context/context_test.dart
|
| diff --git a/packages/analyzer/test/src/context/context_test.dart b/packages/analyzer/test/src/context/context_test.dart
|
| index 12f6fa7873ffd4f9a54b2432b4f91814c04b9290..7da5f3f287851cda42336de829df981cc69b461c 100644
|
| --- a/packages/analyzer/test/src/context/context_test.dart
|
| +++ b/packages/analyzer/test/src/context/context_test.dart
|
| @@ -2,60 +2,67 @@
|
| // 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 test.src.context.context_test;
|
| +library analyzer.test.src.context.context_test;
|
|
|
| import 'dart:async';
|
| -
|
| +import 'dart:collection';
|
| +
|
| +import 'package:analyzer/dart/ast/ast.dart';
|
| +import 'package:analyzer/dart/element/element.dart';
|
| +import 'package:analyzer/dart/element/type.dart';
|
| +import 'package:analyzer/dart/element/visitor.dart';
|
| +import 'package:analyzer/error/error.dart';
|
| +import 'package:analyzer/exception/exception.dart';
|
| +import 'package:analyzer/file_system/file_system.dart';
|
| import 'package:analyzer/file_system/memory_file_system.dart';
|
| +import 'package:analyzer/source/package_map_resolver.dart';
|
| import 'package:analyzer/src/cancelable_future.dart';
|
| import 'package:analyzer/src/context/cache.dart';
|
| import 'package:analyzer/src/context/context.dart';
|
| -import 'package:analyzer/src/generated/ast.dart';
|
| -import 'package:analyzer/src/generated/element.dart';
|
| -import 'package:analyzer/src/generated/engine.dart'
|
| - show
|
| - AnalysisContext,
|
| - AnalysisContextStatistics,
|
| - AnalysisDelta,
|
| - AnalysisEngine,
|
| - AnalysisErrorInfo,
|
| - AnalysisLevel,
|
| - AnalysisNotScheduledError,
|
| - AnalysisOptions,
|
| - AnalysisOptionsImpl,
|
| - AnalysisResult,
|
| - CacheState,
|
| - ChangeNotice,
|
| - ChangeSet,
|
| - IncrementalAnalysisCache,
|
| - TimestampedData;
|
| -import 'package:analyzer/src/generated/error.dart';
|
| -import 'package:analyzer/src/generated/java_engine.dart';
|
| +import 'package:analyzer/src/dart/element/element.dart';
|
| +import 'package:analyzer/src/dart/scanner/scanner.dart';
|
| +import 'package:analyzer/src/generated/engine.dart';
|
| import 'package:analyzer/src/generated/resolver.dart';
|
| -import 'package:analyzer/src/generated/scanner.dart';
|
| import 'package:analyzer/src/generated/source.dart';
|
| +import 'package:analyzer/src/generated/utilities_collection.dart';
|
| import 'package:analyzer/src/task/dart.dart';
|
| import 'package:analyzer/src/task/html.dart';
|
| import 'package:analyzer/task/dart.dart';
|
| +import 'package:analyzer/task/general.dart';
|
| import 'package:analyzer/task/model.dart';
|
| import 'package:html/dom.dart' show Document;
|
| +import 'package:test_reflective_loader/test_reflective_loader.dart';
|
| import 'package:unittest/unittest.dart';
|
| import 'package:watcher/src/utils.dart';
|
|
|
| import '../../generated/engine_test.dart';
|
| import '../../generated/test_support.dart';
|
| -import '../../reflective_tests.dart';
|
| import '../../utils.dart';
|
| import 'abstract_context.dart';
|
|
|
| main() {
|
| initializeTestEnvironment();
|
| - runReflectiveTests(AnalysisContextImplTest);
|
| - runReflectiveTests(LimitedInvalidateTest);
|
| + defineReflectiveTests(AnalysisContextImplTest);
|
| + defineReflectiveTests(LimitedInvalidateTest);
|
| }
|
|
|
| @reflectiveTest
|
| class AnalysisContextImplTest extends AbstractContextTest {
|
| + void fail_getErrors_html_some() {
|
| + Source source = addSource(
|
| + "/test.html",
|
| + r'''
|
| +<html><head>
|
| +<script type='application/dart' src='test.dart'/>
|
| +</head></html>''');
|
| + AnalysisErrorInfo errorInfo = context.getErrors(source);
|
| + expect(errorInfo, isNotNull);
|
| + List<AnalysisError> errors = errorInfo.errors;
|
| + expect(errors, hasLength(0));
|
| + errors = context.computeErrors(source);
|
| + expect(errors, hasLength(2));
|
| + }
|
| +
|
| Future fail_implicitAnalysisEvents_removed() async {
|
| AnalyzedSourcesListener listener = new AnalyzedSourcesListener();
|
| context.implicitAnalysisEvents.listen(listener.onData);
|
| @@ -135,6 +142,56 @@ class AnalysisContextImplTest extends AbstractContextTest {
|
| });
|
| }
|
|
|
| + void test_applyChanges_add_makesExplicit() {
|
| + Source source = newSource('/test.dart');
|
| + // get the entry, it's not explicit
|
| + CacheEntry entry = context.getCacheEntry(source);
|
| + expect(entry.explicitlyAdded, isFalse);
|
| + // add the source
|
| + ChangeSet changeSet = new ChangeSet();
|
| + changeSet.addedSource(source);
|
| + context.applyChanges(changeSet);
|
| + // now the entry is explicit
|
| + expect(entry.explicitlyAdded, isTrue);
|
| + }
|
| +
|
| + void test_applyChanges_addNewImport_invalidateLibraryCycle() {
|
| + context.analysisOptions =
|
| + new AnalysisOptionsImpl.from(context.analysisOptions)
|
| + ..strongMode = true;
|
| + Source embedder = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +library a;
|
| +import 'b.dart';
|
| +//import 'c.dart';
|
| +''');
|
| + addSource(
|
| + '/b.dart',
|
| + r'''
|
| +library b;
|
| +import 'a.dart';
|
| +''');
|
| + addSource(
|
| + '/c.dart',
|
| + r'''
|
| +library c;
|
| +import 'b.dart';
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Add a new import into a.dart, this should invalidate its library cycle.
|
| + // If it doesn't, we will get a task cycle exception.
|
| + context.setContents(
|
| + embedder,
|
| + r'''
|
| +library a;
|
| +import 'b.dart';
|
| +import 'c.dart';
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getCacheEntry(embedder).exception, isNull);
|
| + }
|
| +
|
| Future test_applyChanges_change() {
|
| SourcesChangedListener listener = new SourcesChangedListener();
|
| context.onSourcesChanged.listen(listener.onData);
|
| @@ -226,8 +283,9 @@ int b = aa;''';
|
| Element declarationElement = declaration.variables.variables[0].element;
|
| TopLevelVariableDeclaration use =
|
| partUnit.declarations[0] as TopLevelVariableDeclaration;
|
| - Element useElement = (use.variables.variables[0].initializer
|
| - as SimpleIdentifier).staticElement;
|
| + Element useElement =
|
| + (use.variables.variables[0].initializer as SimpleIdentifier)
|
| + .staticElement;
|
| expect((useElement as PropertyAccessorElement).variable,
|
| same(declarationElement));
|
| return pumpEventQueue().then((_) {
|
| @@ -260,14 +318,78 @@ int b = aa;''';
|
| });
|
| }
|
|
|
| + void test_applyChanges_changedSource_updateModificationTime() {
|
| + String path = '/test.dart';
|
| + File file = resourceProvider.newFile(path, 'var V = 1;');
|
| + Source source = file.createSource();
|
| + context.applyChanges(new ChangeSet()..addedSource(source));
|
| + // Analyze all.
|
| + _analyzeAll_assertFinished();
|
| + expect(context.analysisCache.getState(source, RESOLVED_UNIT),
|
| + CacheState.INVALID);
|
| + // Update the file and notify the context about the change.
|
| + resourceProvider.updateFile(path, 'var V = 2;');
|
| + context.applyChanges(new ChangeSet()..changedSource(source));
|
| + // The analysis results are invalidated.
|
| + // We have seen the new contents, so 'modificationTime' is also updated.
|
| + expect(context.analysisCache.getState(source, RESOLVED_UNIT),
|
| + CacheState.INVALID);
|
| + expect(
|
| + context.getCacheEntry(source).modificationTime, file.modificationStamp);
|
| + }
|
| +
|
| void test_applyChanges_empty() {
|
| context.applyChanges(new ChangeSet());
|
| expect(context.performAnalysisTask().changeNotices, isNull);
|
| }
|
|
|
| + void test_applyChanges_incremental_resetDriver() {
|
| + context.analysisOptions = new AnalysisOptionsImpl()..incremental = true;
|
| + Source source = addSource(
|
| + "/test.dart",
|
| + r'''
|
| +main() {
|
| + print(42);
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(source).errors, hasLength(0));
|
| + // Update the source to have a parse error.
|
| + // This is an incremental change, but we always invalidate DART_ERRORS.
|
| + context.setContents(
|
| + source,
|
| + r'''
|
| +main() {
|
| + print(42)
|
| +}
|
| +''');
|
| + AnalysisCache cache = context.analysisCache;
|
| + expect(cache.getValue(source, PARSE_ERRORS), hasLength(1));
|
| + expect(cache.getState(source, DART_ERRORS), CacheState.INVALID);
|
| + // Perform enough analysis to prepare inputs (is not actually tested) for
|
| + // the DART_ERRORS computing task, but don't compute it yet.
|
| + context.performAnalysisTask();
|
| + context.performAnalysisTask();
|
| + expect(cache.getState(source, DART_ERRORS), CacheState.INVALID);
|
| + // Update the source so that PARSE_ERRORS is empty.
|
| + context.setContents(
|
| + source,
|
| + r'''
|
| +main() {
|
| + print(42);
|
| +}
|
| +''');
|
| + expect(cache.getValue(source, PARSE_ERRORS), hasLength(0));
|
| + // After full analysis DART_ERRORS should also be empty.
|
| + _performPendingAnalysisTasks();
|
| + expect(cache.getValue(source, DART_ERRORS), hasLength(0));
|
| + expect(context.getErrors(source).errors, hasLength(0));
|
| + }
|
| +
|
| void test_applyChanges_overriddenSource() {
|
| - // Note: addSource adds the source to the contentCache.
|
| - Source source = addSource("/test.dart", "library test;");
|
| + String content = "library test;";
|
| + Source source = addSource("/test.dart", content);
|
| + context.setContents(source, content);
|
| context.computeErrors(source);
|
| while (!context.sourcesNeedingProcessing.isEmpty) {
|
| context.performAnalysisTask();
|
| @@ -280,6 +402,39 @@ int b = aa;''';
|
| expect(context.sourcesNeedingProcessing, hasLength(0));
|
| }
|
|
|
| + void test_applyChanges_recompute_exportNamespace() {
|
| + Source libSource = addSource(
|
| + "/lib.dart",
|
| + r'''
|
| +class A {}
|
| +''');
|
| + Source exporterSource = addSource(
|
| + "/exporter.dart",
|
| + r'''
|
| +export 'lib.dart';
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // initially: A
|
| + {
|
| + LibraryElement libraryElement =
|
| + context.getResult(exporterSource, LIBRARY_ELEMENT1);
|
| + expect(libraryElement.exportNamespace.definedNames.keys,
|
| + unorderedEquals(['A']));
|
| + }
|
| + // after update: B
|
| + context.setContents(
|
| + libSource,
|
| + r'''
|
| +class B {}''');
|
| + _performPendingAnalysisTasks();
|
| + {
|
| + LibraryElement libraryElement =
|
| + context.getResult(exporterSource, LIBRARY_ELEMENT1);
|
| + expect(libraryElement.exportNamespace.definedNames.keys,
|
| + unorderedEquals(['B']));
|
| + }
|
| + }
|
| +
|
| Future test_applyChanges_remove() {
|
| SourcesChangedListener listener = new SourcesChangedListener();
|
| context.onSourcesChanged.listen(listener.onData);
|
| @@ -295,7 +450,6 @@ import 'libB.dart';''';
|
| expect(importedLibraries, hasLength(2));
|
| context.computeErrors(libA);
|
| context.computeErrors(libB);
|
| - expect(context.sourcesNeedingProcessing, hasLength(0));
|
| context.setContents(libB, null);
|
| _removeSource(libB);
|
| List<Source> sources = context.sourcesNeedingProcessing;
|
| @@ -303,7 +457,7 @@ import 'libB.dart';''';
|
| expect(sources[0], same(libA));
|
| libAElement = context.computeLibraryElement(libA);
|
| importedLibraries = libAElement.importedLibraries;
|
| - expect(importedLibraries, hasLength(1));
|
| + expect(importedLibraries, hasLength(2));
|
| return pumpEventQueue().then((_) {
|
| listener.assertEvent(wereSourcesAdded: true);
|
| listener.assertEvent(wereSourcesAdded: true);
|
| @@ -348,7 +502,6 @@ main() {
|
| expect(context.getResolvedCompilationUnit2(source, source), unit);
|
| // remove overlay
|
| context.setContents(source, null);
|
| - context.validateCacheConsistency();
|
| _analyzeAll_assertFinished();
|
| expect(context.getResolvedCompilationUnit2(source, source), unit);
|
| }
|
| @@ -365,7 +518,6 @@ import 'libB.dart';''';
|
| context.computeLibraryElement(libA);
|
| context.computeErrors(libA);
|
| context.computeErrors(libB);
|
| - expect(context.sourcesNeedingProcessing, hasLength(0));
|
| ChangeSet changeSet = new ChangeSet();
|
| SourceContainer removedContainer =
|
| new _AnalysisContextImplTest_test_applyChanges_removeContainer(libB);
|
| @@ -382,7 +534,128 @@ import 'libB.dart';''';
|
| });
|
| }
|
|
|
| - void test_computeDocumentationComment_block() {
|
| + void test_applyChanges_removeUsedLibrary_addAgain() {
|
| + String codeA = r'''
|
| +import 'b.dart';
|
| +B b = null;
|
| +''';
|
| + String codeB = r'''
|
| +class B {}
|
| +''';
|
| + Source a = addSource('/a.dart', codeA);
|
| + Source b = addSource('/b.dart', codeB);
|
| + CacheState getErrorsState(Source source) =>
|
| + context.analysisCache.getState(source, LIBRARY_ERRORS_READY);
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(a).errors, hasLength(0));
|
| + // Remove b.dart - errors in a.dart are invalidated and recomputed.
|
| + // Now a.dart has an error.
|
| + _removeSource(b);
|
| + expect(getErrorsState(a), CacheState.INVALID);
|
| + _performPendingAnalysisTasks();
|
| + expect(getErrorsState(a), CacheState.VALID);
|
| + expect(context.getErrors(a).errors, hasLength(isPositive));
|
| + // Add b.dart - errors in a.dart are invalidated and recomputed.
|
| + // The reason is that a.dart adds dependencies on (not existing) b.dart
|
| + // results in cache.
|
| + // Now a.dart does not have errors.
|
| + addSource('/b.dart', codeB);
|
| + expect(getErrorsState(a), CacheState.INVALID);
|
| + _performPendingAnalysisTasks();
|
| + expect(getErrorsState(a), CacheState.VALID);
|
| + expect(context.getErrors(a).errors, hasLength(0));
|
| + }
|
| +
|
| + void test_cacheConsistencyValidator_computed_deleted() {
|
| + CacheConsistencyValidator validator = context.cacheConsistencyValidator;
|
| + var stat = PerformanceStatistics.cacheConsistencyValidationStatistics;
|
| + stat.reset();
|
| + // Add sources.
|
| + MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
|
| + String path1 = '/test1.dart';
|
| + String path2 = '/test2.dart';
|
| + Source source1 = resourceProvider.newFile(path1, '// 1-1').createSource();
|
| + Source source2 = resourceProvider.newFile(path2, '// 2-1').createSource();
|
| + context.applyChanges(
|
| + new ChangeSet()..addedSource(source1)..addedSource(source2));
|
| + // Same modification times.
|
| + expect(
|
| + validator.sourceModificationTimesComputed([source1, source2],
|
| + [source1.modificationStamp, source2.modificationStamp]),
|
| + isFalse);
|
| + expect(stat.numOfChanged, 0);
|
| + expect(stat.numOfRemoved, 0);
|
| + // Add overlay
|
| + context.setContents(source1, '// 1-2');
|
| + expect(
|
| + validator.sourceModificationTimesComputed(
|
| + [source1, source2], [-1, source2.modificationStamp]),
|
| + isFalse);
|
| + context.setContents(source1, null);
|
| + expect(stat.numOfChanged, 0);
|
| + expect(stat.numOfRemoved, 0);
|
| + // Different modification times.
|
| + expect(
|
| + validator.sourceModificationTimesComputed(
|
| + [source1, source2], [-1, source2.modificationStamp]),
|
| + isTrue);
|
| + expect(stat.numOfChanged, 0);
|
| + expect(stat.numOfRemoved, 1);
|
| + }
|
| +
|
| + void test_cacheConsistencyValidator_computed_modified() {
|
| + CacheConsistencyValidator validator = context.cacheConsistencyValidator;
|
| + var stat = PerformanceStatistics.cacheConsistencyValidationStatistics;
|
| + stat.reset();
|
| + // Add sources.
|
| + MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
|
| + String path1 = '/test1.dart';
|
| + String path2 = '/test2.dart';
|
| + Source source1 = resourceProvider.newFile(path1, '// 1-1').createSource();
|
| + Source source2 = resourceProvider.newFile(path2, '// 2-1').createSource();
|
| + context.applyChanges(
|
| + new ChangeSet()..addedSource(source1)..addedSource(source2));
|
| + // Same modification times.
|
| + expect(
|
| + validator.sourceModificationTimesComputed([source1, source2],
|
| + [source1.modificationStamp, source2.modificationStamp]),
|
| + isFalse);
|
| + expect(stat.numOfChanged, 0);
|
| + expect(stat.numOfRemoved, 0);
|
| + // Add overlay
|
| + context.setContents(source1, '// 1-2');
|
| + expect(
|
| + validator.sourceModificationTimesComputed([source1, source2],
|
| + [source1.modificationStamp + 1, source2.modificationStamp]),
|
| + isFalse);
|
| + context.setContents(source1, null);
|
| + expect(stat.numOfChanged, 0);
|
| + expect(stat.numOfRemoved, 0);
|
| + // Different modification times.
|
| + expect(
|
| + validator.sourceModificationTimesComputed([source1, source2],
|
| + [source1.modificationStamp + 1, source2.modificationStamp]),
|
| + isTrue);
|
| + expect(stat.numOfChanged, 1);
|
| + expect(stat.numOfRemoved, 0);
|
| + }
|
| +
|
| + void test_cacheConsistencyValidator_getSources() {
|
| + CacheConsistencyValidator validator = context.cacheConsistencyValidator;
|
| + // Add sources.
|
| + MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
|
| + String path1 = '/test1.dart';
|
| + String path2 = '/test2.dart';
|
| + Source source1 = resourceProvider.newFile(path1, '// 1-1').createSource();
|
| + Source source2 = resourceProvider.newFile(path2, '// 2-1').createSource();
|
| + context.applyChanges(
|
| + new ChangeSet()..addedSource(source1)..addedSource(source2));
|
| + // Verify.
|
| + expect(validator.getSourcesToComputeModificationTimes(),
|
| + unorderedEquals([source1, source2]));
|
| + }
|
| +
|
| + void test_computeDocumentationComment_class_block() {
|
| String comment = "/** Comment */";
|
| Source source = addSource(
|
| "/test.dart",
|
| @@ -396,7 +669,7 @@ class A {}""");
|
| expect(context.computeDocumentationComment(classElement), comment);
|
| }
|
|
|
| - void test_computeDocumentationComment_none() {
|
| + void test_computeDocumentationComment_class_none() {
|
| Source source = addSource("/test.dart", "class A {}");
|
| LibraryElement libraryElement = context.computeLibraryElement(source);
|
| expect(libraryElement, isNotNull);
|
| @@ -405,11 +678,7 @@ class A {}""");
|
| expect(context.computeDocumentationComment(classElement), isNull);
|
| }
|
|
|
| - void test_computeDocumentationComment_null() {
|
| - expect(context.computeDocumentationComment(null), isNull);
|
| - }
|
| -
|
| - void test_computeDocumentationComment_singleLine_multiple_EOL_n() {
|
| + void test_computeDocumentationComment_class_singleLine_multiple_EOL_n() {
|
| String comment = "/// line 1\n/// line 2\n/// line 3\n";
|
| Source source = addSource("/test.dart", "${comment}class A {}");
|
| LibraryElement libraryElement = context.computeLibraryElement(source);
|
| @@ -420,7 +689,7 @@ class A {}""");
|
| expect(actual, "/// line 1\n/// line 2\n/// line 3");
|
| }
|
|
|
| - void test_computeDocumentationComment_singleLine_multiple_EOL_rn() {
|
| + void test_computeDocumentationComment_class_singleLine_multiple_EOL_rn() {
|
| String comment = "/// line 1\r\n/// line 2\r\n/// line 3\r\n";
|
| Source source = addSource("/test.dart", "${comment}class A {}");
|
| LibraryElement libraryElement = context.computeLibraryElement(source);
|
| @@ -431,6 +700,58 @@ class A {}""");
|
| expect(actual, "/// line 1\n/// line 2\n/// line 3");
|
| }
|
|
|
| + void test_computeDocumentationComment_exportDirective_block() {
|
| + String comment = '/** Comment */';
|
| + Source source = addSource(
|
| + "/test.dart",
|
| + '''
|
| +$comment
|
| +export 'dart:async';
|
| +''');
|
| + LibraryElement libraryElement = context.computeLibraryElement(source);
|
| + expect(libraryElement, isNotNull);
|
| + ExportElement exportElement = libraryElement.exports[0];
|
| + expect(context.computeDocumentationComment(exportElement), comment);
|
| + }
|
| +
|
| + void test_computeDocumentationComment_importDirective_block() {
|
| + String comment = '/** Comment */';
|
| + Source source = addSource(
|
| + "/test.dart",
|
| + '''
|
| +$comment
|
| +import 'dart:async';
|
| +''');
|
| + LibraryElement libraryElement = context.computeLibraryElement(source);
|
| + expect(libraryElement, isNotNull);
|
| + ImportElement importElement = libraryElement.imports[0];
|
| + expect(context.computeDocumentationComment(importElement), comment);
|
| + }
|
| +
|
| + void test_computeDocumentationComment_libraryDirective_block() {
|
| + String comment = '/** Comment */';
|
| + Source source = addSource(
|
| + "/test.dart",
|
| + '''
|
| +$comment
|
| +library lib;
|
| +''');
|
| + LibraryElement libraryElement = context.computeLibraryElement(source);
|
| + expect(libraryElement, isNotNull);
|
| + expect(context.computeDocumentationComment(libraryElement), comment);
|
| + }
|
| +
|
| + void test_computeDocumentationComment_null() {
|
| + expect(context.computeDocumentationComment(null), isNull);
|
| + }
|
| +
|
| + void test_computeErrors_dart_malformedCode() {
|
| + Source source = addSource("/lib.dart", "final int , = 42;");
|
| + List<AnalysisError> errors = context.computeErrors(source);
|
| + expect(errors, isNotNull);
|
| + expect(errors.length > 0, isTrue);
|
| + }
|
| +
|
| void test_computeErrors_dart_none() {
|
| Source source = addSource("/lib.dart", "library lib;");
|
| List<AnalysisError> errors = context.computeErrors(source);
|
| @@ -547,12 +868,15 @@ main() {}''');
|
| expect(unit, isNotNull);
|
| completed = true;
|
| });
|
| - return pumpEventQueue().then((_) {
|
| - expect(completed, isFalse);
|
| - _performPendingAnalysisTasks();
|
| - }).then((_) => pumpEventQueue()).then((_) {
|
| - expect(completed, isTrue);
|
| - });
|
| + return pumpEventQueue()
|
| + .then((_) {
|
| + expect(completed, isFalse);
|
| + _performPendingAnalysisTasks();
|
| + })
|
| + .then((_) => pumpEventQueue())
|
| + .then((_) {
|
| + expect(completed, isTrue);
|
| + });
|
| }
|
|
|
| Future test_computeResolvedCompilationUnitAsync_afterDispose() {
|
| @@ -641,21 +965,24 @@ main() {}''');
|
| expect(unit, isNotNull);
|
| completed = true;
|
| });
|
| - return pumpEventQueue().then((_) {
|
| - expect(completed, isFalse);
|
| - _performPendingAnalysisTasks();
|
| - }).then((_) => pumpEventQueue()).then((_) {
|
| - expect(completed, isTrue);
|
| - });
|
| + return pumpEventQueue()
|
| + .then((_) {
|
| + expect(completed, isFalse);
|
| + _performPendingAnalysisTasks();
|
| + })
|
| + .then((_) => pumpEventQueue())
|
| + .then((_) {
|
| + expect(completed, isTrue);
|
| + });
|
| }
|
|
|
| void test_configurationData() {
|
| - var key = new ResultDescriptor('test_key', '');
|
| + var key = new ResultDescriptor('test_key', 'TEST_DEFAULT');
|
| var testData = ['test', 'data'];
|
| context.setConfigurationData(key, testData);
|
| expect(context.getConfigurationData(key), testData);
|
| - var unusedKey = new ResultDescriptor('unused_key', '');
|
| - expect(context.getConfigurationData(unusedKey), null);
|
| + var unusedKey = new ResultDescriptor('unused_key', 'UNUSED_DEFAULT');
|
| + expect(context.getConfigurationData(unusedKey), 'UNUSED_DEFAULT');
|
| }
|
|
|
| void test_dispose() {
|
| @@ -780,10 +1107,61 @@ part of lib;
|
| }
|
|
|
| void test_exists_true() {
|
| - expect(context.exists(new AnalysisContextImplTest_Source_exists_true()),
|
| + expect(context.exists(new _AnalysisContextImplTest_Source_exists_true()),
|
| isTrue);
|
| }
|
|
|
| + void test_flushResolvedUnit_updateFile_dontNotify() {
|
| + String oldCode = '';
|
| + String newCode = r'''
|
| +import 'dart:async';
|
| +''';
|
| + String path = '/test.dart';
|
| + Source source = resourceProvider.newFile(path, oldCode).createSource();
|
| + context.applyChanges(new ChangeSet()..addedSource(source));
|
| + context.resolveCompilationUnit2(source, source);
|
| + // Flush all results units.
|
| + context.analysisCache.flush((target, result) {
|
| + if (target.source == source) {
|
| + return RESOLVED_UNIT_RESULTS.contains(result);
|
| + }
|
| + return false;
|
| + });
|
| + // Update the file, but don't notify the context.
|
| + resourceProvider.updateFile(path, newCode);
|
| + // Driver must detect that the file was changed and recover.
|
| + CompilationUnit unit = context.resolveCompilationUnit2(source, source);
|
| + expect(unit, isNotNull);
|
| + }
|
| +
|
| + void test_flushResolvedUnit_updateFile_dontNotify2() {
|
| + String oldCode = r'''
|
| +main() {}
|
| +''';
|
| + String newCode = r'''
|
| +import 'dart:async';
|
| +main() {}
|
| +''';
|
| + String path = '/test.dart';
|
| + Source source = resourceProvider.newFile(path, oldCode).createSource();
|
| + context.applyChanges(new ChangeSet()..addedSource(source));
|
| + context.resolveCompilationUnit2(source, source);
|
| + // Flush all results units.
|
| + context.analysisCache.flush((target, result) {
|
| + if (target.source == source) {
|
| + if (target.source == source) {
|
| + return RESOLVED_UNIT_RESULTS.contains(result);
|
| + }
|
| + }
|
| + return false;
|
| + });
|
| + // Update the file, but don't notify the context.
|
| + resourceProvider.updateFile(path, newCode);
|
| + // Driver must detect that the file was changed and recover.
|
| + CompilationUnit unit = context.resolveCompilationUnit2(source, source);
|
| + expect(unit, isNotNull);
|
| + }
|
| +
|
| void test_getAnalysisOptions() {
|
| expect(context.analysisOptions, isNotNull);
|
| }
|
| @@ -795,19 +1173,19 @@ part of lib;
|
| expect(contents.data.toString(), content);
|
| }
|
|
|
| - void test_getContents_overridden() {
|
| + void test_getContents_notOverridden() {
|
| String content = "library lib;";
|
| - Source source = new TestSource();
|
| - context.setContents(source, content);
|
| + Source source = new TestSource('/test.dart', content);
|
| + context.setContents(source, "part of lib;");
|
| + context.setContents(source, null);
|
| TimestampedData<String> contents = context.getContents(source);
|
| expect(contents.data.toString(), content);
|
| }
|
|
|
| - void test_getContents_unoverridden() {
|
| + void test_getContents_overridden() {
|
| String content = "library lib;";
|
| - Source source = new TestSource('/test.dart', content);
|
| - context.setContents(source, "part of lib;");
|
| - context.setContents(source, null);
|
| + Source source = new TestSource();
|
| + context.setContents(source, content);
|
| TimestampedData<String> contents = context.getContents(source);
|
| expect(contents.data.toString(), content);
|
| }
|
| @@ -902,21 +1280,6 @@ class A {
|
| expect(errors, hasLength(0));
|
| }
|
|
|
| - void test_getErrors_html_some() {
|
| - Source source = addSource(
|
| - "/test.html",
|
| - r'''
|
| -<html><head>
|
| -<script type='application/dart' src='test.dart'/>
|
| -</head></html>''');
|
| - AnalysisErrorInfo errorInfo = context.getErrors(source);
|
| - expect(errorInfo, isNotNull);
|
| - List<AnalysisError> errors = errorInfo.errors;
|
| - expect(errors, hasLength(0));
|
| - errors = context.computeErrors(source);
|
| - expect(errors, hasLength(2));
|
| - }
|
| -
|
| void test_getHtmlFilesReferencing_html() {
|
| Source htmlSource = addSource(
|
| "/test.html",
|
| @@ -1037,7 +1400,7 @@ main() {}''');
|
| List<Source> sources = context.launchableClientLibrarySources;
|
| expect(sources, isEmpty);
|
| addSource(
|
| - "/a.dart",
|
| + '/a.dart',
|
| r'''
|
| import 'dart:html';
|
| ''');
|
| @@ -1046,7 +1409,7 @@ import 'dart:html';
|
| r'''
|
| import 'a.dart';
|
| main() {}''');
|
| - context.computeLibraryElement(source);
|
| + _analyzeAll_assertFinished();
|
| sources = context.launchableClientLibrarySources;
|
| expect(sources, unorderedEquals([source]));
|
| }
|
| @@ -1055,7 +1418,7 @@ main() {}''');
|
| List<Source> sources = context.launchableClientLibrarySources;
|
| expect(sources, isEmpty);
|
| addSource(
|
| - "/a.dart",
|
| + '/a.dart',
|
| r'''
|
| export 'dart:html';
|
| ''');
|
| @@ -1064,7 +1427,7 @@ export 'dart:html';
|
| r'''
|
| import 'a.dart';
|
| main() {}''');
|
| - context.computeLibraryElement(source);
|
| + _analyzeAll_assertFinished();
|
| sources = context.launchableClientLibrarySources;
|
| expect(sources, unorderedEquals([source]));
|
| }
|
| @@ -1093,12 +1456,12 @@ main() {}
|
| r'''
|
| import 'dart:html';
|
| ''');
|
| - Source source = addSource(
|
| + addSource(
|
| "/test.dart",
|
| r'''
|
| import 'imports_html.dart';
|
| main() {}''');
|
| - context.computeLibraryElement(source);
|
| + _analyzeAll_assertFinished();
|
| expect(context.launchableServerLibrarySources, isEmpty);
|
| }
|
|
|
| @@ -1255,7 +1618,7 @@ main() {}''');
|
| int stamp = 42;
|
| expect(
|
| context.getModificationStamp(
|
| - new AnalysisContextImplTest_Source_getModificationStamp_fromSource(
|
| + new _AnalysisContextImplTest_Source_getModificationStamp_fromSource(
|
| stamp)),
|
| stamp);
|
| }
|
| @@ -1263,7 +1626,7 @@ main() {}''');
|
| void test_getModificationStamp_overridden() {
|
| int stamp = 42;
|
| Source source =
|
| - new AnalysisContextImplTest_Source_getModificationStamp_overridden(
|
| + new _AnalysisContextImplTest_Source_getModificationStamp_overridden(
|
| stamp);
|
| context.setContents(source, "");
|
| expect(stamp != context.getModificationStamp(source), isTrue);
|
| @@ -1323,16 +1686,6 @@ main() {}''');
|
| expect(context.getSourcesWithFullName(filePath), unorderedEquals(expected));
|
| }
|
|
|
| - void test_getStatistics() {
|
| - AnalysisContextStatistics statistics = context.statistics;
|
| - expect(statistics, isNotNull);
|
| - // The following lines are fragile.
|
| - // The values depend on the number of libraries in the SDK.
|
| -// assertLength(0, statistics.getCacheRows());
|
| -// assertLength(0, statistics.getExceptions());
|
| -// assertLength(0, statistics.getSources());
|
| - }
|
| -
|
| void test_handleContentsChanged() {
|
| ContentCache contentCache = new ContentCache();
|
| context.contentCache = contentCache;
|
| @@ -1350,6 +1703,60 @@ main() {}''');
|
| expect(analysisResult.changeNotices, isNotNull);
|
| }
|
|
|
| + void test_handleContentsChanged_incremental_newContentsNull() {
|
| + context.analysisOptions = new AnalysisOptionsImpl()..incremental = true;
|
| + ContentCache contentCache = new ContentCache();
|
| + context.contentCache = contentCache;
|
| + // old contents
|
| + String oldContents = 'foo() {}';
|
| + Source source = resourceProvider.getFile('/test.dart').createSource();
|
| + contentCache.setContents(source, oldContents);
|
| + expect(context.computeLibraryElement(source), isNotNull);
|
| + // new contents
|
| + String newContents = null;
|
| + contentCache.setContents(source, newContents);
|
| + context.handleContentsChanged(source, oldContents, newContents, true);
|
| + expect(context.getLibraryElement(source), isNull);
|
| + }
|
| +
|
| + void test_handleContentsChanged_noOriginal_sameAsFile() {
|
| + ContentCache contentCache = new ContentCache();
|
| + context.contentCache = contentCache;
|
| + // Add the source.
|
| + String code = 'foo() {}';
|
| + Source source = addSource("/test.dart", code);
|
| + _analyzeAll_assertFinished();
|
| + expect(context.getResolvedCompilationUnit2(source, source), isNotNull);
|
| + // Update the content cache, and notify that we updated the source.
|
| + // We pass "null" as "originalContents" because the was no one.
|
| + contentCache.setContents(source, code);
|
| + context.handleContentsChanged(source, null, code, true);
|
| + expect(context.getResolvedCompilationUnit2(source, source), isNotNull);
|
| + }
|
| +
|
| + void test_handleContentsChanged_noOriginal_sameAsFile_butFileUpdated() {
|
| + ContentCache contentCache = new ContentCache();
|
| + context.contentCache = contentCache;
|
| + // Add the source.
|
| + String oldCode = 'foo() {}';
|
| + String newCode = 'bar() {}';
|
| + var file = resourceProvider.newFile('/test.dart', oldCode);
|
| + Source source = file.createSource();
|
| + context.applyChanges(new ChangeSet()..addedSource(source));
|
| + _analyzeAll_assertFinished();
|
| + expect(context.getResolvedCompilationUnit2(source, source), isNotNull);
|
| + // Test for the race condition.
|
| + // 1. Update the file.
|
| + // 2. Update the content cache.
|
| + // 3. Notify the context, and because this is the first time when we
|
| + // update the content cache, we don't know "originalContents".
|
| + // The source must be invalidated, because it has different contents now.
|
| + resourceProvider.updateFile('/test.dart', newCode);
|
| + contentCache.setContents(source, newCode);
|
| + context.handleContentsChanged(source, null, newCode, true);
|
| + expect(context.getResolvedCompilationUnit2(source, source), isNull);
|
| + }
|
| +
|
| Future test_implicitAnalysisEvents_added() async {
|
| AnalyzedSourcesListener listener = new AnalyzedSourcesListener();
|
| context.implicitAnalysisEvents.listen(listener.onData);
|
| @@ -1387,6 +1794,11 @@ main() {}''');
|
| expect(context.isClientLibrary(source), isFalse);
|
| }
|
|
|
| + void test_isClientLibrary_unknown() {
|
| + Source source = newSource("/test.dart");
|
| + expect(context.isClientLibrary(source), isFalse);
|
| + }
|
| +
|
| void test_isServerLibrary_dart() {
|
| Source source = addSource(
|
| "/test.dart",
|
| @@ -1406,12 +1818,57 @@ main() {}''');
|
| expect(context.isServerLibrary(source), isFalse);
|
| }
|
|
|
| - void test_parseCompilationUnit_errors() {
|
| - Source source = addSource("/lib.dart", "library {");
|
| - CompilationUnit compilationUnit = context.parseCompilationUnit(source);
|
| - expect(compilationUnit, isNotNull);
|
| - var errorInfo = context.getErrors(source);
|
| - expect(errorInfo, isNotNull);
|
| + void test_isServerLibrary_unknown() {
|
| + Source source = newSource("/test.dart");
|
| + expect(context.isServerLibrary(source), isFalse);
|
| + }
|
| +
|
| + void test_onResultInvalidated_removeSource() {
|
| + Source source = addSource('/test.dart', 'main() {}');
|
| + _analyzeAll_assertFinished();
|
| + // listen for changes
|
| + bool listenerInvoked = false;
|
| + context.onResultChanged(RESOLVED_UNIT).listen((ResultChangedEvent event) {
|
| + Source eventSource = event.target.source;
|
| + expect(event.wasComputed, isFalse);
|
| + expect(event.wasInvalidated, isTrue);
|
| + expect(event.descriptor, RESOLVED_UNIT);
|
| + expect(eventSource, source);
|
| + listenerInvoked = true;
|
| + });
|
| + // apply changes
|
| + expect(listenerInvoked, false);
|
| + context.applyChanges(new ChangeSet()..removedSource(source));
|
| + // verify
|
| + expect(listenerInvoked, isTrue);
|
| + }
|
| +
|
| + void test_onResultInvalidated_setContents() {
|
| + Source source = addSource('/test.dart', 'main() {}');
|
| + _analyzeAll_assertFinished();
|
| + // listen for changes
|
| + bool listenerInvoked = false;
|
| + context.onResultChanged(RESOLVED_UNIT).listen((ResultChangedEvent event) {
|
| + Source eventSource = event.target.source;
|
| + expect(event.wasComputed, isFalse);
|
| + expect(event.wasInvalidated, isTrue);
|
| + expect(event.descriptor, RESOLVED_UNIT);
|
| + expect(eventSource, source);
|
| + listenerInvoked = true;
|
| + });
|
| + // apply changes
|
| + expect(listenerInvoked, false);
|
| + context.setContents(source, 'class B {}');
|
| + // verify
|
| + expect(listenerInvoked, isTrue);
|
| + }
|
| +
|
| + void test_parseCompilationUnit_errors() {
|
| + Source source = addSource("/lib.dart", "library {");
|
| + CompilationUnit compilationUnit = context.parseCompilationUnit(source);
|
| + expect(compilationUnit, isNotNull);
|
| + var errorInfo = context.getErrors(source);
|
| + expect(errorInfo, isNotNull);
|
| List<AnalysisError> errors = errorInfo.errors;
|
| expect(errors, isNotNull);
|
| expect(errors.length > 0, isTrue);
|
| @@ -1485,7 +1942,7 @@ class ClassA {}''');
|
| CompilationUnit unit = context.computeResult(scripts[0], PARSED_UNIT);
|
| ImportDirective importNode = unit.directives[0] as ImportDirective;
|
| expect(importNode.uriContent, isNotNull);
|
| - expect(importNode.source, libSource);
|
| + expect(importNode.uriSource, libSource);
|
| }
|
|
|
| void test_performAnalysisTask_addPart() {
|
| @@ -1662,7 +2119,7 @@ void g() { f(null); }''');
|
| reason: "part resolved 1");
|
| // update and analyze #1
|
| context.setContents(partSource, "part of lib; // 1");
|
| - if (AnalysisEngine.instance.limitInvalidationInTaskModel) {
|
| + if (context.analysisOptions.finerGrainedInvalidation) {
|
| expect(
|
| context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
|
| reason: "library changed 2");
|
| @@ -1684,7 +2141,7 @@ void g() { f(null); }''');
|
| }
|
| // update and analyze #2
|
| context.setContents(partSource, "part of lib; // 12");
|
| - if (AnalysisEngine.instance.limitInvalidationInTaskModel) {
|
| + if (context.analysisOptions.finerGrainedInvalidation) {
|
| expect(
|
| context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
|
| reason: "library changed 3");
|
| @@ -1807,6 +2264,31 @@ void g() { f(null); }''');
|
| reason: "libA has an error");
|
| }
|
|
|
| + void test_performAnalysisTask_interruptBy_setContents() {
|
| + Source sourceA = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +library expectedToFindSemicolon
|
| +''');
|
| + // Analyze to the point where some of the results stop depending on
|
| + // the source content.
|
| + LibrarySpecificUnit unitA = new LibrarySpecificUnit(sourceA, sourceA);
|
| + for (int i = 0; i < 10000; i++) {
|
| + context.performAnalysisTask();
|
| + if (context.getResult(unitA, RESOLVED_UNIT3) != null) {
|
| + break;
|
| + }
|
| + }
|
| + // Update the source.
|
| + // This should invalidate all the results and also reset the driver.
|
| + context.setContents(sourceA, "library semicolonWasAdded;");
|
| + expect(context.getResult(unitA, RESOLVED_UNIT3), isNull);
|
| + expect(analysisDriver.currentWorkOrder, isNull);
|
| + // Continue analysis.
|
| + _analyzeAll_assertFinished();
|
| + expect(context.getErrors(sourceA).errors, isEmpty);
|
| + }
|
| +
|
| void test_performAnalysisTask_IOException() {
|
| TestSource source = _addSourceWithException2("/test.dart", "library test;");
|
| source.generateExceptionOnRead = false;
|
| @@ -1815,7 +2297,7 @@ void g() { f(null); }''');
|
| _changeSource(source, "");
|
| source.generateExceptionOnRead = true;
|
| _analyzeAll_assertFinished();
|
| - if (AnalysisEngine.instance.limitInvalidationInTaskModel) {
|
| + if (context.analysisOptions.finerGrainedInvalidation) {
|
| expect(source.readCount, 7);
|
| } else {
|
| expect(source.readCount, 5);
|
| @@ -1848,20 +2330,26 @@ void g() { f(null); }''');
|
| // JUnitTestCase.assertNotNullMsg("performAnalysisTask failed to compute an element model", _context.getLibraryElement(source));
|
| }
|
|
|
| - void test_performAnalysisTask_onResultComputed() {
|
| + void test_performAnalysisTask_onResultChanged() {
|
| Set<String> libraryElementUris = new Set<String>();
|
| Set<String> parsedUnitUris = new Set<String>();
|
| Set<String> resolvedUnitUris = new Set<String>();
|
| // listen
|
| - context.onResultComputed(LIBRARY_ELEMENT).listen((event) {
|
| + context.onResultChanged(LIBRARY_ELEMENT).listen((event) {
|
| + expect(event.wasComputed, isTrue);
|
| + expect(event.wasInvalidated, isFalse);
|
| Source librarySource = event.target;
|
| libraryElementUris.add(librarySource.uri.toString());
|
| });
|
| - context.onResultComputed(PARSED_UNIT).listen((event) {
|
| + context.onResultChanged(PARSED_UNIT).listen((event) {
|
| + expect(event.wasComputed, isTrue);
|
| + expect(event.wasInvalidated, isFalse);
|
| Source source = event.target;
|
| parsedUnitUris.add(source.uri.toString());
|
| });
|
| - context.onResultComputed(RESOLVED_UNIT).listen((event) {
|
| + context.onResultChanged(RESOLVED_UNIT).listen((event) {
|
| + expect(event.wasComputed, isTrue);
|
| + expect(event.wasInvalidated, isFalse);
|
| LibrarySpecificUnit target = event.target;
|
| Source librarySource = target.library;
|
| resolvedUnitUris.add(librarySource.uri.toString());
|
| @@ -1870,14 +2358,132 @@ void g() { f(null); }''');
|
| addSource('/test.dart', 'main() {}');
|
| _analyzeAll_assertFinished();
|
| // verify
|
| - expect(libraryElementUris, contains('dart:core'));
|
| expect(libraryElementUris, contains('file:///test.dart'));
|
| - expect(parsedUnitUris, contains('dart:core'));
|
| expect(parsedUnitUris, contains('file:///test.dart'));
|
| - expect(resolvedUnitUris, contains('dart:core'));
|
| expect(resolvedUnitUris, contains('file:///test.dart'));
|
| }
|
|
|
| + void test_performAnalysisTask_switchPackageVersion() {
|
| + // version 1
|
| + resourceProvider.newFile(
|
| + '/pkgs/crypto-1/lib/crypto.dart',
|
| + r'''
|
| +library crypto;
|
| +part 'src/hash_utils.dart';
|
| +''');
|
| + resourceProvider.newFile(
|
| + '/pkgs/crypto-1/lib/src/hash_utils.dart',
|
| + r'''
|
| +part of crypto;
|
| +const _MASK_8 = 0xff;
|
| +''');
|
| + // version 2
|
| + resourceProvider.newFile(
|
| + '/pkgs/crypto-2/lib/crypto.dart',
|
| + r'''
|
| +library crypto;
|
| +part 'src/hash_utils.dart';
|
| +''');
|
| + resourceProvider.newFile(
|
| + '/pkgs/crypto-2/lib/src/hash_utils.dart',
|
| + r'''
|
| +part of crypto;
|
| +const _MASK_8 = 0xff;
|
| +''');
|
| + // use version 1
|
| + context.sourceFactory = new SourceFactory(<UriResolver>[
|
| + sdkResolver,
|
| + resourceResolver,
|
| + new PackageMapUriResolver(resourceProvider, {
|
| + 'crypto': [resourceProvider.getFolder('/pkgs/crypto-1/lib')]
|
| + })
|
| + ]);
|
| + // analyze
|
| + addSource(
|
| + "/test.dart",
|
| + r'''
|
| +import 'package:crypto/crypto.dart';
|
| +''');
|
| + _analyzeAll_assertFinished();
|
| + // use version 2
|
| + context.sourceFactory = new SourceFactory(<UriResolver>[
|
| + sdkResolver,
|
| + resourceResolver,
|
| + new PackageMapUriResolver(resourceProvider, {
|
| + 'crypto': [resourceProvider.getFolder('/pkgs/crypto-2/lib')]
|
| + })
|
| + ]);
|
| + _analyzeAll_assertFinished();
|
| + _assertNoExceptions();
|
| + }
|
| +
|
| + void test_resolveCompilationUnit_existingElementModel() {
|
| + Source source = addSource(
|
| + '/test.dart',
|
| + r'''
|
| +library test;
|
| +
|
| +String topLevelVariable;
|
| +int get topLevelGetter => 0;
|
| +void set topLevelSetter(int value) {}
|
| +String topLevelFunction(int i) => '';
|
| +
|
| +typedef String FunctionTypeAlias(int i);
|
| +
|
| +enum EnumeratedType {Invalid, Valid}
|
| +
|
| +class ClassOne {
|
| + int instanceField;
|
| + static int staticField;
|
| +
|
| + ClassOne();
|
| + ClassOne.named();
|
| +
|
| + int get instanceGetter => 0;
|
| + static String get staticGetter => '';
|
| +
|
| + void set instanceSetter(int value) {}
|
| + static void set staticSetter(int value) {}
|
| +
|
| + int instanceMethod(int first, [int second = 0]) {
|
| + int localVariable;
|
| + int localFunction(String s) {}
|
| + }
|
| + static String staticMethod(int first, {int second: 0}) => '';
|
| +}
|
| +
|
| +class ClassTwo {
|
| + // Implicit no-argument constructor
|
| +}
|
| +''');
|
| + context.resolveCompilationUnit2(source, source);
|
| + LibraryElement firstElement = context.computeLibraryElement(source);
|
| + _ElementGatherer gatherer = new _ElementGatherer();
|
| + firstElement.accept(gatherer);
|
| +
|
| + CacheEntry entry =
|
| + context.analysisCache.get(new LibrarySpecificUnit(source, source));
|
| + entry.setState(RESOLVED_UNIT1, CacheState.FLUSHED);
|
| + entry.setState(RESOLVED_UNIT2, CacheState.FLUSHED);
|
| + entry.setState(RESOLVED_UNIT3, CacheState.FLUSHED);
|
| + entry.setState(RESOLVED_UNIT4, CacheState.FLUSHED);
|
| + entry.setState(RESOLVED_UNIT5, CacheState.FLUSHED);
|
| + entry.setState(RESOLVED_UNIT6, CacheState.FLUSHED);
|
| + entry.setState(RESOLVED_UNIT7, CacheState.FLUSHED);
|
| + entry.setState(RESOLVED_UNIT8, CacheState.FLUSHED);
|
| + entry.setState(RESOLVED_UNIT9, CacheState.FLUSHED);
|
| + entry.setState(RESOLVED_UNIT10, CacheState.FLUSHED);
|
| + entry.setState(RESOLVED_UNIT11, CacheState.FLUSHED);
|
| + entry.setState(RESOLVED_UNIT12, CacheState.FLUSHED);
|
| + entry.setState(RESOLVED_UNIT, CacheState.FLUSHED);
|
| +
|
| + context.resolveCompilationUnit2(source, source);
|
| + LibraryElement secondElement = context.computeLibraryElement(source);
|
| + _ElementComparer comparer = new _ElementComparer(gatherer.elements);
|
| + secondElement.accept(comparer);
|
| + comparer.expectNoDifferences();
|
| + }
|
| +
|
| void test_resolveCompilationUnit_import_relative() {
|
| Source sourceA =
|
| addSource("/libA.dart", "library libA; import 'libB.dart'; class A{}");
|
| @@ -1888,9 +2494,6 @@ void g() { f(null); }''');
|
| LibraryElement library = compilationUnit.element.library;
|
| List<LibraryElement> importedLibraries = library.importedLibraries;
|
| assertNamedElements(importedLibraries, ["dart.core", "libB"]);
|
| - List<LibraryElement> visibleLibraries = library.visibleLibraries;
|
| - assertNamedElements(visibleLibraries,
|
| - ["dart.core", "dart.async", "dart.math", "libA", "libB"]);
|
| }
|
|
|
| void test_resolveCompilationUnit_import_relative_cyclic() {
|
| @@ -1903,18 +2506,6 @@ void g() { f(null); }''');
|
| LibraryElement library = compilationUnit.element.library;
|
| List<LibraryElement> importedLibraries = library.importedLibraries;
|
| assertNamedElements(importedLibraries, ["dart.core", "libB"]);
|
| - List<LibraryElement> visibleLibraries = library.visibleLibraries;
|
| - assertNamedElements(visibleLibraries,
|
| - ["dart.core", "dart.async", "dart.math", "libA", "libB"]);
|
| - }
|
| -
|
| - void test_resolveCompilationUnit_library() {
|
| - Source source = addSource("/lib.dart", "library lib;");
|
| - LibraryElement library = context.computeLibraryElement(source);
|
| - CompilationUnit compilationUnit =
|
| - context.resolveCompilationUnit(source, library);
|
| - expect(compilationUnit, isNotNull);
|
| - expect(compilationUnit.element, isNotNull);
|
| }
|
|
|
| // void test_resolveCompilationUnit_sourceChangeDuringResolution() {
|
| @@ -1928,6 +2519,15 @@ void g() { f(null); }''');
|
| // expect(_context.getLineInfo(source), isNotNull);
|
| // }
|
|
|
| + void test_resolveCompilationUnit_library() {
|
| + Source source = addSource("/lib.dart", "library lib;");
|
| + LibraryElement library = context.computeLibraryElement(source);
|
| + CompilationUnit compilationUnit =
|
| + context.resolveCompilationUnit(source, library);
|
| + expect(compilationUnit, isNotNull);
|
| + expect(compilationUnit.element, isNotNull);
|
| + }
|
| +
|
| void test_resolveCompilationUnit_source() {
|
| Source source = addSource("/lib.dart", "library lib;");
|
| CompilationUnit compilationUnit =
|
| @@ -2112,7 +2712,7 @@ int a = 0;''');
|
| expect(context.sourcesNeedingProcessing.contains(source), isFalse);
|
| }
|
|
|
| - void test_validateCacheConsistency_deletedSource() {
|
| + void test_validateCacheConsistency_deletedFile() {
|
| MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
|
| var fileA = resourceProvider.newFile('/a.dart', "");
|
| var fileB = resourceProvider.newFile('/b.dart', "import 'a.dart';");
|
| @@ -2178,15 +2778,30 @@ int a = 0;''');
|
| for (int i = 0; i < maxIterations; i++) {
|
| List<ChangeNotice> notice = context.performAnalysisTask().changeNotices;
|
| if (notice == null) {
|
| - bool inconsistent = context.validateCacheConsistency();
|
| - if (!inconsistent) {
|
| - return;
|
| - }
|
| + return;
|
| }
|
| }
|
| fail("performAnalysisTask failed to terminate after analyzing all sources");
|
| }
|
|
|
| + void _assertNoExceptions() {
|
| + MapIterator<AnalysisTarget, CacheEntry> iterator = analysisCache.iterator();
|
| + String exceptionsStr = '';
|
| + while (iterator.moveNext()) {
|
| + CaughtException exception = iterator.value.exception;
|
| + if (exception != null) {
|
| + AnalysisTarget target = iterator.key;
|
| + exceptionsStr +=
|
| + '============= key: $target source: ${target.source}\n';
|
| + exceptionsStr += exception.toString();
|
| + exceptionsStr += '\n';
|
| + }
|
| + }
|
| + if (exceptionsStr.isNotEmpty) {
|
| + fail(exceptionsStr);
|
| + }
|
| + }
|
| +
|
| void _changeSource(TestSource source, String contents) {
|
| source.setContents(contents);
|
| ChangeSet changeSet = new ChangeSet();
|
| @@ -2255,301 +2870,2254 @@ int a = 0;''');
|
| class LimitedInvalidateTest extends AbstractContextTest {
|
| @override
|
| void setUp() {
|
| - AnalysisEngine.instance.limitInvalidationInTaskModel = true;
|
| super.setUp();
|
| AnalysisOptionsImpl options =
|
| new AnalysisOptionsImpl.from(context.analysisOptions);
|
| options.incremental = true;
|
| + options.finerGrainedInvalidation = true;
|
| context.analysisOptions = options;
|
| }
|
|
|
| - @override
|
| - void tearDown() {
|
| - AnalysisEngine.instance.limitInvalidationInTaskModel = false;
|
| - super.tearDown();
|
| + void test_applyChanges_changedSource_removeFile() {
|
| + File file = resourceProvider.newFile('/test.dart', 'main() {}');
|
| + Source source = file.createSource();
|
| + context.applyChanges(new ChangeSet()..addedSource(source));
|
| + // Analyze all.
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getResolvedCompilationUnit2(source, source), isNotNull);
|
| + // Delete the file, but tell the context that it is changed.
|
| + // This might happen as a race condition.
|
| + // Or it might be a mishandling of file notification events.
|
| + file.delete();
|
| + context.applyChanges(new ChangeSet()..changedSource(source));
|
| + // All the analysis results are gone.
|
| + void noResolvedUnits() {
|
| + LibrarySpecificUnit unit = new LibrarySpecificUnit(source, source);
|
| + RESOLVED_UNIT_RESULTS.forEach((result) {
|
| + expect(context.getResult(unit, result), isNull);
|
| + });
|
| + }
|
| +
|
| + noResolvedUnits();
|
| + // Analyze again.
|
| + // The source does not exist, so still no resolution.
|
| + _performPendingAnalysisTasks();
|
| + noResolvedUnits();
|
| + expect(context.getModificationStamp(source), -1);
|
| }
|
|
|
| - void test_noChange_thenChange() {
|
| - Source sourceA = addSource(
|
| - "/a.dart",
|
| + void test_class_addMethod_useAsHole_inTopLevelVariable() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| r'''
|
| -library lib_a;
|
| -
|
| class A {
|
| - A();
|
| -}
|
| -class B {
|
| - B();
|
| }
|
| ''');
|
| - Source sourceB = addSource(
|
| - "/b.dart",
|
| + Source b = addSource(
|
| + '/b.dart',
|
| r'''
|
| -library lib_b;
|
| import 'a.dart';
|
| -main() {
|
| - new A();
|
| -}
|
| +var B = A.foo;
|
| ''');
|
| - _performPendingAnalysisTasks();
|
| - expect(context.getErrors(sourceA).errors, hasLength(0));
|
| - expect(context.getErrors(sourceB).errors, hasLength(0));
|
| - var unitA = context.getResolvedCompilationUnit2(sourceA, sourceA);
|
| - var unitElementA = unitA.element;
|
| - var libraryElementA = unitElementA.library;
|
| - // Update a.dart, no declaration changes.
|
| - context.setContents(
|
| - sourceA,
|
| + Source c = addSource(
|
| + '/c.dart',
|
| r'''
|
| -library lib_a;
|
| -class A {
|
| - A();
|
| -}
|
| -class B {
|
| - B();
|
| -}
|
| +import 'b.dart';
|
| +var C = B;
|
| ''');
|
| - _assertInvalid(sourceA, LIBRARY_ERRORS_READY);
|
| - _assertValid(sourceB, LIBRARY_ELEMENT);
|
| - // The a.dart's unit and element are updated incrementally.
|
| - // They are the same instances as initially.
|
| - // So, all the references from other units are still valid.
|
| - {
|
| - LibrarySpecificUnit target = new LibrarySpecificUnit(sourceA, sourceA);
|
| - expect(analysisCache.getValue(target, RESOLVED_UNIT1), same(unitA));
|
| - expect(unitA.element, same(unitElementA));
|
| - expect(unitElementA.library, same(libraryElementA));
|
| - }
|
| - // Analyze.
|
| _performPendingAnalysisTasks();
|
| - expect(context.getErrors(sourceA).errors, hasLength(0));
|
| - expect(context.getErrors(sourceB).errors, hasLength(0));
|
| - // The a.dart's unit and element are the same.
|
| - {
|
| - LibrarySpecificUnit target = new LibrarySpecificUnit(sourceA, sourceA);
|
| - expect(analysisCache.getValue(target, RESOLVED_UNIT), same(unitA));
|
| - expect(unitA.element, same(unitElementA));
|
| - expect(unitElementA.library, same(libraryElementA));
|
| - }
|
| - // Update a.dart, rename A to A2, invalidates b.dart, so
|
| - // we know that the previous update did not damage dependencies.
|
| + expect(context.getErrors(b).errors, hasLength(1));
|
| + // Update a.dart: add A.foo.
|
| + // 'B' in b.dart is invalid, because 'B' references 'foo'
|
| + // c.dart is invalid, because 'C' references 'B'
|
| context.setContents(
|
| - sourceA,
|
| + a,
|
| r'''
|
| -library lib_a;
|
| class A {
|
| - A();
|
| - m() {}
|
| -}
|
| -class B {
|
| - B();
|
| + static void foo(int p) {}
|
| }
|
| ''');
|
| - _assertInvalid(sourceA, LIBRARY_ERRORS_READY);
|
| - _assertInvalid(sourceB, LIBRARY_ELEMENT);
|
| - // The a.dart's unit and element are the same.
|
| - {
|
| - LibrarySpecificUnit target = new LibrarySpecificUnit(sourceA, sourceA);
|
| - expect(analysisCache.getValue(target, RESOLVED_UNIT1), same(unitA));
|
| - expect(unitA.element, same(unitElementA));
|
| - expect(unitElementA.library, same(libraryElementA));
|
| - }
|
| - // Analyze.
|
| - _performPendingAnalysisTasks();
|
| - expect(context.getErrors(sourceA).errors, hasLength(0));
|
| - expect(context.getErrors(sourceB).errors, hasLength(0));
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| +
|
| + _assertValidForDependentLibrary(b);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertInvalidUnits(b, RESOLVED_UNIT4);
|
| +
|
| + _assertValidForDependentLibrary(c);
|
| + _assertInvalid(c, LIBRARY_ERRORS_READY);
|
| + _assertInvalidUnits(c, RESOLVED_UNIT4);
|
| }
|
|
|
| - void test_unusedName() {
|
| - Source sourceA = addSource(
|
| - "/a.dart",
|
| + void test_class_addMethod_useClass() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| r'''
|
| -library lib_a;
|
| class A {}
|
| -class B {}
|
| -class C {}
|
| +class B extends A {
|
| + foo() {}
|
| +}
|
| ''');
|
| - Source sourceB = addSource(
|
| - "/b.dart",
|
| + Source b = addSource(
|
| + '/b.dart',
|
| r'''
|
| -library lib_b;
|
| import 'a.dart';
|
| -main() {
|
| - new A();
|
| - new C();
|
| -}
|
| +B b = null;
|
| ''');
|
| _performPendingAnalysisTasks();
|
| - // Update A.
|
| + // Update a.dart: remove add A.bar.
|
| + // b.dart is valid, because though it uses A, it has the same element.
|
| context.setContents(
|
| - sourceA,
|
| + a,
|
| r'''
|
| -library lib_a;
|
| class A {}
|
| -class B2 {}
|
| -class C {}
|
| +class B extends A {
|
| + foo() {}
|
| + bar() {}
|
| +}
|
| ''');
|
| - // Only a.dart is invalidated.
|
| - // Because b.dart does not use B, so it is valid.
|
| - _assertInvalid(sourceA, LIBRARY_ERRORS_READY);
|
| - _assertValid(sourceB, LIBRARY_ERRORS_READY);
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertValidAllLibraryUnitResults(b);
|
| + _assertValid(b, LIBRARY_ERRORS_READY);
|
| }
|
|
|
| - void test_usedName_directUser() {
|
| - Source sourceA = addSource(
|
| - "/a.dart",
|
| + void test_class_annotation_add_deprecated() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| r'''
|
| -library lib_a;
|
| class A {}
|
| -class B {}
|
| -class C {}
|
| ''');
|
| - Source sourceB = addSource(
|
| - "/b.dart",
|
| + Source b = addSource(
|
| + '/b.dart',
|
| r'''
|
| -library lib_b;
|
| import 'a.dart';
|
| -main() {
|
| - new A();
|
| - new C2();
|
| -}
|
| +List<A> foo() => [];
|
| ''');
|
| _performPendingAnalysisTasks();
|
| - expect(context.getErrors(sourceB).errors, hasLength(1));
|
| - // Update a.dart, invalidates b.dart because it references "C2".
|
| + expect(context.getErrors(b).errors, hasLength(0));
|
| + // Add @deprecated annotation.
|
| + // b.dart has valid resolution, because A is still A, so only errors are
|
| + // invalidated.
|
| context.setContents(
|
| - sourceA,
|
| + a,
|
| r'''
|
| -library lib_a;
|
| +@deprecated
|
| class A {}
|
| -class B {}
|
| -class C2 {}
|
| ''');
|
| - _assertInvalid(sourceA, LIBRARY_ERRORS_READY);
|
| - _assertInvalid(sourceB, LIBRARY_ERRORS_READY);
|
| - // Now b.dart is analyzed and the error is fixed.
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertValidAllResolution(b);
|
| + // Analysis is done successfully.
|
| + _performPendingAnalysisTasks();
|
| + _assertValid(a, LIBRARY_ERRORS_READY);
|
| + _assertValid(a, READY_RESOLVED_UNIT);
|
| + _assertValid(b, LIBRARY_ERRORS_READY);
|
| + _assertValid(b, READY_RESOLVED_UNIT);
|
| + expect(context.getErrors(b).errors, hasLength(1));
|
| + }
|
| +
|
| + void test_class_annotation_remove_deprecated() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +@deprecated
|
| +class A {}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +List<A> foo() => [];
|
| +''');
|
| _performPendingAnalysisTasks();
|
| - expect(context.getErrors(sourceB).errors, hasLength(0));
|
| - // Update a.dart, invalidates b.dart because it references "C".
|
| + expect(context.getErrors(b).errors, hasLength(1));
|
| + // Add @deprecated annotation.
|
| + // b.dart has valid resolution, because A is still A, so only errors are
|
| + // invalidated.
|
| context.setContents(
|
| - sourceA,
|
| + a,
|
| r'''
|
| -library lib_a;
|
| class A {}
|
| -class B {}
|
| -class C {}
|
| ''');
|
| - _assertInvalid(sourceA, LIBRARY_ERRORS_READY);
|
| - _assertInvalid(sourceB, LIBRARY_ERRORS_READY);
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertValidAllResolution(b);
|
| + // Analysis is done successfully.
|
| _performPendingAnalysisTasks();
|
| - // Now b.dart is analyzed and it again has the error.
|
| - expect(context.getErrors(sourceB).errors, hasLength(1));
|
| + _assertValid(a, LIBRARY_ERRORS_READY);
|
| + _assertValid(a, READY_RESOLVED_UNIT);
|
| + _assertValid(b, LIBRARY_ERRORS_READY);
|
| + _assertValid(b, READY_RESOLVED_UNIT);
|
| + expect(context.getErrors(b).errors, hasLength(0));
|
| }
|
|
|
| - void test_usedName_directUser_withIncremental() {
|
| - Source sourceA = addSource(
|
| - "/a.dart",
|
| + void test_class_constructor_named_changeName() {
|
| + // Update a.dart: change A.named() to A.named2().
|
| + // b.dart is invalid, because it references A.named().
|
| + _verifyTwoLibrariesInvalidatesResolution(
|
| r'''
|
| -library lib_a;
|
| class A {
|
| - m() {}
|
| + A.named();
|
| }
|
| -''');
|
| - Source sourceB = addSource(
|
| - "/b.dart",
|
| +''',
|
| + r'''
|
| +class A {
|
| + A.named2();
|
| +}
|
| +''',
|
| r'''
|
| -library lib_b;
|
| import 'a.dart';
|
| main() {
|
| - A a = new A();
|
| - a.m();
|
| + new A.named();
|
| }
|
| ''');
|
| - _performPendingAnalysisTasks();
|
| - // Update A.
|
| - context.setContents(
|
| - sourceA,
|
| + }
|
| +
|
| + void test_class_constructor_named_parameters_add() {
|
| + // Update a.dart: add a new parameter to A.named().
|
| + // b.dart is invalid, because it references A.named().
|
| + _verifyTwoLibrariesInvalidatesResolution(
|
| r'''
|
| -library lib_a;
|
| class A {
|
| - m2() {}
|
| + A.named();
|
| +}
|
| +''',
|
| + r'''
|
| +class A {
|
| + A.named(int p);
|
| +}
|
| +''',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + new A.named();
|
| }
|
| ''');
|
| - _assertInvalid(sourceA, LIBRARY_ERRORS_READY);
|
| - _assertInvalid(sourceB, LIBRARY_ERRORS_READY);
|
| }
|
|
|
| - void test_usedName_indirectUser() {
|
| - Source sourceA = addSource(
|
| - "/a.dart",
|
| + void test_class_constructor_named_parameters_change_usedSuper() {
|
| + // Update a.dart: change A.named().
|
| + // b.dart is invalid, because it references A.named().
|
| + _verifyTwoLibrariesInvalidatesResolution(
|
| r'''
|
| -library lib_a;
|
| class A {
|
| - m() {}
|
| + A.named(int a);
|
| }
|
| -''');
|
| - Source sourceB = addSource(
|
| - "/b.dart",
|
| +''',
|
| + r'''
|
| +class A {
|
| + A.named(String a);
|
| +}
|
| +''',
|
| r'''
|
| -library lib_b;
|
| import 'a.dart';
|
| -class B extends A {}
|
| +class B extends A {
|
| + B() : super.named(42);
|
| +}
|
| ''');
|
| - Source sourceC = addSource(
|
| - "/c.dart",
|
| - r'''
|
| -library lib_c;
|
| -import 'b.dart';
|
| -class C extends B {
|
| - main() {
|
| - m();
|
| }
|
| +
|
| + void test_class_constructor_named_parameters_remove() {
|
| + // Update a.dart: remove a new parameter of A.named().
|
| + // b.dart is invalid, because it references A.named().
|
| + _verifyTwoLibrariesInvalidatesResolution(
|
| + r'''
|
| +class A {
|
| + A.named(int p);
|
| }
|
| -''');
|
| - // No errors, "A.m" exists.
|
| - _performPendingAnalysisTasks();
|
| - expect(context.getErrors(sourceC).errors, hasLength(0));
|
| - // Replace "A.m" with "A.m2", invalidate both b.dart and c.dart files.
|
| - context.setContents(
|
| - sourceA,
|
| +''',
|
| r'''
|
| -library lib_a;
|
| class A {
|
| - m2() {}
|
| + A.named();
|
| +}
|
| +''',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + new A.named();
|
| }
|
| ''');
|
| - _assertInvalid(sourceA, LIBRARY_ERRORS_READY);
|
| - _assertInvalid(sourceB, LIBRARY_ERRORS_READY);
|
| - _assertInvalid(sourceC, LIBRARY_ERRORS_READY);
|
| - // There is an error in c.dart, "A.m" does not exist.
|
| - _performPendingAnalysisTasks();
|
| - expect(context.getErrors(sourceB).errors, hasLength(0));
|
| - expect(context.getErrors(sourceC).errors, hasLength(1));
|
| - // Restore "A.m", invalidate both b.dart and c.dart files.
|
| - context.setContents(
|
| - sourceA,
|
| + }
|
| +
|
| + void test_class_constructor_named_remove_notUsed() {
|
| + // Update a.dart: remove A.foo().
|
| + // b.dart is valid, because it does not reference A.foo().
|
| + _verifyTwoLibrariesAllValid(
|
| r'''
|
| -library lib_a;
|
| class A {
|
| - m() {}
|
| + A.foo();
|
| + A.bar();
|
| +}
|
| +''',
|
| + r'''
|
| +class A {
|
| + A.bar();
|
| +}
|
| +''',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + new A.bar();
|
| }
|
| ''');
|
| - _assertInvalid(sourceA, LIBRARY_ERRORS_READY);
|
| - _assertInvalid(sourceB, LIBRARY_ERRORS_READY);
|
| - _assertInvalid(sourceC, LIBRARY_ERRORS_READY);
|
| - // No errors, "A.m" exists.
|
| - _performPendingAnalysisTasks();
|
| - expect(context.getErrors(sourceC).errors, hasLength(0));
|
| }
|
|
|
| - void _assertInvalid(AnalysisTarget target, ResultDescriptor descriptor) {
|
| - CacheState state = analysisCache.getState(target, descriptor);
|
| - expect(state, CacheState.INVALID);
|
| + void test_class_constructor_named_remove_used() {
|
| + // Update a.dart: remove A.named().
|
| + // b.dart is invalid, because it references A.named().
|
| + _verifyTwoLibrariesInvalidatesResolution(
|
| + r'''
|
| +class A {
|
| + A.named();
|
| +}
|
| +''',
|
| + r'''
|
| +class A {
|
| +}
|
| +''',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + new A.named();
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_class_constructor_unnamed_parameters_change_notUsedSuper() {
|
| + // Update a.dart: change A().
|
| + // Resolution of b.dart is valid, because it does not reference A().
|
| + // Hints and verify errors are invalid, because it extends A.
|
| + // TODO(scheglov) we could keep valid hints and verify errors,
|
| + // because only constructor is changed - this cannot add/remove
|
| + // inherited unimplemented members.
|
| + _verifyTwoLibrariesInvalidHintsVerifyErrors(
|
| + r'''
|
| +class A {
|
| + A(int a);
|
| + A.named(int a);
|
| +}
|
| +''',
|
| + r'''
|
| +class A {
|
| + A(String a);
|
| + A.named(int a);
|
| +}
|
| +''',
|
| + r'''
|
| +import 'a.dart';
|
| +class B extends A {
|
| + B() : super.named(42);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_class_constructor_unnamed_parameters_change_usedSuper() {
|
| + // Update a.dart: change A().
|
| + // b.dart is invalid, because it references A().
|
| + _verifyTwoLibrariesInvalidatesResolution(
|
| + r'''
|
| +class A {
|
| + A(int a);
|
| +}
|
| +''',
|
| + r'''
|
| +class A {
|
| + A(String a);
|
| +}
|
| +''',
|
| + r'''
|
| +import 'a.dart';
|
| +class B extends A {
|
| + B() : super(42);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_class_constructor_unnamed_parameters_remove() {
|
| + // Update a.dart: change A().
|
| + // b.dart is invalid, because it references A().
|
| + _verifyTwoLibrariesInvalidatesResolution(
|
| + r'''
|
| +class A {
|
| + A(int a, int b);
|
| +}
|
| +''',
|
| + r'''
|
| +class A {
|
| + A(int a);
|
| +}
|
| +''',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + new A(1, 2);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_class_constructor_unnamed_remove_notUsed() {
|
| + // Update a.dart: remove A().
|
| + // b.dart is invalid, because it instantiates A.
|
| + _verifyTwoLibrariesInvalidatesResolution(
|
| + r'''
|
| +class A {
|
| + A();
|
| + A.named();
|
| +}
|
| +''',
|
| + r'''
|
| +class A {
|
| + A.named();
|
| +}
|
| +''',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + new A.named();
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_class_constructor_unnamed_remove_used() {
|
| + // Update a.dart: remove A().
|
| + // b.dart is invalid, because it references A().
|
| + _verifyTwoLibrariesInvalidatesResolution(
|
| + r'''
|
| +class A {
|
| + A();
|
| +}
|
| +''',
|
| + r'''
|
| +class A {
|
| +}
|
| +''',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + new A();
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_class_method_change_notUsed() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {
|
| + foo() {}
|
| + bar() {}
|
| +}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main(A a) {
|
| + a.foo();
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart: remove A.bar, add A.bar2.
|
| + // b.dart is valid, because it doesn't references 'bar' or 'bar2'.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {
|
| + foo() {}
|
| + bar2() {}
|
| +}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertValidAllLibraryUnitResults(b);
|
| + _assertValid(b, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void test_class_method_change_notUsed_throughSubclass_extends() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {
|
| + foo() {}
|
| + bar() {}
|
| +}
|
| +class B extends A {}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main(B b) {
|
| + a.foo();
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart: remove A.bar, add A.bar2.
|
| + // b.dart is valid, because it doesn't references 'bar' or 'bar2'.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {
|
| + foo() {}
|
| + bar2() {}
|
| +}
|
| +class B extends A {}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertValidAllLibraryUnitResults(b);
|
| + _assertValid(b, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void test_class_method_definedInSuper_sameLibrary() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {
|
| + m() {}
|
| +}
|
| +class B extends A {}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main(B b) {
|
| + b.m();
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart: change A.m
|
| + // This makes B changed.
|
| + // b.dart is invalid, because it references B.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {
|
| + m2() {}
|
| +}
|
| +class B extends A {}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void test_class_method_remove_notUsed_instantiated() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +abstract class I {
|
| + void foo();
|
| +}
|
| +class A implements I {
|
| + void foo() {}
|
| +}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + new A();
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart: remove 'A.foo'.
|
| + // b.dart is valid because it does not reference 'foo'.
|
| + // The class 'A' has a warning, but it is still not abstract.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +abstract class I {
|
| + void fo();
|
| +}
|
| +class A implements I {
|
| +}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| +
|
| + _assertValidForDependentLibrary(b);
|
| + _assertValidAllLibraryUnitResults(b);
|
| + _assertValidAllResolution(b);
|
| + _assertValidAllErrors(b);
|
| + }
|
| +
|
| + void test_class_method_remove_subclass() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +abstract class I {
|
| + void foo();
|
| +}
|
| +class A implements I {
|
| + void foo() {}
|
| +}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +class B extends A {}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart: remove A.bar, add A.bar2.
|
| + // b.dart
|
| + // Resolution is valid because 'foo' is not referenced.
|
| + // HINTS are invalid because 'B' might have invalid @override.
|
| + // VERIFY_ERRORS are invalid because 'B' might not implement something.
|
| + // Other errors are also invalid.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +abstract class I {
|
| + void foo();
|
| +}
|
| +class A implements I {
|
| +}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| +
|
| + _assertValidForDependentLibrary(b);
|
| + _assertValidAllResolution(b);
|
| + _assertInvalidHintsVerifyErrors(b);
|
| + }
|
| +
|
| + void test_class_private_member() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {
|
| + A();
|
| + A._privateConstructor();
|
| +
|
| + foo() {}
|
| +
|
| + int _privateField;
|
| + _privateMethod() {}
|
| + int get _privateGetter => null;
|
| + void set _privateSetter(_) {}
|
| +}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main(A a) {
|
| + a.foo();
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart: rename private members of A
|
| + // b.dart is valid, it cannot see these private members.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {
|
| + A();
|
| + A._privateConstructor2();
|
| +
|
| + foo() {}
|
| +
|
| + int _privateField2;
|
| + _privateMethod2() {}
|
| + int get _privateGetter2 => null;
|
| + void set _privateSetter2(_) {}
|
| +}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertValidAllLibraryUnitResults(b);
|
| + _assertValid(b, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void test_enum_add() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +main() {
|
| + print(MyEnum.A);
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Insert a new enum declaration.
|
| + // No errors expected.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +main() {
|
| + print(MyEnum.A);
|
| +}
|
| +enum MyEnum { A, B, C }
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(a).errors, isEmpty);
|
| + }
|
| +
|
| + void test_private_class() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class _A {}
|
| +class _B2 {}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + new _A();
|
| + new _B();
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart: change _A and _B2
|
| + // b.dart is valid, because _A, _B, _A2 and _B2 are all private,
|
| + // so b.dart cannot see them.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class _A2 {}
|
| +class _B {}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertValidAllLibraryUnitResults(b);
|
| + _assertValid(b, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void test_private_topLevelVariable() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +int _V = 1;
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + print(_A);
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart: change _V
|
| + // b.dart is valid, because _V is private and b.dart cannot see it.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +int _V = 2;
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertValidAllLibraryUnitResults(b);
|
| + _assertValid(b, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void test_private_topLevelVariable_throughPublic() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +int _A = 1;
|
| +int B = _A + 1;
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + print(B);
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart: change _A
|
| + // b.dart is invalid, because it uses B, which uses _A.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +int _A = 2;
|
| +int B = _A + 1;
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void test_sequence_applyChanges_changedSource() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {}
|
| +class B {}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + new A();
|
| + new B();
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + resourceProvider.updateFile(
|
| + '/a.dart',
|
| + r'''
|
| +class A2 {}
|
| +class B {}
|
| +''');
|
| + // Update a.dart: remove A, add A2.
|
| + // b.dart is invalid, because it references A.
|
| + var changeSet = new ChangeSet()..changedSource(a);
|
| + context.applyChanges(changeSet);
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertInvalidUnits(b, RESOLVED_UNIT4);
|
| + // Analyze.
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(a).errors, hasLength(0));
|
| + expect(context.getErrors(b).errors, hasLength(1));
|
| + _assertValid(a, READY_RESOLVED_UNIT);
|
| + _assertValid(b, READY_RESOLVED_UNIT);
|
| + _assertValidAllLibraryUnitResults(a);
|
| + _assertValidAllLibraryUnitResults(b);
|
| + }
|
| +
|
| + void test_sequence_class_give_take() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {}
|
| +class B {}
|
| +class C {}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + new A();
|
| + new C2();
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(b).errors, hasLength(1));
|
| + // Update a.dart: remove C, add C2.
|
| + // b.dart is invalid, because it references C2.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {}
|
| +class B {}
|
| +class C2 {}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertInvalidUnits(b, RESOLVED_UNIT4);
|
| + // Now b.dart is analyzed and the error is fixed.
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(b).errors, hasLength(0));
|
| + // Update a.dart: remove C2, add C.
|
| + // b.dart is invalid, because it references C2.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {}
|
| +class B {}
|
| +class C {}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertInvalidUnits(b, RESOLVED_UNIT4);
|
| + // Now b.dart is analyzed and it again has the error.
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(b).errors, hasLength(1));
|
| + }
|
| +
|
| + void test_sequence_class_removeMethod_overridden() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {
|
| + void foo() {}
|
| +}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +class B extends A {
|
| + @override
|
| + void foo() {}
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(b).errors, hasLength(0));
|
| + // Update a.dart: remove add A.foo.
|
| + // b.dart has a new hint, because B.foo does not override anything
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {
|
| +}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertValidAllResolution(b);
|
| + _assertInvalidHintsVerifyErrors(b);
|
| +
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(b).errors, hasLength(1));
|
| + }
|
| +
|
| + void test_sequence_clearParameterElements() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {
|
| + foo(int p) {}
|
| +}
|
| +final a = new A();
|
| +main() {
|
| + a.foo(42);
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + Expression find42() {
|
| + CompilationUnit unit =
|
| + context.getResult(new LibrarySpecificUnit(a, a), RESOLVED_UNIT);
|
| + ExpressionStatement statement =
|
| + AstFinder.getStatementsInTopLevelFunction(unit, 'main').single;
|
| + MethodInvocation invocation = statement.expression;
|
| + return invocation.argumentList.arguments[0];
|
| + }
|
| +
|
| + {
|
| + Expression argument = find42();
|
| + expect(argument.staticParameterElement, isNull);
|
| + }
|
| +
|
| + // Update a.dart: add type annotation for 'a'.
|
| + // '42' has 'staticParameterElement'.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {
|
| + foo(int p) {}
|
| +}
|
| +final A a = new A();
|
| +main() {
|
| + a.foo(42);
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + {
|
| + Expression argument = find42();
|
| + expect(argument.staticParameterElement, isNotNull);
|
| + }
|
| +
|
| + // Update a.dart: remove type annotation for 'a'.
|
| + // '42' doesn't have 'staticParameterElement'.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {
|
| + foo(int p) {}
|
| +}
|
| +final a = new A();
|
| +main() {
|
| + a.foo(42);
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + {
|
| + Expression argument = find42();
|
| + expect(argument.staticParameterElement, isNull);
|
| + }
|
| + }
|
| +
|
| + void test_sequence_closureParameterTypesPropagation() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +main() {
|
| + f((p) => 4.2);
|
| +}
|
| +f(c(int p)) {}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + LibrarySpecificUnit targetA = new LibrarySpecificUnit(a, a);
|
| + // Update and analyze.
|
| + String newCode = r'''
|
| +newFunction() {}
|
| +main() {
|
| + f((p) => 4.2);
|
| +}
|
| +f(c(int p)) {}
|
| +''';
|
| + context.setContents(a, newCode);
|
| + _performPendingAnalysisTasks();
|
| + // Validate "(p) => 4.2" types.
|
| + CompilationUnit unit = context.getResult(targetA, RESOLVED_UNIT2);
|
| + SimpleIdentifier parameterName =
|
| + EngineTestCase.findSimpleIdentifier(unit, newCode, 'p) => 4.2);');
|
| + expect(parameterName.staticType, context.typeProvider.dynamicType);
|
| + expect(parameterName.propagatedType, context.typeProvider.intType);
|
| + }
|
| +
|
| + void test_sequence_closureParameterTypesPropagation2() {
|
| + var code = r'''
|
| +import 'b.dart';
|
| +main(x) {
|
| + x.toMap();
|
| + f((p) => 'z');
|
| +}
|
| +f(double c(int p)) {}
|
| +''';
|
| + Source a = addSource('/a.dart', code);
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'c.dart';
|
| +''');
|
| + addSource(
|
| + '/c.dart',
|
| + r'''
|
| +import 'd.dart';
|
| +''');
|
| + Source d = addSource(
|
| + '/d.dart',
|
| + r'''
|
| +class D {}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + LibrarySpecificUnit targetA = new LibrarySpecificUnit(a, a);
|
| + // Update b.dart, resolution in a.dart is not affected.
|
| + context.setContents(
|
| + b,
|
| + r'''
|
| +import 'c.dart';
|
| +class B {}
|
| +''');
|
| + _assertValidAllResolution(a);
|
| + _performPendingAnalysisTasks();
|
| + // Update d.dart, this should invalidate a.dart and type propagation
|
| + // performed for the closure parameter.
|
| + context.setContents(
|
| + d,
|
| + r'''
|
| +class D {
|
| + toMap() {}
|
| +}
|
| +''');
|
| + _assertValidUnits(a, RESOLVED_UNIT6);
|
| + _assertInvalidUnits(a, RESOLVED_UNIT7);
|
| + _performPendingAnalysisTasks();
|
| + // Validate "(p) =>" types.
|
| + {
|
| + CompilationUnit unit = context.getResult(targetA, RESOLVED_UNIT2);
|
| + SimpleIdentifier parameterName =
|
| + EngineTestCase.findSimpleIdentifier(unit, code, 'p) =>');
|
| + expect(parameterName.staticType, context.typeProvider.dynamicType);
|
| + expect(parameterName.propagatedType, context.typeProvider.intType);
|
| + }
|
| + }
|
| +
|
| + void test_sequence_compoundingResults_exportNamespace() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A<T> {}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +export 'a.dart';
|
| +''');
|
| + Source c = addSource(
|
| + '/c.dart',
|
| + r'''
|
| +import 'b.dart';
|
| +main() {
|
| + new A<int>();
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(c).errors, isEmpty);
|
| + // Update a.dart, so that `A<T>` has a type bound.
|
| + // This should invalidate export namespace for b.dart.
|
| + // Currently we invalidate the whole LIBRARY_ELEMENT4.
|
| + // So, c.dart will see the new `A<T extends B>` and report an error.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A<T extends B> {}
|
| +class B {}
|
| +''');
|
| + _assertInvalid(b, LIBRARY_ELEMENT4);
|
| + // Analyze and validate that a new error is reported.
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(c).errors, hasLength(1));
|
| + _assertValid(a, LIBRARY_ERRORS_READY);
|
| + _assertValid(b, LIBRARY_ERRORS_READY);
|
| + _assertValid(c, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void test_sequence_compoundingResults_invalidateButKeepDependency() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +import 'b.dart';
|
| +class A {}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +import 'c.dart';
|
| +class B {}
|
| +''');
|
| + Source c = addSource(
|
| + '/c.dart',
|
| + r'''
|
| +class C {}
|
| +''');
|
| + Source d = addSource(
|
| + '/d.dart',
|
| + r'''
|
| +export 'b.dart';
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(c).errors, isEmpty);
|
| + // Update: a.dart (limited) and b.dart (limited).
|
| + // This should invalidate LIBRARY_ELEMENT4 in d.dart, but it should be
|
| + // done in a way that keep dependency of other results od d.dart on
|
| + // LIBRARY_ELEMENT4 of d.dart, so that when we perform unlimited
|
| + // invalidation of c.dart, this makes d.dart invalid.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +import 'b.dart';
|
| +class A2 {}
|
| +''');
|
| + context.setContents(
|
| + b,
|
| + r'''
|
| +import 'a.dart';
|
| +import 'c.dart';
|
| +class B2 {}
|
| +''');
|
| + context.setContents(
|
| + c,
|
| + r'''
|
| +import 'dart:async';
|
| +class C {}
|
| +''');
|
| + _assertInvalid(d, LIBRARY_ELEMENT4);
|
| + _assertInvalid(d, LIBRARY_ERRORS_READY);
|
| + // Analyze and validate that a new error is reported.
|
| + _performPendingAnalysisTasks();
|
| + _assertValid(a, EXPORT_SOURCE_CLOSURE);
|
| + _assertValid(b, EXPORT_SOURCE_CLOSURE);
|
| + _assertValid(c, EXPORT_SOURCE_CLOSURE);
|
| + _assertValid(d, EXPORT_SOURCE_CLOSURE);
|
| + _assertValid(a, LIBRARY_ERRORS_READY);
|
| + _assertValid(b, LIBRARY_ERRORS_READY);
|
| + _assertValid(c, LIBRARY_ERRORS_READY);
|
| + _assertValid(d, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void test_sequence_compoundingResults_resolvedTypeNames() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +class B<T> {
|
| + B(p);
|
| +}
|
| +''');
|
| + Source c = addSource(
|
| + '/c.dart',
|
| + r'''
|
| +export 'a.dart';
|
| +export 'b.dart';
|
| +''');
|
| + Source d = addSource(
|
| + '/d.dart',
|
| + r'''
|
| +import 'c.dart';
|
| +main() {
|
| + new B<int>(null);
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart and b.dart
|
| + // This should invalidate most results in a.dart and b.dart
|
| + //
|
| + // This should also invalidate "compounding" results in c.dart, such as
|
| + // READY_LIBRARY_ELEMENT6, which represent a state of the whole source
|
| + // closure, not a result of this single unit or a library.
|
| + //
|
| + // The reason is that although type names (RESOLVED_UNIT5) b.dart will be
|
| + // eventually resolved and set into b.dart elements, it may happen
|
| + // after we attempted to re-resolve c.dart, which created Member(s), and
|
| + // attempts to use elements without types set.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A2 {}
|
| +''');
|
| + context.setContents(
|
| + b,
|
| + r'''
|
| +class B<T> {
|
| + B(T p);
|
| +}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForChangedLibrary(b);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertInvalid(c, READY_LIBRARY_ELEMENT6);
|
| + _assertInvalid(c, READY_LIBRARY_ELEMENT7);
|
| + // Analyze and validate that all results are valid.
|
| + _performPendingAnalysisTasks();
|
| + _assertValid(a, LIBRARY_ERRORS_READY);
|
| + _assertValid(b, LIBRARY_ERRORS_READY);
|
| + _assertValid(c, LIBRARY_ERRORS_READY);
|
| + _assertValid(d, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void test_sequence_dependenciesWithCycles() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +const A = 1;
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'c.dart';
|
| +const B = C1 + 1;
|
| +''');
|
| + Source c = addSource(
|
| + '/c.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +import 'b.dart';
|
| +const C1 = A + 1;
|
| +const C2 = B + 2;
|
| +''');
|
| + Source d = addSource(
|
| + '/d.dart',
|
| + r'''
|
| +import 'c.dart';
|
| +const D = C2 + 1;
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update "A" constant.
|
| + // This should invalidate results in all sources.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +const A = 2;
|
| +''');
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertInvalid(c, LIBRARY_ERRORS_READY);
|
| + _assertInvalid(d, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void test_sequence_duplicateField_syntheticAndNot_renameNotSynthetic() {
|
| + context.analysisOptions =
|
| + new AnalysisOptionsImpl.from(context.analysisOptions)
|
| + ..strongMode = true;
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {
|
| + int foo;
|
| + int get foo => 1;
|
| +}
|
| +class B extends A {
|
| + int get foo => 2;
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(a).errors, hasLength(2));
|
| + // Update a.dart: rename "int foo" to "int bar".
|
| + // The strong mode "getter cannot override field" error is gone.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {
|
| + int bar;
|
| + int get foo => 1;
|
| +}
|
| +class B extends A {
|
| + int get foo => 2;
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(a).errors, isEmpty);
|
| + }
|
| +
|
| + void test_sequence_inBodyChange_addRef_deltaChange() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {
|
| +}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main(A a) {
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(b).errors, hasLength(0));
|
| + // Update b.dart: in-body incremental change - start referencing 'foo'.
|
| + // Should update referenced names.
|
| + context.setContents(
|
| + b,
|
| + r'''
|
| +import 'a.dart';
|
| +main(A a) {
|
| + a.foo;
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(b).errors, hasLength(1));
|
| + // Update a.dart: add A.foo
|
| + // b.dart is invalid, because it references 'foo'.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {
|
| + int foo;
|
| +}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertInvalidUnits(b, RESOLVED_UNIT4);
|
| + // No errors after analysis.
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(b).errors, hasLength(0));
|
| + }
|
| +
|
| + void test_sequence_inBodyChange_removeRef_deltaChange() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {
|
| +}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main(A a) {
|
| + a.foo;
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(b).errors, hasLength(1));
|
| + // Update b.dart: in-body incremental change - stop referencing 'foo'.
|
| + // Should update referenced names.
|
| + context.setContents(
|
| + b,
|
| + r'''
|
| +import 'a.dart';
|
| +main(A a) {
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(b).errors, hasLength(0));
|
| + // Update a.dart: add A.foo
|
| + // b.dart is still valid, because it does references 'foo' anymore.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {
|
| + int foo;
|
| +}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertValidAllLibraryUnitResults(b);
|
| + _assertValid(b, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void test_sequence_middleLimited_thenFirstFull() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +export 'a.dart';
|
| +''');
|
| + Source c = addSource(
|
| + '/c.dart',
|
| + r'''
|
| +import 'b.dart';
|
| +A a;
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update b.dart: limited invalidation.
|
| + // Results in c.dart are valid, because the change in b.dart does not
|
| + // affect anything in c.dart.
|
| + context.setContents(
|
| + b,
|
| + r'''
|
| +export 'a.dart';
|
| +class B {}
|
| +''');
|
| + _assertValid(a, LIBRARY_ERRORS_READY);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertValid(c, LIBRARY_ERRORS_READY);
|
| + _assertUnitValid(c, RESOLVED_UNIT4);
|
| + _assertUnitValid(c, RESOLVED_UNIT5);
|
| + // Update a.dart: unlimited invalidation.
|
| + // Results RESOLVED_UNIT4, RESOLVED_UNIT5, and RESOLVED_UNIT6 in c.dart
|
| + // are invalid, because after unlimited change to a.dart everything
|
| + // should be invalidated.
|
| + // This fixes the problem that c.dart was not re-resolving type names.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +import 'dart:async';
|
| +class A {}
|
| +''');
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertInvalid(c, LIBRARY_ERRORS_READY);
|
| + _assertInvalidUnits(c, RESOLVED_UNIT4);
|
| + }
|
| +
|
| + void test_sequence_noChange_thenChange() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {
|
| + A();
|
| +}
|
| +
|
| +class B {
|
| + B();
|
| +}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + new A();
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(a).errors, hasLength(0));
|
| + expect(context.getErrors(b).errors, hasLength(0));
|
| + var unitA = context.getResolvedCompilationUnit2(a, a);
|
| + var unitElementA = unitA.element;
|
| + var libraryElementA = unitElementA.library;
|
| + // Update a.dart, no declaration changes.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {
|
| + A();
|
| +}
|
| +class B {
|
| + B();
|
| +}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertValidAllLibraryUnitResults(b);
|
| + _assertValid(b, LIBRARY_ERRORS_READY);
|
| + // The a.dart's unit and element are updated incrementally.
|
| + // They are the same instances as initially.
|
| + // So, all the references from other units are still valid.
|
| + {
|
| + LibrarySpecificUnit target = new LibrarySpecificUnit(a, a);
|
| + expect(analysisCache.getValue(target, RESOLVED_UNIT1), same(unitA));
|
| + expect(unitA.element, same(unitElementA));
|
| + expect(unitElementA.library, same(libraryElementA));
|
| + }
|
| + // Analyze.
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(a).errors, hasLength(0));
|
| + expect(context.getErrors(b).errors, hasLength(0));
|
| + // The a.dart's unit and element are the same.
|
| + {
|
| + LibrarySpecificUnit target = new LibrarySpecificUnit(a, a);
|
| + expect(analysisCache.getValue(target, RESOLVED_UNIT), same(unitA));
|
| + expect(unitA.element, same(unitElementA));
|
| + expect(unitElementA.library, same(libraryElementA));
|
| + }
|
| + // Add a new method to a.dart. This invalidates b.dart, so
|
| + // we know that the previous update did not damage dependencies.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {
|
| + A();
|
| + m() {}
|
| +}
|
| +class B {
|
| + B();
|
| +}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertValidAllResolution(b);
|
| + _assertValidAllErrors(b);
|
| + // The a.dart's unit and element are the same.
|
| + {
|
| + LibrarySpecificUnit target = new LibrarySpecificUnit(a, a);
|
| + expect(analysisCache.getValue(target, RESOLVED_UNIT1), same(unitA));
|
| + expect(unitA.element, same(unitElementA));
|
| + expect(unitElementA.library, same(libraryElementA));
|
| + }
|
| + // Analyze.
|
| + _performPendingAnalysisTasks();
|
| + expect(context.getErrors(a).errors, hasLength(0));
|
| + expect(context.getErrors(b).errors, hasLength(0));
|
| + }
|
| +
|
| + void test_sequence_parts_disableForPart() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +library my_lib;
|
| +part 'b.dart';
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +part of my_lib;
|
| +class A {}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update b.dart - it is a part, which we don't support.
|
| + // So, invalidate everything.
|
| + context.setContents(
|
| + b,
|
| + r'''
|
| +part of my_lib;
|
| +class A {}
|
| +class B {}
|
| +''');
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertInvalidUnits(a, RESOLVED_UNIT2);
|
| + _assertInvalidUnits(b, RESOLVED_UNIT1);
|
| + }
|
| +
|
| + void test_sequence_parts_disableWithPart() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +library my_lib;
|
| +part 'b.dart';
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +part of my_lib;
|
| +class B {}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart - it is a library with a part, which we don't support.
|
| + // So, invalidate everything.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +library my_lib;
|
| +part 'b.dart';
|
| +class A {}
|
| +''');
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertInvalidUnits(a, RESOLVED_UNIT1);
|
| + _assertInvalidUnits(b, RESOLVED_UNIT1);
|
| + }
|
| +
|
| + void test_sequence_reorder_localFunctions() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +f1() {
|
| + localFunction() {
|
| + const C = 1;
|
| + }
|
| +}
|
| +f2() {}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart: reorder functions.
|
| + // This should not fail with FrozenHashCodeException, because identifiers
|
| + // of local elements should be relative to the enclosing top-level elements.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +f2() {}
|
| +f1() {
|
| + localFunction() {
|
| + const C = 1;
|
| + }
|
| +}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void test_sequence_unitConstants_addRemove() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +const A = 1;
|
| +const B = 2;
|
| +const C = 3;
|
| +foo() {
|
| + const V1 = 10;
|
| +}
|
| +bar() {
|
| + const V2 = 20;
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + LibrarySpecificUnit unitA = new LibrarySpecificUnit(a, a);
|
| + List<ConstantEvaluationTarget> oldConstants =
|
| + context.getResult(unitA, COMPILATION_UNIT_CONSTANTS);
|
| + expect(oldConstants, hasLength(5));
|
| + ConstVariableElement oldA = _findConstVariable(oldConstants, 'A');
|
| + ConstVariableElement oldB = _findConstVariable(oldConstants, 'B');
|
| + ConstVariableElement oldC = _findConstVariable(oldConstants, 'C');
|
| + ConstVariableElement oldV1 = _findConstVariable(oldConstants, 'V1');
|
| + ConstVariableElement oldV2 = _findConstVariable(oldConstants, 'V2');
|
| + expect(context.analysisCache.get(oldA), isNotNull);
|
| + expect(context.analysisCache.get(oldB), isNotNull);
|
| + expect(context.analysisCache.get(oldC), isNotNull);
|
| + expect(context.analysisCache.get(oldV1), isNotNull);
|
| + // Update and validate new constants.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +const A = 1;
|
| +const B = 2;
|
| +const D = 4;
|
| +foo() {
|
| + const V1 = 10;
|
| +}
|
| +baz() {
|
| + const V3 = 30;
|
| +}
|
| +''');
|
| + List<ConstantEvaluationTarget> newConstants =
|
| + context.getResult(unitA, COMPILATION_UNIT_CONSTANTS);
|
| + expect(newConstants, hasLength(5));
|
| + expect(newConstants, contains(same(oldA)));
|
| + expect(newConstants, contains(same(oldB)));
|
| + expect(newConstants, contains(same(oldV1)));
|
| + ConstVariableElement newD = _findConstVariable(newConstants, 'D');
|
| + ConstVariableElement newV3 = _findConstVariable(newConstants, 'V3');
|
| + // Perform analysis, compute constant values.
|
| + _performPendingAnalysisTasks();
|
| + // Validate const variable values.
|
| + expect(context.analysisCache.get(oldA), isNotNull);
|
| + expect(context.analysisCache.get(oldB), isNotNull);
|
| + expect(context.analysisCache.get(oldV1), isNotNull);
|
| + expect(context.analysisCache.get(oldC), isNull);
|
| + expect(context.analysisCache.get(oldV2), isNull);
|
| + expect(context.analysisCache.get(newD), isNotNull);
|
| + expect(context.analysisCache.get(newV3), isNotNull);
|
| + expect(oldA.evaluationResult.value.toIntValue(), 1);
|
| + expect(oldB.evaluationResult.value.toIntValue(), 2);
|
| + expect(newD.evaluationResult.value.toIntValue(), 4);
|
| + expect(oldV1.evaluationResult.value.toIntValue(), 10);
|
| + expect(newV3.evaluationResult.value.toIntValue(), 30);
|
| + }
|
| +
|
| + void test_sequence_unitConstants_local_insertSpace() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +main() {
|
| + const C = 1;
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + LibrarySpecificUnit unitA = new LibrarySpecificUnit(a, a);
|
| + List<ConstantEvaluationTarget> oldConstants =
|
| + context.getResult(unitA, COMPILATION_UNIT_CONSTANTS);
|
| + expect(oldConstants, hasLength(1));
|
| + ConstVariableElement C = _findConstVariable(oldConstants, 'C');
|
| + expect(context.analysisCache.get(C), isNotNull);
|
| + // Insert a space before the name.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +main() {
|
| + const C = 1;
|
| +}
|
| +''');
|
| + List<ConstantEvaluationTarget> newConstants =
|
| + context.getResult(unitA, COMPILATION_UNIT_CONSTANTS);
|
| + expect(newConstants, hasLength(1));
|
| + expect(newConstants, contains(same(C)));
|
| + // Perform analysis, compute constant values.
|
| + _performPendingAnalysisTasks();
|
| + // Validate const variable values.
|
| + expect(context.analysisCache.get(C), isNotNull);
|
| + expect(C.evaluationResult.value.toIntValue(), 1);
|
| + }
|
| +
|
| + void test_sequence_useAnyResolvedUnit() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {}
|
| +class B {}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + new A();
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + _assertValid(a, LIBRARY_ERRORS_READY);
|
| + _assertValid(b, LIBRARY_ERRORS_READY);
|
| + // Invalidate RESOLVED_UNIT
|
| + CacheEntry entryA = context.getCacheEntry(new LibrarySpecificUnit(a, a));
|
| + entryA.setState(RESOLVED_UNIT, CacheState.FLUSHED);
|
| + entryA.setState(RESOLVED_UNIT1, CacheState.FLUSHED);
|
| + entryA.setState(RESOLVED_UNIT2, CacheState.FLUSHED);
|
| + entryA.setState(RESOLVED_UNIT3, CacheState.FLUSHED);
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {}
|
| +class B2 {}
|
| +''');
|
| + _assertValidAllLibraryUnitResults(b);
|
| + _assertValid(b, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void test_sequence_useAnyResolvedUnit_needsLibraryElement() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {}
|
| +class B {}
|
| +''');
|
| + // Perform analysis until we get RESOLVED_UNIT1.
|
| + // But it does not have 'library' set, so `unitElement.context` is `null`.
|
| + LibrarySpecificUnit aUnitTarget = new LibrarySpecificUnit(a, a);
|
| + while (context.getResult(aUnitTarget, RESOLVED_UNIT1) == null) {
|
| + context.performAnalysisTask();
|
| + }
|
| + // There was a bug with exception in incremental element builder.
|
| + // We should not attempt to use `unitElement.context`.
|
| + // It calls `unitElement.library`, which might be not set yet.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {}
|
| +class B2 {}
|
| +''');
|
| + // OK, no exceptions.
|
| + }
|
| +
|
| + void test_unusedName_class_add() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {}
|
| +class B {}
|
| +class C {}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + new A();
|
| + new C();
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + _assertValid(a, LINE_INFO);
|
| + // The class B is not referenced.
|
| + // a.dart is invalid.
|
| + // b.dart is valid.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {}
|
| +class B2 {}
|
| +class C {}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertUnitInvalid(a, RESOLVED_UNIT);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertValidAllLibraryUnitResults(b);
|
| + _assertValid(b, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void test_usedName_class_name_asHole_inBody() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {}
|
| +class B {}
|
| +class C {}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + new A();
|
| + new C2();
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart: remove C, add C2.
|
| + // b.dart is invalid, because it references C2.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {}
|
| +class B {}
|
| +class C2 {}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertInvalidUnits(b, RESOLVED_UNIT4);
|
| + }
|
| +
|
| + void test_usedName_class_name_asSuper() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +class B extends A {}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart: remove A, add A2.
|
| + // b.dart is invalid, because it references A.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A2 {}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertInvalidUnits(b, RESOLVED_UNIT4);
|
| + }
|
| +
|
| + void test_usedName_class_name_asTypeBound() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +class B<T extends A> {
|
| + T f;
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart: remove A, add A2.
|
| + // b.dart is invalid, because it references A.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A2 {}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertInvalidUnits(b, RESOLVED_UNIT4);
|
| + }
|
| +
|
| + void test_usedName_class_name_inBody() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {}
|
| +class B {}
|
| +class C {}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + new A();
|
| + new C();
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart: remove C, add C2.
|
| + // b.dart is invalid, because it references C.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {}
|
| +class B {}
|
| +class C2 {}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertInvalidUnits(b, RESOLVED_UNIT4);
|
| + }
|
| +
|
| + void test_usedName_classMethod_name_inBody() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {
|
| + m() {}
|
| +}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +main() {
|
| + A a = new A();
|
| + a.m();
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart: remove A.m, add A.m2.
|
| + // b.dart is invalid, because it references 'm'.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {
|
| + m2() {}
|
| +}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertInvalidLibraryElements(b, LIBRARY_ELEMENT4);
|
| + _assertInvalidUnits(b, RESOLVED_UNIT4);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void test_usedName_indirect_classMethod_name_inBody() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {
|
| + m() {}
|
| +}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +class B extends A {}
|
| +''');
|
| + Source c = addSource(
|
| + '/c.dart',
|
| + r'''
|
| +import 'b.dart';
|
| +main() {
|
| + B b = new B();
|
| + b.m();
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart: remove A.m, add A.m2.
|
| + // b.dart has valid resolution, and invalid errors.
|
| + // c.dart is invalid, because 'main' references 'm'.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {
|
| + m2() {}
|
| +}
|
| +''');
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| +
|
| + _assertValidForDependentLibrary(b);
|
| + _assertValidAllResolution(b);
|
| + _assertInvalidHintsVerifyErrors(b);
|
| +
|
| + _assertValidForDependentLibrary(c);
|
| + _assertInvalidLibraryElements(c, LIBRARY_ELEMENT5);
|
| + _assertInvalidUnits(c, RESOLVED_UNIT4);
|
| + _assertInvalid(c, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void test_usedName_indirect_classMethod_returnType_inBody() {
|
| + Source a = addSource(
|
| + '/a.dart',
|
| + r'''
|
| +class A {
|
| + int m() {
|
| + return 1;
|
| + }
|
| +}
|
| +''');
|
| + Source b = addSource(
|
| + '/b.dart',
|
| + r'''
|
| +import 'a.dart';
|
| +class B extends A {}
|
| +''');
|
| + Source c = addSource(
|
| + '/c.dart',
|
| + r'''
|
| +import 'b.dart';
|
| +main() {
|
| + B b = new B();
|
| + b.m();
|
| +}
|
| +''');
|
| + _performPendingAnalysisTasks();
|
| + // Update a.dart: remove A.m, add A.m2.
|
| + // b.dart is invalid, because B extends A.
|
| + // c.dart is invalid, because 'main' references 'm'.
|
| + context.setContents(
|
| + a,
|
| + r'''
|
| +class A {
|
| + double m() {
|
| + return 1.2;
|
| + }
|
| +}
|
| +''');
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| +
|
| + _assertValidForDependentLibrary(b);
|
| + _assertValidAllResolution(b);
|
| + _assertInvalidHintsVerifyErrors(b);
|
| +
|
| + _assertValidForDependentLibrary(c);
|
| + _assertInvalidLibraryElements(c, LIBRARY_ELEMENT5);
|
| + _assertInvalidUnits(c, RESOLVED_UNIT4);
|
| + _assertInvalid(c, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + void _assertInvalid(AnalysisTarget target, ResultDescriptor descriptor) {
|
| + CacheState actual = analysisCache.getState(target, descriptor);
|
| + if (actual != CacheState.INVALID) {
|
| + fail("cache state of $target $descriptor: wanted INVALID, got: $actual");
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Assert that [VERIFY_ERRORS] and other error results that include it,
|
| + * are invalid.
|
| + */
|
| + void _assertInvalidHintsVerifyErrors(Source unit) {
|
| + _assertUnitInvalid(unit, HINTS);
|
| + _assertUnitInvalid(unit, VERIFY_ERRORS);
|
| + _assertUnitInvalid(unit, LIBRARY_UNIT_ERRORS);
|
| + _assertInvalid(unit, DART_ERRORS);
|
| + _assertInvalid(unit, LIBRARY_ERRORS_READY);
|
| + }
|
| +
|
| + /**
|
| + * Assert that [LIBRARY_ELEMENT_RESULTS] for [first] and after it are invalid.
|
| + */
|
| + void _assertInvalidLibraryElements(
|
| + Source source, ResultDescriptor<LibraryElement> first) {
|
| + bool foundFirst = false;
|
| + for (ResultDescriptor<LibraryElement> result in LIBRARY_ELEMENT_RESULTS) {
|
| + foundFirst = foundFirst || result == first;
|
| + if (foundFirst) {
|
| + _assertInvalid(source, result);
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _assertInvalidUnits(Source unit, ResultDescriptor<CompilationUnit> first,
|
| + {Source library}) {
|
| + var target = new LibrarySpecificUnit(library ?? unit, unit);
|
| + bool foundFirst = false;
|
| + for (ResultDescriptor<CompilationUnit> result in RESOLVED_UNIT_RESULTS) {
|
| + foundFirst = foundFirst || result == first;
|
| + if (foundFirst) {
|
| + _assertInvalid(target, result);
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _assertUnitInvalid(Source unitSource, ResultDescriptor descriptor,
|
| + {Source librarySource}) {
|
| + librarySource ??= unitSource;
|
| + _assertInvalid(
|
| + new LibrarySpecificUnit(librarySource, unitSource), descriptor);
|
| + }
|
| +
|
| + void _assertUnitValid(Source unitSource, ResultDescriptor descriptor,
|
| + {Source librarySource}) {
|
| + librarySource ??= unitSource;
|
| + _assertValid(
|
| + new LibrarySpecificUnit(librarySource, unitSource), descriptor);
|
| + }
|
| +
|
| + void _assertUnitValidTaskResults(Source unitSource, TaskDescriptor descriptor,
|
| + {Source librarySource}) {
|
| + librarySource ??= unitSource;
|
| + for (ResultDescriptor result in descriptor.results) {
|
| + _assertUnitValid(unitSource, result, librarySource: librarySource);
|
| + }
|
| }
|
|
|
| void _assertValid(AnalysisTarget target, ResultDescriptor descriptor) {
|
| CacheState state = analysisCache.getState(target, descriptor);
|
| - expect(state, CacheState.VALID);
|
| + expect(state, isIn([CacheState.VALID, CacheState.FLUSHED]),
|
| + reason: '$descriptor in $target');
|
| + }
|
| +
|
| + /**
|
| + * Assert that all error results for the given [unit] are valid.
|
| + */
|
| + void _assertValidAllErrors(Source unit) {
|
| + for (ListResultDescriptor<AnalysisError> result in ERROR_SOURCE_RESULTS) {
|
| + _assertValid(unit, result);
|
| + }
|
| + for (ListResultDescriptor<AnalysisError> result in ERROR_UNIT_RESULTS) {
|
| + _assertUnitValid(unit, result);
|
| + }
|
| + }
|
| +
|
| + void _assertValidAllLibraryUnitResults(Source source, {Source library}) {
|
| + library ??= source;
|
| + for (ResultDescriptor<LibraryElement> result in LIBRARY_ELEMENT_RESULTS) {
|
| + if (result == LIBRARY_ELEMENT4) {
|
| + continue;
|
| + }
|
| + _assertValid(library, result);
|
| + }
|
| + LibrarySpecificUnit target = new LibrarySpecificUnit(library, source);
|
| + for (ResultDescriptor<CompilationUnit> result in RESOLVED_UNIT_RESULTS) {
|
| + _assertValid(target, result);
|
| + }
|
| + }
|
| +
|
| + void _assertValidAllResolution(Source unit) {
|
| + _assertValidUnits(unit, null);
|
| + _assertUnitValidTaskResults(unit, ResolveUnitTypeNamesTask.DESCRIPTOR);
|
| + _assertUnitValidTaskResults(unit, ResolveUnitTask.DESCRIPTOR);
|
| + _assertValidTaskResults(unit, ResolveLibraryReferencesTask.DESCRIPTOR);
|
| + _assertValidTaskResults(unit, ResolveLibraryTask.DESCRIPTOR);
|
| + }
|
| +
|
| + void _assertValidForAnyLibrary(Source source) {
|
| + // Source results.
|
| + _assertValidTaskResults(source, ScanDartTask.DESCRIPTOR);
|
| + // Library results.
|
| + _assertValidTaskResults(source, BuildLibraryElementTask.DESCRIPTOR);
|
| + _assertValidTaskResults(source, BuildDirectiveElementsTask.DESCRIPTOR);
|
| + _assertValidTaskResults(source, BuildSourceExportClosureTask.DESCRIPTOR);
|
| + _assertValidTaskResults(source, ReadyLibraryElement2Task.DESCRIPTOR);
|
| + _assertValidTaskResults(source, ComputeLibraryCycleTask.DESCRIPTOR);
|
| + // Unit results.
|
| + _assertUnitValidTaskResults(
|
| + source, BuildCompilationUnitElementTask.DESCRIPTOR);
|
| + _assertUnitValidTaskResults(
|
| + source, ResolveDirectiveElementsTask.DESCRIPTOR);
|
| + _assertUnitValidTaskResults(source, BuildEnumMemberElementsTask.DESCRIPTOR);
|
| + }
|
| +
|
| + void _assertValidForChangedLibrary(Source source) {
|
| + _assertValidForAnyLibrary(source);
|
| + }
|
| +
|
| + void _assertValidForDependentLibrary(Source source) {
|
| + _assertValidForAnyLibrary(source);
|
| + // Library results.
|
| + _assertValidTaskResults(source, BuildPublicNamespaceTask.DESCRIPTOR);
|
| + }
|
| +
|
| + void _assertValidTaskResults(AnalysisTarget target, TaskDescriptor task) {
|
| + for (ResultDescriptor result in task.results) {
|
| + _assertValid(target, result);
|
| + }
|
| + }
|
| +
|
| + void _assertValidUnits(Source unit, ResultDescriptor<CompilationUnit> last,
|
| + {Source library}) {
|
| + var target = new LibrarySpecificUnit(library ?? unit, unit);
|
| + bool foundLast = false;
|
| + for (ResultDescriptor<CompilationUnit> result in RESOLVED_UNIT_RESULTS) {
|
| + if (!foundLast) {
|
| + _assertValid(target, result);
|
| + }
|
| + foundLast = foundLast || result == last;
|
| + }
|
| + }
|
| +
|
| + ConstVariableElement _findConstVariable(
|
| + List<ConstantEvaluationTarget> constants, String name) {
|
| + return constants.singleWhere((c) {
|
| + return c is ConstVariableElement && c.name == name;
|
| + });
|
| }
|
|
|
| void _performPendingAnalysisTasks([int maxTasks = 512]) {
|
| @@ -2559,6 +5127,67 @@ class A {
|
| }
|
| }
|
| }
|
| +
|
| + void _verifyTwoLibrariesAllValid(
|
| + String firstCodeA, String secondCodeA, String codeB) {
|
| + Source a = addSource('/a.dart', firstCodeA);
|
| + Source b = addSource('/b.dart', codeB);
|
| + _performPendingAnalysisTasks();
|
| + context.setContents(a, secondCodeA);
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertValidAllResolution(b);
|
| + _assertValidAllErrors(b);
|
| + }
|
| +
|
| + void _verifyTwoLibrariesInvalidatesResolution(
|
| + String firstCodeA, String secondCodeA, String codeB) {
|
| + Source a = addSource('/a.dart', firstCodeA);
|
| + Source b = addSource('/b.dart', codeB);
|
| + _performPendingAnalysisTasks();
|
| + context.setContents(a, secondCodeA);
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertInvalid(b, LIBRARY_ERRORS_READY);
|
| + _assertInvalidUnits(b, RESOLVED_UNIT4);
|
| + }
|
| +
|
| + void _verifyTwoLibrariesInvalidHintsVerifyErrors(
|
| + String firstCodeA, String secondCodeA, String codeB) {
|
| + Source a = addSource('/a.dart', firstCodeA);
|
| + Source b = addSource('/b.dart', codeB);
|
| + _performPendingAnalysisTasks();
|
| + context.setContents(a, secondCodeA);
|
| + _assertValidForChangedLibrary(a);
|
| + _assertInvalid(a, LIBRARY_ERRORS_READY);
|
| + _assertValidForDependentLibrary(b);
|
| + _assertValidAllResolution(b);
|
| + _assertUnitValid(b, RESOLVE_UNIT_ERRORS);
|
| + _assertInvalidHintsVerifyErrors(b);
|
| + }
|
| +}
|
| +
|
| +class _AnalysisContextImplTest_Source_exists_true extends TestSource {
|
| + @override
|
| + bool exists() => true;
|
| +}
|
| +
|
| +class _AnalysisContextImplTest_Source_getModificationStamp_fromSource
|
| + extends TestSource {
|
| + int stamp;
|
| + _AnalysisContextImplTest_Source_getModificationStamp_fromSource(this.stamp);
|
| + @override
|
| + int get modificationStamp => stamp;
|
| +}
|
| +
|
| +class _AnalysisContextImplTest_Source_getModificationStamp_overridden
|
| + extends TestSource {
|
| + int stamp;
|
| + _AnalysisContextImplTest_Source_getModificationStamp_overridden(this.stamp);
|
| + @override
|
| + int get modificationStamp => stamp;
|
| }
|
|
|
| class _AnalysisContextImplTest_test_applyChanges_removeContainer
|
| @@ -2568,3 +5197,82 @@ class _AnalysisContextImplTest_test_applyChanges_removeContainer
|
| @override
|
| bool contains(Source source) => source == libB;
|
| }
|
| +
|
| +/**
|
| + * A visitor that can be used to compare all of the elements in an element model
|
| + * with a previously created map of elements. The class [ElementGatherer] can be
|
| + * used to create the map of elements.
|
| + */
|
| +class _ElementComparer extends GeneralizingElementVisitor {
|
| + /**
|
| + * The previously created map of elements.
|
| + */
|
| + final Map<Element, Element> previousElements;
|
| +
|
| + /**
|
| + * The number of elements that were found to have been overwritten.
|
| + */
|
| + int overwrittenCount = 0;
|
| +
|
| + /**
|
| + * A buffer to which a description of the overwritten elements will be written.
|
| + */
|
| + final StringBuffer buffer = new StringBuffer();
|
| +
|
| + /**
|
| + * Initialize a newly created visitor.
|
| + */
|
| + _ElementComparer(this.previousElements);
|
| +
|
| + /**
|
| + * Expect that no differences were found, causing the test to fail if that
|
| + * wasn't the case.
|
| + */
|
| + void expectNoDifferences() {
|
| + if (overwrittenCount > 0) {
|
| + fail('Found $overwrittenCount overwritten elements.$buffer');
|
| + }
|
| + }
|
| +
|
| + @override
|
| + void visitElement(Element element) {
|
| + Element previousElement = previousElements[element];
|
| + if (!identical(previousElement, element)) {
|
| + if (overwrittenCount == 0) {
|
| + buffer.writeln();
|
| + }
|
| + overwrittenCount++;
|
| + buffer.writeln('Overwritten element:');
|
| + Element currentElement = element;
|
| + while (currentElement != null) {
|
| + buffer.write(' ');
|
| + buffer.writeln(currentElement.toString());
|
| + currentElement = currentElement.enclosingElement;
|
| + }
|
| + }
|
| + super.visitElement(element);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * A visitor that can be used to collect all of the elements in an element
|
| + * model.
|
| + */
|
| +class _ElementGatherer extends GeneralizingElementVisitor {
|
| + /**
|
| + * The map in which the elements are collected. The value of each key is the
|
| + * key itself.
|
| + */
|
| + Map<Element, Element> elements = new HashMap<Element, Element>();
|
| +
|
| + /**
|
| + * Initialize the visitor.
|
| + */
|
| + _ElementGatherer();
|
| +
|
| + @override
|
| + void visitElement(Element element) {
|
| + elements[element] = element;
|
| + super.visitElement(element);
|
| + }
|
| +}
|
|
|