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

Unified Diff: packages/analyzer/test/src/context/context_test.dart

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);
+ }
+}
« no previous file with comments | « packages/analyzer/test/src/context/cache_test.dart ('k') | packages/analyzer/test/src/context/mock_sdk.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698