blob: 7da5f3f287851cda42336de829df981cc69b461c [file] [log] [blame]
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library analyzer.test.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/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/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 '../../utils.dart';
import 'abstract_context.dart';
main() {
initializeTestEnvironment();
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);
//
// Create a file that references an file that is not explicitly being
// analyzed and fully analyze it. Ensure that the listener is told about
// the implicitly analyzed file.
//
Source sourceA = newSource('/a.dart', "library a; import 'b.dart';");
Source sourceB = newSource('/b.dart', "library b;");
ChangeSet changeSet = new ChangeSet();
changeSet.addedSource(sourceA);
context.applyChanges(changeSet);
context.computeErrors(sourceA);
await pumpEventQueue();
listener.expectAnalyzed(sourceB);
//
// Remove the reference and ensure that the listener is told that we're no
// longer implicitly analyzing the file.
//
context.setContents(sourceA, "library a;");
context.computeErrors(sourceA);
await pumpEventQueue();
listener.expectNotAnalyzed(sourceB);
}
void fail_performAnalysisTask_importedLibraryDelete_html() {
// NOTE: This was failing before converting to the new task model.
Source htmlSource = addSource(
"/page.html",
r'''
<html><body><script type="application/dart">
import 'libB.dart';
main() {print('hello dart');}
</script></body></html>''');
Source libBSource = addSource("/libB.dart", "library libB;");
_analyzeAll_assertFinished();
context.computeErrors(htmlSource);
expect(
context.getResolvedCompilationUnit2(libBSource, libBSource), isNotNull,
reason: "libB resolved 1");
expect(!_hasAnalysisErrorWithErrorSeverity(context.getErrors(htmlSource)),
isTrue,
reason: "htmlSource doesn't have errors");
// remove libB.dart content and analyze
context.setContents(libBSource, null);
_analyzeAll_assertFinished();
context.computeErrors(htmlSource);
AnalysisErrorInfo errors = context.getErrors(htmlSource);
expect(_hasAnalysisErrorWithErrorSeverity(errors), isTrue,
reason: "htmlSource has an error");
}
void fail_recordLibraryElements() {
fail("Implement this");
}
@override
void tearDown() {
context = null;
sourceFactory = null;
super.tearDown();
}
Future test_applyChanges_add() {
SourcesChangedListener listener = new SourcesChangedListener();
context.onSourcesChanged.listen(listener.onData);
expect(context.sourcesNeedingProcessing, isEmpty);
Source source = newSource('/test.dart');
ChangeSet changeSet = new ChangeSet();
changeSet.addedSource(source);
context.applyChanges(changeSet);
expect(context.sourcesNeedingProcessing, contains(source));
return pumpEventQueue().then((_) {
listener.assertEvent(wereSourcesAdded: true);
listener.assertNoMoreEvents();
});
}
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);
expect(context.sourcesNeedingProcessing, isEmpty);
Source source = newSource('/test.dart');
ChangeSet changeSet1 = new ChangeSet();
changeSet1.addedSource(source);
context.applyChanges(changeSet1);
expect(context.sourcesNeedingProcessing, contains(source));
Source source2 = newSource('/test2.dart');
ChangeSet changeSet2 = new ChangeSet();
changeSet2.addedSource(source2);
changeSet2.changedSource(source);
context.applyChanges(changeSet2);
return pumpEventQueue().then((_) {
listener.assertEvent(wereSourcesAdded: true);
listener.assertEvent(wereSourcesAdded: true, changedSources: [source]);
listener.assertNoMoreEvents();
});
}
Future test_applyChanges_change_content() {
SourcesChangedListener listener = new SourcesChangedListener();
context.onSourcesChanged.listen(listener.onData);
expect(context.sourcesNeedingProcessing, isEmpty);
Source source = newSource('/test.dart');
ChangeSet changeSet1 = new ChangeSet();
changeSet1.addedSource(source);
context.applyChanges(changeSet1);
expect(context.sourcesNeedingProcessing, contains(source));
Source source2 = newSource('/test2.dart');
ChangeSet changeSet2 = new ChangeSet();
changeSet2.addedSource(source2);
changeSet2.changedContent(source, 'library test;');
context.applyChanges(changeSet2);
return pumpEventQueue().then((_) {
listener.assertEvent(wereSourcesAdded: true);
listener.assertEvent(wereSourcesAdded: true, changedSources: [source]);
listener.assertNoMoreEvents();
});
}
void test_applyChanges_change_flush_element() {
Source librarySource = addSource(
"/lib.dart",
r'''
library lib;
int a = 0;''');
expect(context.computeLibraryElement(librarySource), isNotNull);
context.setContents(
librarySource,
r'''
library lib;
int aa = 0;''');
expect(context.getLibraryElement(librarySource), isNull);
}
Future test_applyChanges_change_multiple() {
SourcesChangedListener listener = new SourcesChangedListener();
context.onSourcesChanged.listen(listener.onData);
String libraryContents1 = r'''
library lib;
part 'part.dart';
int a = 0;''';
Source librarySource = addSource("/lib.dart", libraryContents1);
String partContents1 = r'''
part of lib;
int b = a;''';
Source partSource = addSource("/part.dart", partContents1);
context.computeLibraryElement(librarySource);
String libraryContents2 = r'''
library lib;
part 'part.dart';
int aa = 0;''';
context.setContents(librarySource, libraryContents2);
String partContents2 = r'''
part of lib;
int b = aa;''';
context.setContents(partSource, partContents2);
context.computeLibraryElement(librarySource);
CompilationUnit libraryUnit =
context.resolveCompilationUnit2(librarySource, librarySource);
expect(libraryUnit, isNotNull);
CompilationUnit partUnit =
context.resolveCompilationUnit2(partSource, librarySource);
expect(partUnit, isNotNull);
TopLevelVariableDeclaration declaration =
libraryUnit.declarations[0] as TopLevelVariableDeclaration;
Element declarationElement = declaration.variables.variables[0].element;
TopLevelVariableDeclaration use =
partUnit.declarations[0] as TopLevelVariableDeclaration;
Element useElement =
(use.variables.variables[0].initializer as SimpleIdentifier)
.staticElement;
expect((useElement as PropertyAccessorElement).variable,
same(declarationElement));
return pumpEventQueue().then((_) {
listener.assertEvent(wereSourcesAdded: true);
listener.assertEvent(wereSourcesAdded: true);
listener.assertEvent(changedSources: [librarySource]);
listener.assertEvent(changedSources: [partSource]);
listener.assertNoMoreEvents();
});
}
Future test_applyChanges_change_range() {
SourcesChangedListener listener = new SourcesChangedListener();
context.onSourcesChanged.listen(listener.onData);
expect(context.sourcesNeedingProcessing, isEmpty);
Source source = newSource('/test.dart');
ChangeSet changeSet1 = new ChangeSet();
changeSet1.addedSource(source);
context.applyChanges(changeSet1);
expect(context.sourcesNeedingProcessing, contains(source));
Source source2 = newSource('/test2.dart');
ChangeSet changeSet2 = new ChangeSet();
changeSet2.addedSource(source2);
changeSet2.changedRange(source, 'library test;', 0, 0, 13);
context.applyChanges(changeSet2);
return pumpEventQueue().then((_) {
listener.assertEvent(wereSourcesAdded: true);
listener.assertEvent(wereSourcesAdded: true, changedSources: [source]);
listener.assertNoMoreEvents();
});
}
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() {
String content = "library test;";
Source source = addSource("/test.dart", content);
context.setContents(source, content);
context.computeErrors(source);
while (!context.sourcesNeedingProcessing.isEmpty) {
context.performAnalysisTask();
}
// Adding the source as a changedSource should have no effect since
// it is already overridden in the content cache.
ChangeSet changeSet = new ChangeSet();
changeSet.changedSource(source);
context.applyChanges(changeSet);
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);
String libAContents = r'''
library libA;
import 'libB.dart';''';
Source libA = addSource("/libA.dart", libAContents);
String libBContents = "library libB;";
Source libB = addSource("/libB.dart", libBContents);
LibraryElement libAElement = context.computeLibraryElement(libA);
expect(libAElement, isNotNull);
List<LibraryElement> importedLibraries = libAElement.importedLibraries;
expect(importedLibraries, hasLength(2));
context.computeErrors(libA);
context.computeErrors(libB);
context.setContents(libB, null);
_removeSource(libB);
List<Source> sources = context.sourcesNeedingProcessing;
expect(sources, hasLength(1));
expect(sources[0], same(libA));
libAElement = context.computeLibraryElement(libA);
importedLibraries = libAElement.importedLibraries;
expect(importedLibraries, hasLength(2));
return pumpEventQueue().then((_) {
listener.assertEvent(wereSourcesAdded: true);
listener.assertEvent(wereSourcesAdded: true);
listener.assertEvent(wereSourcesRemovedOrDeleted: true);
listener.assertNoMoreEvents();
});
}
/**
* IDEA uses the following scenario:
* 1. Add overlay.
* 2. Change overlay.
* 3. If the contents of the document buffer is the same as the contents
* of the file, remove overlay.
* So, we need to try to use incremental resolution for removing overlays too.
*/
void test_applyChanges_remove_incremental() {
MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
Source source = resourceProvider
.newFile(
'/test.dart',
r'''
main() {
print(1);
}
''')
.createSource();
context.analysisOptions = new AnalysisOptionsImpl()..incremental = true;
context.applyChanges(new ChangeSet()..addedSource(source));
// remember compilation unit
_analyzeAll_assertFinished();
CompilationUnit unit = context.getResolvedCompilationUnit2(source, source);
// add overlay
context.setContents(
source,
r'''
main() {
print(12);
}
''');
_analyzeAll_assertFinished();
expect(context.getResolvedCompilationUnit2(source, source), unit);
// remove overlay
context.setContents(source, null);
_analyzeAll_assertFinished();
expect(context.getResolvedCompilationUnit2(source, source), unit);
}
Future test_applyChanges_removeContainer() {
SourcesChangedListener listener = new SourcesChangedListener();
context.onSourcesChanged.listen(listener.onData);
String libAContents = r'''
library libA;
import 'libB.dart';''';
Source libA = addSource("/libA.dart", libAContents);
String libBContents = "library libB;";
Source libB = addSource("/libB.dart", libBContents);
context.computeLibraryElement(libA);
context.computeErrors(libA);
context.computeErrors(libB);
ChangeSet changeSet = new ChangeSet();
SourceContainer removedContainer =
new _AnalysisContextImplTest_test_applyChanges_removeContainer(libB);
changeSet.removedContainer(removedContainer);
context.applyChanges(changeSet);
List<Source> sources = context.sourcesNeedingProcessing;
expect(sources, hasLength(1));
expect(sources[0], same(libA));
return pumpEventQueue().then((_) {
listener.assertEvent(wereSourcesAdded: true);
listener.assertEvent(wereSourcesAdded: true);
listener.assertEvent(wereSourcesRemovedOrDeleted: true);
listener.assertNoMoreEvents();
});
}
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",
"""
$comment
class A {}""");
LibraryElement libraryElement = context.computeLibraryElement(source);
expect(libraryElement, isNotNull);
ClassElement classElement = libraryElement.definingCompilationUnit.types[0];
expect(libraryElement, isNotNull);
expect(context.computeDocumentationComment(classElement), comment);
}
void test_computeDocumentationComment_class_none() {
Source source = addSource("/test.dart", "class A {}");
LibraryElement libraryElement = context.computeLibraryElement(source);
expect(libraryElement, isNotNull);
ClassElement classElement = libraryElement.definingCompilationUnit.types[0];
expect(libraryElement, isNotNull);
expect(context.computeDocumentationComment(classElement), isNull);
}
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);
expect(libraryElement, isNotNull);
ClassElement classElement = libraryElement.definingCompilationUnit.types[0];
expect(libraryElement, isNotNull);
String actual = context.computeDocumentationComment(classElement);
expect(actual, "/// line 1\n/// line 2\n/// line 3");
}
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);
expect(libraryElement, isNotNull);
ClassElement classElement = libraryElement.definingCompilationUnit.types[0];
expect(libraryElement, isNotNull);
String actual = context.computeDocumentationComment(classElement);
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);
expect(errors, hasLength(0));
}
void test_computeErrors_dart_part() {
Source librarySource =
addSource("/lib.dart", "library lib; part 'part.dart';");
Source partSource = addSource("/part.dart", "part of 'lib';");
context.parseCompilationUnit(librarySource);
List<AnalysisError> errors = context.computeErrors(partSource);
expect(errors, isNotNull);
expect(errors.length > 0, isTrue);
}
void test_computeErrors_dart_some() {
Source source = addSource("/lib.dart", "library 'lib';");
List<AnalysisError> errors = context.computeErrors(source);
expect(errors, isNotNull);
expect(errors.length > 0, isTrue);
}
void test_computeErrors_html_none() {
Source source = addSource("/test.html", "<!DOCTYPE html><html></html>");
List<AnalysisError> errors = context.computeErrors(source);
expect(errors, hasLength(0));
}
void test_computeExportedLibraries_none() {
Source source = addSource("/test.dart", "library test;");
expect(context.computeExportedLibraries(source), hasLength(0));
}
void test_computeExportedLibraries_some() {
// addSource("/lib1.dart", "library lib1;");
// addSource("/lib2.dart", "library lib2;");
Source source = addSource(
"/test.dart", "library test; export 'lib1.dart'; export 'lib2.dart';");
expect(context.computeExportedLibraries(source), hasLength(2));
}
void test_computeImportedLibraries_none() {
Source source = addSource("/test.dart", "library test;");
expect(context.computeImportedLibraries(source), hasLength(0));
}
void test_computeImportedLibraries_some() {
Source source = addSource(
"/test.dart", "library test; import 'lib1.dart'; import 'lib2.dart';");
expect(context.computeImportedLibraries(source), hasLength(2));
}
void test_computeKindOf_html() {
Source source = addSource("/test.html", "");
expect(context.computeKindOf(source), same(SourceKind.HTML));
}
void test_computeKindOf_library() {
Source source = addSource("/test.dart", "library lib;");
expect(context.computeKindOf(source), same(SourceKind.LIBRARY));
}
void test_computeKindOf_libraryAndPart() {
Source source = addSource("/test.dart", "library lib; part of lib;");
expect(context.computeKindOf(source), same(SourceKind.LIBRARY));
}
void test_computeKindOf_part() {
Source source = addSource("/test.dart", "part of lib;");
expect(context.computeKindOf(source), same(SourceKind.PART));
}
void test_computeLibraryElement() {
Source source = addSource("/test.dart", "library lib;");
LibraryElement element = context.computeLibraryElement(source);
expect(element, isNotNull);
}
void test_computeLineInfo_dart() {
Source source = addSource(
"/test.dart",
r'''
library lib;
main() {}''');
LineInfo info = context.computeLineInfo(source);
expect(info, isNotNull);
}
void test_computeLineInfo_html() {
Source source = addSource(
"/test.html",
r'''
<html>
<body>
<h1>A</h1>
</body>
</html>''');
LineInfo info = context.computeLineInfo(source);
expect(info, isNotNull);
}
Future test_computeResolvedCompilationUnitAsync() {
Source source = addSource("/lib.dart", "library lib;");
// Complete all pending analysis tasks and flush the AST so that it won't
// be available immediately.
_performPendingAnalysisTasks();
_flushAst(source);
bool completed = false;
context
.computeResolvedCompilationUnitAsync(source, source)
.then((CompilationUnit unit) {
expect(unit, isNotNull);
completed = true;
});
return pumpEventQueue()
.then((_) {
expect(completed, isFalse);
_performPendingAnalysisTasks();
})
.then((_) => pumpEventQueue())
.then((_) {
expect(completed, isTrue);
});
}
Future test_computeResolvedCompilationUnitAsync_afterDispose() {
Source source = addSource("/lib.dart", "library lib;");
// Complete all pending analysis tasks and flush the AST so that it won't
// be available immediately.
_performPendingAnalysisTasks();
_flushAst(source);
// Dispose of the context.
context.dispose();
// Any attempt to start an asynchronous computation should return a future
// which completes with error.
CancelableFuture<CompilationUnit> future =
context.computeResolvedCompilationUnitAsync(source, source);
bool completed = false;
future.then((CompilationUnit unit) {
fail('Future should have completed with error');
}, onError: (error) {
expect(error, new isInstanceOf<AnalysisNotScheduledError>());
completed = true;
});
return pumpEventQueue().then((_) {
expect(completed, isTrue);
});
}
Future test_computeResolvedCompilationUnitAsync_cancel() {
Source source = addSource("/lib.dart", "library lib;");
// Complete all pending analysis tasks and flush the AST so that it won't
// be available immediately.
_performPendingAnalysisTasks();
_flushAst(source);
CancelableFuture<CompilationUnit> future =
context.computeResolvedCompilationUnitAsync(source, source);
bool completed = false;
future.then((CompilationUnit unit) {
fail('Future should have been canceled');
}, onError: (error) {
expect(error, new isInstanceOf<FutureCanceledError>());
completed = true;
});
expect(completed, isFalse);
expect(context.pendingFutureSources_forTesting, isNotEmpty);
future.cancel();
expect(context.pendingFutureSources_forTesting, isEmpty);
return pumpEventQueue().then((_) {
expect(completed, isTrue);
expect(context.pendingFutureSources_forTesting, isEmpty);
});
}
Future test_computeResolvedCompilationUnitAsync_dispose() {
Source source = addSource("/lib.dart", "library lib;");
// Complete all pending analysis tasks and flush the AST so that it won't
// be available immediately.
_performPendingAnalysisTasks();
_flushAst(source);
bool completed = false;
CancelableFuture<CompilationUnit> future =
context.computeResolvedCompilationUnitAsync(source, source);
future.then((CompilationUnit unit) {
fail('Future should have completed with error');
}, onError: (error) {
expect(error, new isInstanceOf<AnalysisNotScheduledError>());
completed = true;
});
expect(completed, isFalse);
expect(context.pendingFutureSources_forTesting, isNotEmpty);
// Disposing of the context should cause all pending futures to complete
// with AnalysisNotScheduled, so that no clients are left hanging.
context.dispose();
expect(context.pendingFutureSources_forTesting, isEmpty);
return pumpEventQueue().then((_) {
expect(completed, isTrue);
expect(context.pendingFutureSources_forTesting, isEmpty);
});
}
Future test_computeResolvedCompilationUnitAsync_noCacheEntry() {
Source librarySource = addSource("/lib.dart", "library lib;");
Source partSource = addSource("/part.dart", "part of foo;");
bool completed = false;
context
.computeResolvedCompilationUnitAsync(partSource, librarySource)
.then((CompilationUnit unit) {
expect(unit, isNotNull);
completed = true;
});
return pumpEventQueue()
.then((_) {
expect(completed, isFalse);
_performPendingAnalysisTasks();
})
.then((_) => pumpEventQueue())
.then((_) {
expect(completed, isTrue);
});
}
void test_configurationData() {
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', 'UNUSED_DEFAULT');
expect(context.getConfigurationData(unusedKey), 'UNUSED_DEFAULT');
}
void test_dispose() {
expect(context.isDisposed, isFalse);
context.dispose();
expect(context.isDisposed, isTrue);
}
void test_ensureResolvedDartUnits_definingUnit_hasResolved() {
Source source = addSource('/test.dart', '');
LibrarySpecificUnit libTarget = new LibrarySpecificUnit(source, source);
analysisDriver.computeResult(libTarget, RESOLVED_UNIT);
CompilationUnit unit =
context.getCacheEntry(libTarget).getValue(RESOLVED_UNIT);
List<CompilationUnit> units = context.ensureResolvedDartUnits(source);
expect(units, unorderedEquals([unit]));
}
void test_ensureResolvedDartUnits_definingUnit_notResolved() {
Source source = addSource('/test.dart', '');
LibrarySpecificUnit libTarget = new LibrarySpecificUnit(source, source);
analysisDriver.computeResult(libTarget, RESOLVED_UNIT);
// flush
context
.getCacheEntry(libTarget)
.setState(RESOLVED_UNIT, CacheState.FLUSHED);
// schedule recomputing
List<CompilationUnit> units = context.ensureResolvedDartUnits(source);
expect(units, isNull);
// should be the next result to compute
TargetedResult nextResult = context.dartWorkManager.getNextResult();
expect(nextResult.target, libTarget);
expect(nextResult.result, RESOLVED_UNIT);
}
void test_ensureResolvedDartUnits_partUnit_hasResolved() {
Source libSource1 = addSource(
'/lib1.dart',
r'''
library lib;
part 'part.dart';
''');
Source libSource2 = addSource(
'/lib2.dart',
r'''
library lib;
part 'part.dart';
''');
Source partSource = addSource(
'/part.dart',
r'''
part of lib;
''');
LibrarySpecificUnit partTarget1 =
new LibrarySpecificUnit(libSource1, partSource);
LibrarySpecificUnit partTarget2 =
new LibrarySpecificUnit(libSource2, partSource);
analysisDriver.computeResult(partTarget1, RESOLVED_UNIT);
analysisDriver.computeResult(partTarget2, RESOLVED_UNIT);
CompilationUnit unit1 =
context.getCacheEntry(partTarget1).getValue(RESOLVED_UNIT);
CompilationUnit unit2 =
context.getCacheEntry(partTarget2).getValue(RESOLVED_UNIT);
List<CompilationUnit> units = context.ensureResolvedDartUnits(partSource);
expect(units, unorderedEquals([unit1, unit2]));
}
void test_ensureResolvedDartUnits_partUnit_notResolved() {
Source libSource1 = addSource(
'/lib1.dart',
r'''
library lib;
part 'part.dart';
''');
Source libSource2 = addSource(
'/lib2.dart',
r'''
library lib;
part 'part.dart';
''');
Source partSource = addSource(
'/part.dart',
r'''
part of lib;
''');
LibrarySpecificUnit partTarget1 =
new LibrarySpecificUnit(libSource1, partSource);
LibrarySpecificUnit partTarget2 =
new LibrarySpecificUnit(libSource2, partSource);
analysisDriver.computeResult(partTarget1, RESOLVED_UNIT);
analysisDriver.computeResult(partTarget2, RESOLVED_UNIT);
// flush
context
.getCacheEntry(partTarget1)
.setState(RESOLVED_UNIT, CacheState.FLUSHED);
context
.getCacheEntry(partTarget2)
.setState(RESOLVED_UNIT, CacheState.FLUSHED);
// schedule recomputing
List<CompilationUnit> units = context.ensureResolvedDartUnits(partSource);
expect(units, isNull);
// should be the next result to compute
TargetedResult nextResult = context.dartWorkManager.getNextResult();
expect(nextResult.target, anyOf(partTarget1, partTarget2));
expect(nextResult.result, RESOLVED_UNIT);
}
void test_exists_false() {
TestSource source = new TestSource();
source.exists2 = false;
expect(context.exists(source), isFalse);
}
void test_exists_null() {
expect(context.exists(null), isFalse);
}
void test_exists_overridden() {
Source source = new TestSource();
context.setContents(source, "");
expect(context.exists(source), isTrue);
}
void test_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);
}
void test_getContents_fromSource() {
String content = "library lib;";
TimestampedData<String> contents =
context.getContents(new TestSource('/test.dart', content));
expect(contents.data.toString(), content);
}
void test_getContents_notOverridden() {
String content = "library lib;";
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_overridden() {
String content = "library lib;";
Source source = new TestSource();
context.setContents(source, content);
TimestampedData<String> contents = context.getContents(source);
expect(contents.data.toString(), content);
}
void test_getDeclaredVariables() {
expect(context.declaredVariables, isNotNull);
}
void test_getElement() {
LibraryElement core =
context.computeLibraryElement(sourceFactory.forUri("dart:core"));
expect(core, isNotNull);
ClassElement classObject =
_findClass(core.definingCompilationUnit, "Object");
expect(classObject, isNotNull);
ElementLocation location = classObject.location;
Element element = context.getElement(location);
expect(element, same(classObject));
}
void test_getElement_constructor_named() {
Source source = addSource(
"/lib.dart",
r'''
class A {
A.named() {}
}''');
_analyzeAll_assertFinished();
LibraryElement library = context.computeLibraryElement(source);
ClassElement classA = _findClass(library.definingCompilationUnit, "A");
ConstructorElement constructor = classA.constructors[0];
ElementLocation location = constructor.location;
Element element = context.getElement(location);
expect(element, same(constructor));
}
void test_getElement_constructor_unnamed() {
Source source = addSource(
"/lib.dart",
r'''
class A {
A() {}
}''');
_analyzeAll_assertFinished();
LibraryElement library = context.computeLibraryElement(source);
ClassElement classA = _findClass(library.definingCompilationUnit, "A");
ConstructorElement constructor = classA.constructors[0];
ElementLocation location = constructor.location;
Element element = context.getElement(location);
expect(element, same(constructor));
}
void test_getElement_enum() {
Source source = addSource('/test.dart', 'enum MyEnum {A, B, C}');
_analyzeAll_assertFinished();
LibraryElement library = context.computeLibraryElement(source);
ClassElement myEnum = library.definingCompilationUnit.getEnum('MyEnum');
ElementLocation location = myEnum.location;
Element element = context.getElement(location);
expect(element, same(myEnum));
}
void test_getErrors_dart_none() {
Source source = addSource("/lib.dart", "library lib;");
var errorInfo = context.getErrors(source);
expect(errorInfo, isNotNull);
List<AnalysisError> errors = errorInfo.errors;
expect(errors, hasLength(0));
context.computeErrors(source);
errors = errorInfo.errors;
expect(errors, hasLength(0));
}
void test_getErrors_dart_some() {
Source source = addSource("/lib.dart", "library 'lib';");
var errorInfo = context.getErrors(source);
expect(errorInfo, isNotNull);
List<AnalysisError> errors = errorInfo.errors;
expect(errors, hasLength(0));
errors = context.computeErrors(source);
expect(errors, hasLength(1));
}
void test_getErrors_html_none() {
Source source = addSource("/test.html", "<html></html>");
AnalysisErrorInfo errorInfo = context.getErrors(source);
expect(errorInfo, isNotNull);
List<AnalysisError> errors = errorInfo.errors;
expect(errors, hasLength(0));
context.computeErrors(source);
errors = errorInfo.errors;
expect(errors, hasLength(0));
}
void test_getHtmlFilesReferencing_html() {
Source htmlSource = addSource(
"/test.html",
r'''
<html><head>
<script type='application/dart' src='test.dart'/>
<script type='application/dart' src='test.js'/>
</head></html>''');
Source librarySource = addSource("/test.dart", "library lib;");
Source secondHtmlSource = addSource("/test.html", "<html></html>");
context.computeLibraryElement(librarySource);
List<Source> result = context.getHtmlFilesReferencing(secondHtmlSource);
expect(result, hasLength(0));
context.parseHtmlDocument(htmlSource);
result = context.getHtmlFilesReferencing(secondHtmlSource);
expect(result, hasLength(0));
}
void test_getHtmlFilesReferencing_library() {
Source htmlSource = addSource(
"/test.html",
r'''
<!DOCTYPE html>
<html><head>
<script type='application/dart' src='test.dart'/>
<script type='application/dart' src='test.js'/>
</head></html>''');
Source librarySource = addSource("/test.dart", "library lib;");
context.computeLibraryElement(librarySource);
List<Source> result = context.getHtmlFilesReferencing(librarySource);
expect(result, hasLength(0));
// Indirectly force the data to be computed.
context.computeErrors(htmlSource);
result = context.getHtmlFilesReferencing(librarySource);
expect(result, hasLength(1));
expect(result[0], htmlSource);
}
void test_getHtmlFilesReferencing_part() {
Source htmlSource = addSource(
"/test.html",
r'''
<!DOCTYPE html>
<html><head>
<script type='application/dart' src='test.dart'/>
<script type='application/dart' src='test.js'/>
</head></html>''');
Source librarySource =
addSource("/test.dart", "library lib; part 'part.dart';");
Source partSource = addSource("/part.dart", "part of lib;");
context.computeLibraryElement(librarySource);
List<Source> result = context.getHtmlFilesReferencing(partSource);
expect(result, hasLength(0));
// Indirectly force the data to be computed.
context.computeErrors(htmlSource);
result = context.getHtmlFilesReferencing(partSource);
expect(result, hasLength(1));
expect(result[0], htmlSource);
}
void test_getHtmlSources() {
List<Source> sources = context.htmlSources;
expect(sources, hasLength(0));
Source source = addSource("/test.html", "");
sources = context.htmlSources;
expect(sources, hasLength(1));
expect(sources[0], source);
}
void test_getKindOf_html() {
Source source = addSource("/test.html", "");
expect(context.getKindOf(source), same(SourceKind.HTML));
}
void test_getKindOf_library() {
Source source = addSource("/test.dart", "library lib;");
expect(context.getKindOf(source), same(SourceKind.UNKNOWN));
context.computeKindOf(source);
expect(context.getKindOf(source), same(SourceKind.LIBRARY));
}
void test_getKindOf_part() {
Source source = addSource("/test.dart", "part of lib;");
expect(context.getKindOf(source), same(SourceKind.UNKNOWN));
context.computeKindOf(source);
expect(context.getKindOf(source), same(SourceKind.PART));
}
void test_getKindOf_unknown() {
Source source = addSource("/test.css", "");
expect(context.getKindOf(source), same(SourceKind.UNKNOWN));
}
void test_getLaunchableClientLibrarySources_doesNotImportHtml() {
Source source = addSource(
"/test.dart",
r'''
main() {}''');
context.computeLibraryElement(source);
List<Source> sources = context.launchableClientLibrarySources;
expect(sources, isEmpty);
}
void test_getLaunchableClientLibrarySources_importsHtml_explicitly() {
List<Source> sources = context.launchableClientLibrarySources;
expect(sources, isEmpty);
Source source = addSource(
"/test.dart",
r'''
import 'dart:html';
main() {}''');
context.computeLibraryElement(source);
sources = context.launchableClientLibrarySources;
expect(sources, unorderedEquals([source]));
}
void test_getLaunchableClientLibrarySources_importsHtml_implicitly() {
List<Source> sources = context.launchableClientLibrarySources;
expect(sources, isEmpty);
addSource(
'/a.dart',
r'''
import 'dart:html';
''');
Source source = addSource(
"/test.dart",
r'''
import 'a.dart';
main() {}''');
_analyzeAll_assertFinished();
sources = context.launchableClientLibrarySources;
expect(sources, unorderedEquals([source]));
}
void test_getLaunchableClientLibrarySources_importsHtml_implicitly2() {
List<Source> sources = context.launchableClientLibrarySources;
expect(sources, isEmpty);
addSource(
'/a.dart',
r'''
export 'dart:html';
''');
Source source = addSource(
"/test.dart",
r'''
import 'a.dart';
main() {}''');
_analyzeAll_assertFinished();
sources = context.launchableClientLibrarySources;
expect(sources, unorderedEquals([source]));
}
void test_getLaunchableServerLibrarySources() {
expect(context.launchableServerLibrarySources, isEmpty);
Source source = addSource("/test.dart", "main() {}");
context.computeLibraryElement(source);
expect(context.launchableServerLibrarySources, unorderedEquals([source]));
}
void test_getLaunchableServerLibrarySources_importsHtml_explicitly() {
Source source = addSource(
"/test.dart",
r'''
import 'dart:html';
main() {}
''');
context.computeLibraryElement(source);
expect(context.launchableServerLibrarySources, isEmpty);
}
void test_getLaunchableServerLibrarySources_importsHtml_implicitly() {
addSource(
"/imports_html.dart",
r'''
import 'dart:html';
''');
addSource(
"/test.dart",
r'''
import 'imports_html.dart';
main() {}''');
_analyzeAll_assertFinished();
expect(context.launchableServerLibrarySources, isEmpty);
}
void test_getLaunchableServerLibrarySources_noMain() {
Source source = addSource("/test.dart", '');
context.computeLibraryElement(source);
expect(context.launchableServerLibrarySources, isEmpty);
}
void test_getLibrariesContaining() {
Source librarySource = addSource(
"/lib.dart",
r'''
library lib;
part 'part.dart';''');
Source partSource = addSource("/part.dart", "part of lib;");
context.computeLibraryElement(librarySource);
List<Source> result = context.getLibrariesContaining(librarySource);
expect(result, hasLength(1));
expect(result[0], librarySource);
result = context.getLibrariesContaining(partSource);
expect(result, hasLength(1));
expect(result[0], librarySource);
}
void test_getLibrariesDependingOn() {
Source libASource = addSource("/libA.dart", "library libA;");
addSource("/libB.dart", "library libB;");
Source lib1Source = addSource(
"/lib1.dart",
r'''
library lib1;
import 'libA.dart';
export 'libB.dart';''');
Source lib2Source = addSource(
"/lib2.dart",
r'''
library lib2;
import 'libB.dart';
export 'libA.dart';''');
context.computeLibraryElement(lib1Source);
context.computeLibraryElement(lib2Source);
List<Source> result = context.getLibrariesDependingOn(libASource);
expect(result, unorderedEquals([lib1Source, lib2Source]));
}
void test_getLibrariesReferencedFromHtml() {
Source htmlSource = addSource(
"/test.html",
r'''
<!DOCTYPE html>
<html><head>
<script type='application/dart' src='test.dart'/>
<script type='application/dart' src='test.js'/>
</head></html>''');
Source librarySource = addSource("/test.dart", "library lib;");
context.computeLibraryElement(librarySource);
// Indirectly force the data to be computed.
context.computeErrors(htmlSource);
List<Source> result = context.getLibrariesReferencedFromHtml(htmlSource);
expect(result, hasLength(1));
expect(result[0], librarySource);
}
void test_getLibrariesReferencedFromHtml_none() {
Source htmlSource = addSource(
"/test.html",
r'''
<html><head>
<script type='application/dart' src='test.js'/>
</head></html>''');
addSource("/test.dart", "library lib;");
context.parseHtmlDocument(htmlSource);
List<Source> result = context.getLibrariesReferencedFromHtml(htmlSource);
expect(result, hasLength(0));
}
void test_getLibraryElement() {
Source source = addSource("/test.dart", "library lib;");
LibraryElement element = context.getLibraryElement(source);
expect(element, isNull);
context.computeLibraryElement(source);
element = context.getLibraryElement(source);
expect(element, isNotNull);
}
void test_getLibrarySources() {
List<Source> sources = context.librarySources;
int originalLength = sources.length;
Source source = addSource("/test.dart", "library lib;");
context.computeKindOf(source);
sources = context.librarySources;
expect(sources, hasLength(originalLength + 1));
for (Source returnedSource in sources) {
if (returnedSource == source) {
return;
}
}
fail("The added source was not in the list of library sources");
}
void test_getLibrarySources_inSDK() {
Source source = addSource(
'/test.dart',
r'''
import 'dart:async';
Stream S = null;
''');
LibraryElement testLibrary = context.computeLibraryElement(source);
// prepare "Stream" ClassElement
ClassElement streamElement;
{
CompilationUnitElement testUnit = testLibrary.definingCompilationUnit;
InterfaceType streamType = testUnit.topLevelVariables[0].type;
streamElement = streamType.element;
}
// must be from SDK context
AnalysisContext sdkContext = context.sourceFactory.dartSdk.context;
expect(sdkContext, streamElement.context);
Source intSource = streamElement.source;
// must be in the "async" library - SDK context
{
List<Source> coreLibraries = sdkContext.getLibrariesContaining(intSource);
expect(coreLibraries, hasLength(1));
Source coreSource = coreLibraries[0];
expect(coreSource.isInSystemLibrary, isTrue);
expect(coreSource.shortName, 'async.dart');
}
// must be in the "async" library - main context
{
List<Source> coreLibraries = context.getLibrariesContaining(intSource);
expect(coreLibraries, hasLength(1));
Source coreSource = coreLibraries[0];
expect(coreSource.isInSystemLibrary, isTrue);
expect(coreSource.shortName, 'async.dart');
}
}
void test_getLineInfo() {
Source source = addSource(
"/test.dart",
r'''
library lib;
main() {}''');
LineInfo info = context.getLineInfo(source);
expect(info, isNull);
context.parseCompilationUnit(source);
info = context.getLineInfo(source);
expect(info, isNotNull);
}
void test_getModificationStamp_fromSource() {
int stamp = 42;
expect(
context.getModificationStamp(
new _AnalysisContextImplTest_Source_getModificationStamp_fromSource(
stamp)),
stamp);
}
void test_getModificationStamp_overridden() {
int stamp = 42;
Source source =
new _AnalysisContextImplTest_Source_getModificationStamp_overridden(
stamp);
context.setContents(source, "");
expect(stamp != context.getModificationStamp(source), isTrue);
}
void test_getPublicNamespace_element() {
Source source = addSource("/test.dart", "class A {}");
LibraryElement library = context.computeLibraryElement(source);
expect(library, isNotNull);
Namespace namespace = context.getPublicNamespace(library);
expect(namespace, isNotNull);
EngineTestCase.assertInstanceOf(
(obj) => obj is ClassElement, ClassElement, namespace.get("A"));
}
void test_getResolvedCompilationUnit_library() {
Source source = addSource("/lib.dart", "library libb;");
LibraryElement library = context.computeLibraryElement(source);
context.computeErrors(source); // Force the resolved unit to be built.
expect(context.getResolvedCompilationUnit(source, library), isNotNull);
context.setContents(source, "library lib;");
expect(context.getResolvedCompilationUnit(source, library), isNull);
}
void test_getResolvedCompilationUnit_library_null() {
Source source = addSource("/lib.dart", "library lib;");
expect(context.getResolvedCompilationUnit(source, null), isNull);
}
void test_getResolvedCompilationUnit_source_dart() {
Source source = addSource("/lib.dart", "library lib;");
expect(context.getResolvedCompilationUnit2(source, source), isNull);
context.resolveCompilationUnit2(source, source);
expect(context.getResolvedCompilationUnit2(source, source), isNotNull);
}
void test_getSourceFactory() {
expect(context.sourceFactory, same(sourceFactory));
}
void test_getSourcesWithFullName() {
String filePath = '/foo/lib/file.dart';
List<Source> expected = <Source>[];
ChangeSet changeSet = new ChangeSet();
TestSourceWithUri source1 =
new TestSourceWithUri(filePath, Uri.parse('file://$filePath'));
expected.add(source1);
changeSet.addedSource(source1);
TestSourceWithUri source2 =
new TestSourceWithUri(filePath, Uri.parse('package:foo/file.dart'));
expected.add(source2);
changeSet.addedSource(source2);
context.applyChanges(changeSet);
expect(context.getSourcesWithFullName(filePath), unorderedEquals(expected));
}
void test_handleContentsChanged() {
ContentCache contentCache = new ContentCache();
context.contentCache = contentCache;
String oldContents = 'foo() {}';
String newContents = 'bar() {}';
// old contents
Source source = addSource("/test.dart", oldContents);
_analyzeAll_assertFinished();
expect(context.getResolvedCompilationUnit2(source, source), isNotNull);
// new contents
contentCache.setContents(source, newContents);
context.handleContentsChanged(source, oldContents, newContents, true);
// there is some work to do
AnalysisResult analysisResult = context.performAnalysisTask();
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);
//
// Create a file that references an file that is not explicitly being
// analyzed and fully analyze it. Ensure that the listener is told about
// the implicitly analyzed file.
//
Source sourceA = newSource('/a.dart', "library a; import 'b.dart';");
Source sourceB = newSource('/b.dart', "library b;");
ChangeSet changeSet = new ChangeSet();
changeSet.addedSource(sourceA);
context.applyChanges(changeSet);
context.computeErrors(sourceA);
await pumpEventQueue();
listener.expectAnalyzed(sourceB);
}
void test_isClientLibrary_dart() {
Source source = addSource(
"/test.dart",
r'''
import 'dart:html';
main() {}''');
expect(context.isClientLibrary(source), isFalse);
expect(context.isServerLibrary(source), isFalse);
context.computeLibraryElement(source);
expect(context.isClientLibrary(source), isTrue);
expect(context.isServerLibrary(source), isFalse);
}
void test_isClientLibrary_html() {
Source source = addSource("/test.html", "<html></html>");
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",
r'''
library lib;
main() {}''');
expect(context.isClientLibrary(source), isFalse);
expect(context.isServerLibrary(source), isFalse);
context.computeLibraryElement(source);
expect(context.isClientLibrary(source), isFalse);
expect(context.isServerLibrary(source), isTrue);
}
void test_isServerLibrary_html() {
Source source = addSource("/test.html", "<html></html>");
expect(context.isServerLibrary(source), isFalse);
}
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);
}
void test_parseCompilationUnit_exception() {
Source source = _addSourceWithException("/test.dart");
try {
context.parseCompilationUnit(source);
fail("Expected AnalysisException");
} on AnalysisException {
// Expected
}
}
void test_parseCompilationUnit_html() {
Source source = addSource("/test.html", "<html></html>");
expect(context.parseCompilationUnit(source), isNull);
}
void test_parseCompilationUnit_noErrors() {
Source source = addSource("/lib.dart", "library lib;");
CompilationUnit compilationUnit = context.parseCompilationUnit(source);
expect(compilationUnit, isNotNull);
AnalysisErrorInfo errorInfo = context.getErrors(source);
expect(errorInfo, isNotNull);
expect(errorInfo.errors, hasLength(0));
}
void test_parseCompilationUnit_nonExistentSource() {
Source source = newSource('/test.dart');
resourceProvider.deleteFile('/test.dart');
try {
context.parseCompilationUnit(source);
fail("Expected AnalysisException because file does not exist");
} on AnalysisException {
// Expected result
}
}
void test_parseHtmlDocument() {
Source source = addSource("/lib.html", "<!DOCTYPE html><html></html>");
Document document = context.parseHtmlDocument(source);
expect(document, isNotNull);
}
void test_parseHtmlUnit_resolveDirectives() {
Source libSource = addSource(
"/lib.dart",
r'''
library lib;
class ClassA {}''');
Source source = addSource(
"/lib.html",
r'''
<!DOCTYPE html>
<html>
<head>
<script type='application/dart'>
import 'lib.dart';
ClassA v = null;
</script>
</head>
<body>
</body>
</html>''');
Document document = context.parseHtmlDocument(source);
expect(document, isNotNull);
List<DartScript> scripts = context.computeResult(source, DART_SCRIPTS);
expect(scripts, hasLength(1));
CompilationUnit unit = context.computeResult(scripts[0], PARSED_UNIT);
ImportDirective importNode = unit.directives[0] as ImportDirective;
expect(importNode.uriContent, isNotNull);
expect(importNode.uriSource, libSource);
}
void test_performAnalysisTask_addPart() {
Source libSource = addSource(
"/lib.dart",
r'''
library lib;
part 'part.dart';''');
// run all tasks without part
_analyzeAll_assertFinished();
expect(_hasAnalysisErrorWithErrorSeverity(context.getErrors(libSource)),
isTrue,
reason: "lib has errors");
// add part and run all tasks
Source partSource = addSource(
"/part.dart",
r'''
part of lib;
''');
_analyzeAll_assertFinished();
// "libSource" should be here
List<Source> librariesWithPart = context.getLibrariesContaining(partSource);
expect(librariesWithPart, unorderedEquals([libSource]));
expect(_hasAnalysisErrorWithErrorSeverity(context.getErrors(libSource)),
isFalse,
reason: "lib doesn't have errors");
expect(
context.getResolvedCompilationUnit2(partSource, libSource), isNotNull,
reason: "part resolved");
}
void test_performAnalysisTask_changeLibraryContents() {
Source libSource =
addSource("/test.dart", "library lib; part 'test-part.dart';");
Source partSource = addSource("/test-part.dart", "part of lib;");
_analyzeAll_assertFinished();
expect(context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
reason: "library resolved 1");
expect(
context.getResolvedCompilationUnit2(partSource, libSource), isNotNull,
reason: "part resolved 1");
// update and analyze #1
context.setContents(libSource, "library lib;");
expect(context.getResolvedCompilationUnit2(libSource, libSource), isNull,
reason: "library changed 2");
expect(context.getResolvedCompilationUnit2(partSource, libSource), isNull,
reason: "part changed 2");
_analyzeAll_assertFinished();
expect(context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
reason: "library resolved 2");
expect(context.getResolvedCompilationUnit2(partSource, libSource), isNull,
reason: "part resolved 2");
// update and analyze #2
context.setContents(libSource, "library lib; part 'test-part.dart';");
expect(context.getResolvedCompilationUnit2(libSource, libSource), isNull,
reason: "library changed 3");
expect(context.getResolvedCompilationUnit2(partSource, libSource), isNull,
reason: "part changed 3");
_analyzeAll_assertFinished();
expect(context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
reason: "library resolved 3");
expect(
context.getResolvedCompilationUnit2(partSource, libSource), isNotNull,
reason: "part resolved 3");
}
void test_performAnalysisTask_changeLibraryThenPartContents() {
Source libSource =
addSource("/test.dart", "library lib; part 'test-part.dart';");
Source partSource = addSource("/test-part.dart", "part of lib;");
_analyzeAll_assertFinished();
expect(context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
reason: "library resolved 1");
expect(
context.getResolvedCompilationUnit2(partSource, libSource), isNotNull,
reason: "part resolved 1");
// update and analyze #1
context.setContents(libSource, "library lib;");
expect(context.getResolvedCompilationUnit2(libSource, libSource), isNull,
reason: "library changed 2");
expect(context.getResolvedCompilationUnit2(partSource, libSource), isNull,
reason: "part changed 2");
_analyzeAll_assertFinished();
expect(context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
reason: "library resolved 2");
expect(context.getResolvedCompilationUnit2(partSource, libSource), isNull,
reason: "part resolved 2");
// update and analyze #2
context.setContents(partSource, "part of lib; // 1");
// Assert that changing the part's content does not effect the library
// now that it is no longer part of that library
expect(context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
reason: "library changed 3");
expect(context.getResolvedCompilationUnit2(partSource, libSource), isNull,
reason: "part changed 3");
_analyzeAll_assertFinished();
expect(context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
reason: "library resolved 3");
expect(context.getResolvedCompilationUnit2(partSource, libSource), isNull,
reason: "part resolved 3");
}
void test_performAnalysisTask_changePartContents_makeItAPart() {
Source libSource = addSource(
"/lib.dart",
r'''
library lib;
part 'part.dart';
void f(x) {}''');
Source partSource = addSource("/part.dart", "void g() { f(null); }");
_analyzeAll_assertFinished();
expect(context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
reason: "library resolved 1");
expect(
context.getResolvedCompilationUnit2(partSource, partSource), isNotNull,
reason: "part resolved 1");
// update and analyze
context.setContents(
partSource,
r'''
part of lib;
void g() { f(null); }''');
expect(context.getResolvedCompilationUnit2(libSource, libSource), isNull,
reason: "library changed 2");
expect(context.getResolvedCompilationUnit2(partSource, partSource), isNull,
reason: "part changed 2");
_analyzeAll_assertFinished();
expect(context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
reason: "library resolved 2");
expect(
context.getResolvedCompilationUnit2(partSource, libSource), isNotNull,
reason: "part resolved 2");
expect(context.getErrors(libSource).errors, hasLength(0));
expect(context.getErrors(partSource).errors, hasLength(0));
}
/**
* https://code.google.com/p/dart/issues/detail?id=12424
*/
void test_performAnalysisTask_changePartContents_makeItNotPart() {
Source libSource = addSource(
"/lib.dart",
r'''
library lib;
part 'part.dart';
void f(x) {}''');
Source partSource = addSource(
"/part.dart",
r'''
part of lib;
void g() { f(null); }''');
_analyzeAll_assertFinished();
expect(context.getErrors(libSource).errors, hasLength(0));
expect(context.getErrors(partSource).errors, hasLength(0));
// Remove 'part' directive, which should make "f(null)" an error.
context.setContents(
partSource,
r'''
//part of lib;
void g() { f(null); }''');
_analyzeAll_assertFinished();
expect(context.getErrors(libSource).errors.length != 0, isTrue);
}
void test_performAnalysisTask_changePartContents_noSemanticChanges() {
Source libSource =
addSource("/test.dart", "library lib; part 'test-part.dart';");
Source partSource = addSource("/test-part.dart", "part of lib;");
_analyzeAll_assertFinished();
expect(context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
reason: "library resolved 1");
expect(
context.getResolvedCompilationUnit2(partSource, libSource), isNotNull,
reason: "part resolved 1");
// update and analyze #1
context.setContents(partSource, "part of lib; // 1");
if (context.analysisOptions.finerGrainedInvalidation) {
expect(
context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
reason: "library changed 2");
expect(
context.getResolvedCompilationUnit2(partSource, libSource), isNotNull,
reason: "part changed 2");
} else {
expect(context.getResolvedCompilationUnit2(libSource, libSource), isNull,
reason: "library changed 2");
expect(context.getResolvedCompilationUnit2(partSource, libSource), isNull,
reason: "part changed 2");
_analyzeAll_assertFinished();
expect(
context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
reason: "library resolved 2");
expect(
context.getResolvedCompilationUnit2(partSource, libSource), isNotNull,
reason: "part resolved 2");
}
// update and analyze #2
context.setContents(partSource, "part of lib; // 12");
if (context.analysisOptions.finerGrainedInvalidation) {
expect(
context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
reason: "library changed 3");
expect(
context.getResolvedCompilationUnit2(partSource, libSource), isNotNull,
reason: "part changed 3");
} else {
expect(context.getResolvedCompilationUnit2(libSource, libSource), isNull,
reason: "library changed 3");
expect(context.getResolvedCompilationUnit2(partSource, libSource), isNull,
reason: "part changed 3");
_analyzeAll_assertFinished();
expect(
context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
reason: "library resolved 3");
expect(
context.getResolvedCompilationUnit2(partSource, libSource), isNotNull,
reason: "part resolved 3");
}
}
void test_performAnalysisTask_getContentException_dart() {
Source source = _addSourceWithException('test.dart');
// prepare errors
_analyzeAll_assertFinished();
List<AnalysisError> errors = context.getErrors(source).errors;
// validate errors
expect(errors, hasLength(1));
AnalysisError error = errors[0];
expect(error.source, same(source));
expect(error.errorCode, ScannerErrorCode.UNABLE_GET_CONTENT);
}
void test_performAnalysisTask_getContentException_html() {
Source source = _addSourceWithException('test.html');
// prepare errors
_analyzeAll_assertFinished();
List<AnalysisError> errors = context.getErrors(source).errors;
// validate errors
expect(errors, hasLength(1));
AnalysisError error = errors[0];
expect(error.source, same(source));
expect(error.errorCode, ScannerErrorCode.UNABLE_GET_CONTENT);
}
void test_performAnalysisTask_importedLibraryAdd() {
Source libASource =
addSource("/libA.dart", "library libA; import 'libB.dart';");
_analyzeAll_assertFinished();
expect(
context.getResolvedCompilationUnit2(libASource, libASource), isNotNull,
reason: "libA resolved 1");
expect(_hasAnalysisErrorWithErrorSeverity(context.getErrors(libASource)),
isTrue,
reason: "libA has an error");
// add libB.dart and analyze
Source libBSource = addSource("/libB.dart", "library libB;");
_analyzeAll_assertFinished();
expect(
context.getResolvedCompilationUnit2(libASource, libASource), isNotNull,
reason: "libA resolved 2");
expect(
context.getResolvedCompilationUnit2(libBSource, libBSource), isNotNull,
reason: "libB resolved 2");
expect(_hasAnalysisErrorWithErrorSeverity(context.getErrors(libASource)),
isFalse,
reason: "libA doesn't have errors");
}
void test_performAnalysisTask_importedLibraryAdd_html() {
Source htmlSource = addSource(
"/page.html",
r'''
<html><body><script type="application/dart">
import '/libB.dart';
main() {print('hello dart');}
</script></body></html>''');
_analyzeAll_assertFinished();
context.computeErrors(htmlSource);
// expect(_hasAnalysisErrorWithErrorSeverity(context.getErrors(htmlSource)),
// isTrue,
// reason: "htmlSource has an error");
// add libB.dart and analyze
Source libBSource = addSource("/libB.dart", "library libB;");
_analyzeAll_assertFinished();
expect(
context.getResolvedCompilationUnit2(libBSource, libBSource), isNotNull,
reason: "libB resolved 2");
// TODO (danrubel) commented out to fix red bots
// context.computeErrors(htmlSource);
// AnalysisErrorInfo errors = _context.getErrors(htmlSource);
// expect(
// !_hasAnalysisErrorWithErrorSeverity(errors),
// isTrue,
// reason: "htmlSource doesn't have errors");
}
void test_performAnalysisTask_importedLibraryDelete() {
Source libASource =
addSource("/libA.dart", "library libA; import 'libB.dart';");
Source libBSource = addSource("/libB.dart", "library libB;");
_analyzeAll_assertFinished();
expect(
context.getResolvedCompilationUnit2(libASource, libASource), isNotNull,
reason: "libA resolved 1");
expect(
context.getResolvedCompilationUnit2(libBSource, libBSource), isNotNull,
reason: "libB resolved 1");
expect(!_hasAnalysisErrorWithErrorSeverity(context.getErrors(libASource)),
isTrue,
reason: "libA doesn't have errors");
// remove libB.dart and analyze
_removeSource(libBSource);
_analyzeAll_assertFinished();
expect(
context.getResolvedCompilationUnit2(libASource, libASource), isNotNull,
reason: "libA resolved 2");
expect(_hasAnalysisErrorWithErrorSeverity(context.getErrors(libASource)),
isTrue,
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;
_analyzeAll_assertFinished();
expect(source.readCount, 2);
_changeSource(source, "");
source.generateExceptionOnRead = true;
_analyzeAll_assertFinished();
if (context.analysisOptions.finerGrainedInvalidation) {
expect(source.readCount, 7);
} else {
expect(source.readCount, 5);
}
}
void test_performAnalysisTask_missingPart() {
Source source =
addSource("/test.dart", "library lib; part 'no-such-file.dart';");
_analyzeAll_assertFinished();
expect(context.getLibraryElement(source), isNotNull,
reason: "performAnalysisTask failed to compute an element model");
}
void test_performAnalysisTask_modifiedAfterParse() {
// TODO(scheglov) no threads in Dart
// Source source = _addSource("/test.dart", "library lib;");
// int initialTime = _context.getModificationStamp(source);
// List<Source> sources = <Source>[];
// sources.add(source);
// _context.analysisPriorityOrder = sources;
// _context.parseCompilationUnit(source);
// while (initialTime == JavaSystem.currentTimeMillis()) {
// Thread.sleep(1);
// // Force the modification time to be different.
// }
// _context.setContents(source, "library test;");
// JUnitTestCase.assertTrue(initialTime != _context.getModificationStamp(source));
// _analyzeAll_assertFinished();
// JUnitTestCase.assertNotNullMsg("performAnalysisTask failed to compute an element model", _context.getLibraryElement(source));
}
void test_performAnalysisTask_onResultChanged() {
Set<String> libraryElementUris = new Set<String>();
Set<String> parsedUnitUris = new Set<String>();
Set<String> resolvedUnitUris = new Set<String>();
// listen
context.onResultChanged(LIBRARY_ELEMENT).listen((event) {
expect(event.wasComputed, isTrue);
expect(event.wasInvalidated, isFalse);
Source librarySource = event.target;
libraryElementUris.add(librarySource.uri.toString());
});
context.onResultChanged(PARSED_UNIT).listen((event) {
expect(event.wasComputed, isTrue);
expect(event.wasInvalidated, isFalse);
Source source = event.target;
parsedUnitUris.add(source.uri.toString());
});
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());
});
// analyze
addSource('/test.dart', 'main() {}');
_analyzeAll_assertFinished();
// verify
expect(libraryElementUris, contains('file:///test.dart'));
expect(parsedUnitUris, contains('file:///test.dart'));
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{}");
addSource("/libB.dart", "library libB; class B{}");
CompilationUnit compilationUnit =
context.resolveCompilationUnit2(sourceA, sourceA);
expect(compilationUnit, isNotNull);
LibraryElement library = compilationUnit.element.library;
List<LibraryElement> importedLibraries = library.importedLibraries;
assertNamedElements(importedLibraries, ["dart.core", "libB"]);
}
void test_resolveCompilationUnit_import_relative_cyclic() {
Source sourceA =
addSource("/libA.dart", "library libA; import 'libB.dart'; class A{}");
addSource("/libB.dart", "library libB; import 'libA.dart'; class B{}");
CompilationUnit compilationUnit =
context.resolveCompilationUnit2(sourceA, sourceA);
expect(compilationUnit, isNotNull);
LibraryElement library = compilationUnit.element.library;
List<LibraryElement> importedLibraries = library.importedLibraries;
assertNamedElements(importedLibraries, ["dart.core", "libB"]);
}
// void test_resolveCompilationUnit_sourceChangeDuringResolution() {
// _context = new _AnalysisContext_sourceChangeDuringResolution();
// AnalysisContextFactory.initContextWithCore(_context);
// _sourceFactory = _context.sourceFactory;
// Source source = _addSource("/lib.dart", "library lib;");
// CompilationUnit compilationUnit =
// _context.resolveCompilationUnit2(source, source);
// expect(compilationUnit, isNotNull);
// 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 =
context.resolveCompilationUnit2(source, source);
expect(compilationUnit, isNotNull);
}
void test_setAnalysisOptions() {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.cacheSize = 42;
options.dart2jsHint = false;
options.hint = false;
context.analysisOptions = options;
AnalysisOptions result = context.analysisOptions;
expect(result.cacheSize, options.cacheSize);
expect(result.dart2jsHint, options.dart2jsHint);
expect(result.hint, options.hint);
}
void test_setAnalysisPriorityOrder() {
int priorityCount = 4;
List<Source> sources = <Source>[];
for (int index = 0; index < priorityCount; index++) {
sources.add(addSource("/lib.dart$index", ""));
}
context.analysisPriorityOrder = sources;
expect(_getPriorityOrder(context).length, priorityCount);
}
void test_setAnalysisPriorityOrder_empty() {
context.analysisPriorityOrder = <Source>[];
}
void test_setAnalysisPriorityOrder_nonEmpty() {
List<Source> sources = <Source>[];
sources.add(addSource("/lib.dart", "library lib;"));
context.analysisPriorityOrder = sources;
}
void test_setAnalysisPriorityOrder_resetAnalysisDriver() {
Source source = addSource('/lib.dart', 'library lib;');
// start analysis
context.performAnalysisTask();
expect(context.driver.currentWorkOrder, isNotNull);
// set priority sources, AnalysisDriver is reset
context.analysisPriorityOrder = <Source>[source];
expect(context.driver.currentWorkOrder, isNull);
// analysis continues
context.performAnalysisTask();
expect(context.driver.currentWorkOrder, isNotNull);
}
Future test_setChangedContents_libraryWithPart() {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.incremental = true;
context.analysisOptions = options;
SourcesChangedListener listener = new SourcesChangedListener();
context.onSourcesChanged.listen(listener.onData);
String oldCode = r'''
library lib;
part 'part.dart';
int a = 0;''';
Source librarySource = addSource("/lib.dart", oldCode);
String partContents = r'''
part of lib;
int b = a;''';
Source partSource = addSource("/part.dart", partContents);
LibraryElement element = context.computeLibraryElement(librarySource);
CompilationUnit unit =
context.resolveCompilationUnit(librarySource, element);
expect(unit, isNotNull);
int offset = oldCode.indexOf("int a") + 4;
String newCode = r'''
library lib;
part 'part.dart';
int ya = 0;''';
context.setChangedContents(librarySource, newCode, offset, 0, 1);
expect(context.getContents(librarySource).data, newCode);
expect(
context.getResolvedCompilationUnit2(partSource, librarySource), isNull);
return pumpEventQueue().then((_) {
listener.assertEvent(wereSourcesAdded: true);
listener.assertEvent(wereSourcesAdded: true);
listener.assertEvent(changedSources: [librarySource]);
listener.assertNoMoreEvents();
});
}
void test_setChangedContents_notResolved() {
AnalysisOptionsImpl options =
new AnalysisOptionsImpl.from(context.analysisOptions);
options.incremental = true;
context.analysisOptions = options;
String oldCode = r'''
library lib;
int a = 0;''';
Source librarySource = addSource("/lib.dart", oldCode);
int offset = oldCode.indexOf("int a") + 4;
String newCode = r'''
library lib;
int ya = 0;''';
context.setChangedContents(librarySource, newCode, offset, 0, 1);
expect(context.getContents(librarySource).data, newCode);
}
Future test_setContents_libraryWithPart() {
SourcesChangedListener listener = new SourcesChangedListener();
context.onSourcesChanged.listen(listener.onData);
String libraryContents1 = r'''
library lib;
part 'part.dart';
int a = 0;''';
Source librarySource = addSource("/lib.dart", libraryContents1);
String partContents1 = r'''
part of lib;
int b = a;''';
Source partSource = addSource("/part.dart", partContents1);
context.computeLibraryElement(librarySource);
String libraryContents2 = r'''
library lib;
part 'part.dart';
int aa = 0;''';
context.setContents(librarySource, libraryContents2);
expect(
context.getResolvedCompilationUnit2(partSource, librarySource), isNull);
return pumpEventQueue().then((_) {
listener.assertEvent(wereSourcesAdded: true);
listener.assertEvent(wereSourcesAdded: true);
listener.assertEvent(changedSources: [librarySource]);
listener.assertNoMoreEvents();
});
}
void test_setContents_null() {
Source librarySource = addSource(
"/lib.dart",
r'''
library lib;
int a = 0;''');
context.setContents(librarySource, '// different');
context.computeLibraryElement(librarySource);
context.setContents(librarySource, null);
expect(context.getResolvedCompilationUnit2(librarySource, librarySource),
isNull);
}
void test_setContents_unchanged_consistentModificationTime() {
String contents = "// foo";
Source source = addSource("/test.dart", contents);
context.setContents(source, contents);
// do all, no tasks
_analyzeAll_assertFinished();
{
AnalysisResult result = context.performAnalysisTask();
expect(result.changeNotices, isNull);
}
// set the same contents, still no tasks
context.setContents(source, contents);
{
AnalysisResult result = context.performAnalysisTask();
expect(result.changeNotices, isNull);
}
}
void test_setSourceFactory() {
expect(context.sourceFactory, sourceFactory);
SourceFactory factory = new SourceFactory([]);
context.sourceFactory = factory;
expect(context.sourceFactory, factory);
}
void test_updateAnalysis() {
expect(context.sourcesNeedingProcessing, isEmpty);
Source source = newSource('/test.dart');
AnalysisDelta delta = new AnalysisDelta();
delta.setAnalysisLevel(source, AnalysisLevel.ALL);
context.applyAnalysisDelta(delta);
expect(context.sourcesNeedingProcessing, contains(source));
delta = new AnalysisDelta();
delta.setAnalysisLevel(source, AnalysisLevel.NONE);
context.applyAnalysisDelta(delta);
expect(context.sourcesNeedingProcessing.contains(source), isFalse);
}
void test_validateCacheConsistency_deletedFile() {
MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
var fileA = resourceProvider.newFile('/a.dart', "");
var fileB = resourceProvider.newFile('/b.dart', "import 'a.dart';");
Source sourceA = fileA.createSource();
Source sourceB = fileB.createSource();
context.applyChanges(
new ChangeSet()..addedSource(sourceA)..addedSource(sourceB));
// analyze everything
_analyzeAll_assertFinished();
// delete a.dart
resourceProvider.deleteFile('/a.dart');
// analysis should eventually stop
_analyzeAll_assertFinished();
}
void xtest_performAnalysisTask_stress() {
int maxCacheSize = 4;
AnalysisOptionsImpl options =
new AnalysisOptionsImpl.from(context.analysisOptions);
options.cacheSize = maxCacheSize;
context.analysisOptions = options;
int sourceCount = maxCacheSize + 2;
List<Source> sources = <Source>[];
ChangeSet changeSet = new ChangeSet();
for (int i = 0; i < sourceCount; i++) {
Source source = addSource("/lib$i.dart", "library lib$i;");
sources.add(source);
changeSet.addedSource(source);
}
context.applyChanges(changeSet);
context.analysisPriorityOrder = sources;
for (int i = 0; i < 1000; i++) {
List<ChangeNotice> notice = context.performAnalysisTask().changeNotices;
if (notice == null) {
//System.out.println("test_performAnalysisTask_stress: " + i);
break;
}
}
List<ChangeNotice> notice = context.performAnalysisTask().changeNotices;
if (notice != null) {
fail(
"performAnalysisTask failed to terminate after analyzing all sources");
}
}
TestSource _addSourceWithException(String fileName) {
return _addSourceWithException2(fileName, "");
}
TestSource _addSourceWithException2(String fileName, String contents) {
TestSource source = new TestSource(fileName, contents);
source.generateExceptionOnRead = true;
ChangeSet changeSet = new ChangeSet();
changeSet.addedSource(source);
context.applyChanges(changeSet);
return source;
}
/**
* Perform analysis tasks up to 512 times and assert that it was enough.
*/
void _analyzeAll_assertFinished([int maxIterations = 512]) {
for (int i = 0; i < maxIterations; i++) {
List<ChangeNotice> notice = context.performAnalysisTask().changeNotices;
if (notice == null) {
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();
changeSet.changedSource(source);
context.applyChanges(changeSet);
}
/**
* Search the given compilation unit for a class with the given name. Return the class with the
* given name, or `null` if the class cannot be found.
*
* @param unit the compilation unit being searched
* @param className the name of the class being searched for
* @return the class with the given name
*/
ClassElement _findClass(CompilationUnitElement unit, String className) {
for (ClassElement classElement in unit.types) {
if (classElement.displayName == className) {
return classElement;
}
}
return null;
}
void _flushAst(Source source) {
CacheEntry entry =
context.getCacheEntry(new LibrarySpecificUnit(source, source));
entry.setState(RESOLVED_UNIT, CacheState.FLUSHED);
}
List<Source> _getPriorityOrder(AnalysisContextImpl context) {
return context.test_priorityOrder;
}
void _performPendingAnalysisTasks([int maxTasks = 512]) {
for (int i = 0; context.performAnalysisTask().hasMoreWork; i++) {
if (i > maxTasks) {
fail('Analysis did not terminate.');
}
}
}
void _removeSource(Source source) {
resourceProvider.deleteFile(source.fullName);
ChangeSet changeSet = new ChangeSet();
changeSet.removedSource(source);
context.applyChanges(changeSet);
}
/**
* Returns `true` if there is an [AnalysisError] with [ErrorSeverity.ERROR] in
* the given [AnalysisErrorInfo].
*/
static bool _hasAnalysisErrorWithErrorSeverity(AnalysisErrorInfo errorInfo) {
List<AnalysisError> errors = errorInfo.errors;
for (AnalysisError analysisError in errors) {
if (analysisError.errorCode.errorSeverity == ErrorSeverity.ERROR) {
return true;
}
}
return false;
}
}
@reflectiveTest
class LimitedInvalidateTest extends AbstractContextTest {
@override
void setUp() {
super.setUp();
AnalysisOptionsImpl options =
new AnalysisOptionsImpl.from(context.analysisOptions);
options.incremental = true;
options.finerGrainedInvalidation = true;
context.analysisOptions = options;
}
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_class_addMethod_useAsHole_inTopLevelVariable() {
Source a = addSource(
'/a.dart',
r'''
class A {
}
''');
Source b = addSource(
'/b.dart',
r'''
import 'a.dart';
var B = A.foo;
''');
Source c = addSource(
'/c.dart',
r'''
import 'b.dart';
var C = B;
''');
_performPendingAnalysisTasks();
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(
a,
r'''
class A {
static void foo(int p) {}
}
''');
_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_class_addMethod_useClass() {
Source a = addSource(
'/a.dart',
r'''
class A {}
class B extends A {
foo() {}
}
''');
Source b = addSource(
'/b.dart',
r'''
import 'a.dart';
B b = null;
''');
_performPendingAnalysisTasks();
// Update a.dart: remove add A.bar.
// b.dart is valid, because though it uses A, it has the same element.
context.setContents(
a,
r'''
class A {}
class B extends A {
foo() {}
bar() {}
}
''');
_assertValidForChangedLibrary(a);
_assertInvalid(a, LIBRARY_ERRORS_READY);
_assertValidForDependentLibrary(b);
_assertValidAllLibraryUnitResults(b);
_assertValid(b, LIBRARY_ERRORS_READY);
}
void test_class_annotation_add_deprecated() {
Source a = addSource(
'/a.dart',
r'''
class A {}
''');
Source b = addSource(
'/b.dart',
r'''
import 'a.dart';
List<A> foo() => [];
''');
_performPendingAnalysisTasks();
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(
a,
r'''
@deprecated
class A {}
''');
_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(b).errors, hasLength(1));
// Add @deprecated annotation.
// b.dart has valid resolution, because A is still A, so only errors are
// invalidated.
context.setContents(
a,
r'''
class A {}
''');
_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(0));
}
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'''
class A {
A.named();
}
''',
r'''
class A {
A.named2();
}
''',
r'''
import 'a.dart';
main() {
new A.named();
}
''');
}
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'''
class A {
A.named();
}
''',
r'''
class A {
A.named(int p);
}
''',
r'''
import 'a.dart';
main() {
new A.named();
}
''');
}
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'''
class A {
A.named(int a);
}
''',
r'''
class A {
A.named(String a);
}
''',
r'''
import 'a.dart';
class B extends A {
B() : super.named(42);
}
''');
}
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);
}
''',
r'''
class A {
A.named();
}
''',
r'''
import 'a.dart';
main() {
new A.named();
}
''');
}
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'''
class A {
A.foo();
A.bar();
}
''',
r'''
class A {
A.bar();
}
''',
r'''
import 'a.dart';
main() {
new A.bar();
}
''');
}
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, 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]) {
for (int i = 0; context.performAnalysisTask().hasMoreWork; i++) {
if (i > maxTasks) {
fail('Analysis did not terminate.');
}
}
}
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
implements SourceContainer {
Source libB;
_AnalysisContextImplTest_test_applyChanges_removeContainer(this.libB);
@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);
}
}