blob: 35c7750d36c0b2ec8dc2113775f220f7917c9108 [file] [log] [blame]
// Copyright (c) 2016, 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.
import 'dart:async';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/dart/analysis/driver_event.dart' as driver_events;
import 'package:analyzer/src/dart/analysis/file_state.dart';
import 'package:analyzer/src/dart/analysis/status.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/utilities/extensions/async.dart';
import 'package:linter/src/rules.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../../../util/element_printer.dart';
import '../../../util/tree_string_sink.dart';
import '../resolution/context_collection_resolution.dart';
import '../resolution/node_text_expectations.dart';
import '../resolution/resolution.dart';
import 'result_printer.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(AnalysisDriver_PubPackageTest);
defineReflectiveTests(AnalysisDriver_BlazeWorkspaceTest);
defineReflectiveTests(UpdateNodeTextExpectations);
});
}
@reflectiveTest
class AnalysisDriver_BlazeWorkspaceTest extends BlazeWorkspaceResolutionTest {
void test_nestedLib_notCanonicalUri() async {
var outerLibPath = '$workspaceRootPath/my/outer/lib';
var innerFile = newFile('$outerLibPath/inner/lib/b.dart', 'class B {}');
var innerUri = Uri.parse('package:my.outer.lib.inner/b.dart');
var analysisSession = contextFor(innerFile).currentSession;
void assertInnerUri(ResolvedUnitResult result) {
var innerLibrary = result.libraryElement.importedLibraries
.where((e) => e.source.fullName == innerFile.path)
.single;
expect(innerLibrary.source.uri, innerUri);
}
// Reference "inner" using a non-canonical URI.
{
var a = newFile(convertPath('$outerLibPath/a.dart'), r'''
import 'inner/lib/b.dart';
''');
var result = await analysisSession.getResolvedUnit(a.path);
result as ResolvedUnitResult;
assertInnerUri(result);
}
// Reference "inner" using the canonical URI, via relative.
{
var c = newFile('$outerLibPath/inner/lib/c.dart', r'''
import 'b.dart';
''');
var result = await analysisSession.getResolvedUnit(c.path);
result as ResolvedUnitResult;
assertInnerUri(result);
}
// Reference "inner" using the canonical URI, via absolute.
{
var d = newFile('$outerLibPath/inner/lib/d.dart', '''
import '$innerUri';
''');
var result = await analysisSession.getResolvedUnit(d.path);
result as ResolvedUnitResult;
assertInnerUri(result);
}
}
}
@reflectiveTest
class AnalysisDriver_PubPackageTest extends PubPackageResolutionTest {
final DriverEventsPrinterConfiguration configuration =
DriverEventsPrinterConfiguration();
@override
bool get retainDataForTesting => true;
Future<void> assertEventsText(
DriverEventCollector collector,
String expected,
) async {
await pumpEventQueue(times: 5000);
var buffer = StringBuffer();
var sink = TreeStringSink(sink: buffer, indent: '');
var elementPrinter = ElementPrinter(
sink: sink,
configuration: ElementPrinterConfiguration(),
selfUriStr: null,
);
var events = collector.take();
DriverEventsPrinter(
configuration: configuration,
sink: sink,
elementPrinter: elementPrinter,
idProvider: collector.idProvider,
).write(events);
var actual = buffer.toString();
if (actual != expected) {
print('-------- Actual --------');
print('$actual------------------------');
NodeTextExpectationsCollector.add(actual);
}
expect(actual, expected);
}
@override
void setUp() {
super.setUp();
registerLintRules();
useEmptyByteStore();
}
test_addedFiles() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var b = newFile('$testPackageLibPath/b.dart', '');
var driver = driverFor(testFile);
driver.addFile2(a);
driver.addFile2(b);
await driver.applyPendingFileChanges();
expect(driver.addedFiles2, unorderedEquals([a, b]));
driver.removeFile2(a);
await driver.applyPendingFileChanges();
expect(driver.addedFiles2, unorderedEquals([b]));
}
test_addFile() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var b = newFile('$testPackageLibPath/b.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(b);
driver.addFile2(a);
// The files are analyzed in the order of adding.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[status] idle
''');
}
test_addFile_afterRemove() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
class A {}''');
var b = newFile('$testPackageLibPath/b.dart', r'''
import 'a.dart';
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
driver.addFile2(b);
// Initial analysis, `b` does not use `a`, so there is a hint.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
errors
7 +8 UNUSED_IMPORT
[status] idle
''');
// Update `b` to use `a`, no more hints.
modifyFile2(b, r'''
import 'a.dart';
void f() {
A;
}
''');
// Remove and add `b`.
driver.removeFile2(b);
driver.addFile2(b);
// `b` was analyzed, no more hints.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #2
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[status] idle
''');
}
test_addFile_library_producesMacroGenerated() async {
if (!configureWithCommonMacros()) {
return;
}
var a = newFile('$testPackageLibPath/a.dart', r'''
import 'append.dart';
@DeclareTypesPhase('B', 'class B {}')
class A {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
await collector.nextStatusIdle();
// We produced both the library, and its macro-generated file.
configuration.withMacroFileContent();
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #1
path: /home/test/lib/a.macro.dart
uri: package:test/a.macro.dart
flags: exists isAugmentation isMacroAugmentation
content
---
augment library 'package:test/a.dart';
class B {}
---
[status] idle
''');
}
test_addFile_notAbsolutePath() async {
var driver = driverFor(testFile);
expect(() {
driver.addFile('not_absolute.dart');
}, throwsArgumentError);
}
test_addFile_priorityFiles() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var b = newFile('$testPackageLibPath/b.dart', '');
var c = newFile('$testPackageLibPath/c.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
driver.addFile2(b);
driver.addFile2(c);
driver.priorityFiles2 = [b];
// 1. The priority file is produced first.
// 2. Each analyzed file produces `ResolvedUnitResult`.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/c.dart
library: /home/test/lib/c.dart
[stream]
ResolvedUnitResult #2
path: /home/test/lib/c.dart
uri: package:test/c.dart
flags: exists isLibrary
[status] idle
''');
}
test_addFile_removeFile() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// Add, and immediately remove.
driver.addFile2(a);
driver.removeFile2(a);
// No files to analyze.
await assertEventsText(collector, r'''
[status] working
[status] idle
''');
}
test_addFile_thenRemove() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var b = newFile('$testPackageLibPath/b.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
driver.addFile2(b);
// Now remove `a`.
driver.removeFile2(a);
// We remove `a` before analysis started.
// So, only `b` was analyzed.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[status] idle
''');
}
test_cachedPriorityResults() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.priorityFiles2 = [a];
// Get the result, not cached.
collector.getResolvedUnit('A1', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[status] idle
''');
// Get the (cached) result, not reported to the stream.
collector.getResolvedUnit('A2', a);
await assertEventsText(collector, r'''
[future] getResolvedUnit A2
ResolvedUnitResult #0
''');
// Get the (cached) result, reported to the stream.
collector.getResolvedUnit('A3', a, sendCachedToStream: true);
await assertEventsText(collector, r'''
[stream]
ResolvedUnitResult #0
[future] getResolvedUnit A3
ResolvedUnitResult #0
''');
}
test_cachedPriorityResults_flush_onAnyFileChange() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var b = newFile('$testPackageLibPath/b.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.priorityFiles2 = [a];
collector.getResolvedUnit('A1', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[status] idle
''');
// Change a file.
// The cache is flushed, so we get a new result.
driver.changeFile2(a);
collector.getResolvedUnit('A2', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A2
ResolvedUnitResult #1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #1
[status] idle
''');
// Add `b`.
// The cache is flushed, so we get a new result.
driver.addFile2(b);
collector.getResolvedUnit('A3', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A3
ResolvedUnitResult #2
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #2
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #3
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[status] idle
''');
// Remove `b`.
// The cache is flushed, so we get a new result.
driver.removeFile2(b);
collector.getResolvedUnit('A4', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A4
ResolvedUnitResult #4
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #4
[status] idle
''');
}
test_cachedPriorityResults_flush_onPrioritySetChange() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var b = newFile('$testPackageLibPath/b.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.priorityFiles2 = [a];
// Get the result for `a`, new.
collector.getResolvedUnit('A1', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[status] idle
''');
// Make `a` and `b` priority.
// We still have the result for `a` cached.
driver.priorityFiles2 = [a, b];
collector.getResolvedUnit('A2', a);
await assertEventsText(collector, r'''
[status] working
[future] getResolvedUnit A2
ResolvedUnitResult #0
[status] idle
''');
// Get the result for `b`, new.
collector.getResolvedUnit('B1', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[future] getResolvedUnit B1
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #1
[status] idle
''');
// Get the result for `b`, cached.
collector.getResolvedUnit('B2', b);
await assertEventsText(collector, r'''
[future] getResolvedUnit B2
ResolvedUnitResult #1
''');
// Only `b` is priority.
// The result for `a` is flushed, so analyzed when asked.
driver.priorityFiles2 = [b];
collector.getResolvedUnit('A3', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A3
ResolvedUnitResult #2
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #2
[status] idle
''');
}
test_cachedPriorityResults_notPriority() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// Always analyzed the first time.
collector.getResolvedUnit('A1', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[status] idle
''');
// Analyzed again, because `a` is not priority.
collector.getResolvedUnit('A2', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A2
ResolvedUnitResult #1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #1
[status] idle
''');
}
test_cachedPriorityResults_wholeLibrary_priorityLibrary_askLibrary() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
part 'b.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of 'a.dart';
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.priorityFiles2 = [a];
// Ask the result for `a`, should cache for both `a` and `b`.
collector.getResolvedUnit('A1', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[status] idle
''');
// Verify that the results for `a` and `b` are cached.
// Note, no analysis.
collector.getResolvedUnit('A2', a);
collector.getResolvedUnit('B1', b);
await assertEventsText(collector, r'''
[future] getResolvedUnit A2
ResolvedUnitResult #0
[future] getResolvedUnit B1
ResolvedUnitResult #1
''');
// Ask for resolved library.
// Note, no analysis.
// Note, the units are cached.
collector.getResolvedLibrary('L1', a);
await assertEventsText(collector, r'''
[future] getResolvedLibrary L1
ResolvedLibraryResult #2
element: package:test/a.dart
units
ResolvedUnitResult #0
ResolvedUnitResult #1
''');
}
test_cachedPriorityResults_wholeLibrary_priorityLibrary_askPart() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
part 'b.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of 'a.dart';
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.priorityFiles2 = [a];
// Ask the result for `b`, should cache for both `a` and `b`.
collector.getResolvedUnit('B1', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getResolvedUnit B1
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[stream]
ResolvedUnitResult #1
[status] idle
''');
// Verify that the results for `a` and `b` are cached.
// Note, no analysis.
collector.getResolvedUnit('A1', a);
collector.getResolvedUnit('B2', b);
await assertEventsText(collector, r'''
[future] getResolvedUnit A1
ResolvedUnitResult #0
[future] getResolvedUnit B2
ResolvedUnitResult #1
''');
// Ask for resolved library.
// Note, no analysis.
// Note, the units are cached.
collector.getResolvedLibrary('L1', a);
await assertEventsText(collector, r'''
[future] getResolvedLibrary L1
ResolvedLibraryResult #2
element: package:test/a.dart
units
ResolvedUnitResult #0
ResolvedUnitResult #1
''');
}
test_cachedPriorityResults_wholeLibrary_priorityPart_askPart() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
part 'b.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of 'a.dart';
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.priorityFiles2 = [b];
// Ask the result for `b`, should cache for both `a` and `b`.
collector.getResolvedUnit('B1', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getResolvedUnit B1
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[stream]
ResolvedUnitResult #1
[status] idle
''');
// Verify that the results for `a` and `b` are cached.
// Note, no analysis.
collector.getResolvedUnit('A1', a);
collector.getResolvedUnit('B2', b);
await assertEventsText(collector, r'''
[future] getResolvedUnit A1
ResolvedUnitResult #0
[future] getResolvedUnit B2
ResolvedUnitResult #1
''');
// Ask for resolved library.
// Note, no analysis.
// Note, the units are cached.
collector.getResolvedLibrary('L1', a);
await assertEventsText(collector, r'''
[future] getResolvedLibrary L1
ResolvedLibraryResult #2
element: package:test/a.dart
units
ResolvedUnitResult #0
ResolvedUnitResult #1
''');
}
test_changeFile_implicitlyAnalyzed() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
import 'b.dart';
var A = B;
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
var B = 0;
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.priorityFiles2 = [a];
driver.addFile2(a);
configuration.libraryConfiguration.unitConfiguration.nodeSelector =
(result) {
return result.findNode.simple('B;');
};
// We have a result only for "a".
// The type of `B` is `int`.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
selectedNode: SimpleIdentifier
token: B
staticElement: package:test/b.dart::@getter::B
staticType: int
[status] idle
''');
// Change "b" and notify.
modifyFile2(b, r'''
var B = 1.2;
''');
driver.changeFile2(b);
// While "b" is not analyzed explicitly, it is analyzed implicitly.
// The change causes "a" to be reanalyzed.
// The type of `B` is now `double`.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
selectedNode: SimpleIdentifier
token: B
staticElement: package:test/b.dart::@getter::B
staticType: double
[status] idle
''');
}
test_changeFile_library_producesMacroGenerated() async {
if (!configureWithCommonMacros()) {
return;
}
var a = newFile('$testPackageLibPath/a.dart', r'''
import 'append.dart';
@DeclareTypesPhase('B', 'class B {}')
class A {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
// Discard results so far.
await collector.nextStatusIdle();
collector.take();
modifyFile2(a, r'''
import 'append.dart';
@DeclareTypesPhase('B2', 'class B2 {}')
class A {}
''');
driver.changeFile2(a);
await collector.nextStatusIdle();
// We produced both the library, and its macro-generated file.
configuration.withMacroFileContent();
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #1
path: /home/test/lib/a.macro.dart
uri: package:test/a.macro.dart
flags: exists isAugmentation isMacroAugmentation
content
---
augment library 'package:test/a.dart';
class B2 {}
---
[status] idle
''');
}
test_changeFile_macroImpl_macroGenerated_ifPriority() async {
if (!configureWithCommonMacros()) {
return;
}
File addMacroFile(String className) {
return newFile('$testPackageLibPath/a.dart', '''
import 'package:macros/macros.dart';
macro class MyMacro implements ClassTypesMacro {
const MyMacro();
buildTypesForClass(clazz, builder) {
builder.declareType(
'$className',
DeclarationCode.fromString('class $className {}'),
);
}
}
''');
}
// The macro declares `A1`.
var a = addMacroFile('A1');
var b = newFile('$testPackageLibPath/b.dart', r'''
import 'a.dart';
@MyMacro()
class B {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// Subscribe for errors in `b`.
driver.addFile2(b);
// As if the user opened `b.macro.dart` in the editor.
driver.priorityFiles2 = [b.macroForLibrary!];
// Discard results so far.
await collector.nextStatusIdle();
collector.take();
// Declares `A2` instead of `A1`.
addMacroFile('A2');
driver.changeFile2(a);
await collector.nextStatusIdle();
// There are no cached errors for `MyMacro` with `A2`.
// So, we analyze the whole library.
// We produce both the library, and its macro-generated file.
// Note, the macro-generated file has `A2`.
configuration.withMacroFileContent();
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.macro.dart
uri: package:test/b.macro.dart
flags: exists isAugmentation isMacroAugmentation
content
---
augment library 'package:test/b.dart';
class A2 {}
---
[status] idle
''');
// Declares again `A1`, was `A2`.
addMacroFile('A1');
driver.changeFile2(a);
await collector.nextStatusIdle();
// The macro-generated file is priority, so we need the resolved unit.
// We analyze the whole library.
// Note, the macro-generated file has `A1`.
configuration.withMacroFileContent();
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #2
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #3
path: /home/test/lib/b.macro.dart
uri: package:test/b.macro.dart
flags: exists isAugmentation isMacroAugmentation
content
---
augment library 'package:test/b.dart';
class A1 {}
---
[status] idle
''');
}
test_changeFile_macroImpl_macroGenerated_notPriority() async {
if (!configureWithCommonMacros()) {
return;
}
File addMacroFile(String className) {
return newFile('$testPackageLibPath/a.dart', '''
import 'package:macros/macros.dart';
macro class MyMacro implements ClassTypesMacro {
const MyMacro();
buildTypesForClass(clazz, builder) {
builder.declareType(
'$className',
DeclarationCode.fromString('class $className {}'),
);
}
}
''');
}
// The macro declares `A1`.
var a = addMacroFile('A1');
var b = newFile('$testPackageLibPath/b.dart', r'''
import 'a.dart';
@MyMacro()
class B {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// Subscribe for errors in `b`.
driver.addFile2(b);
// Discard results so far.
await collector.nextStatusIdle();
collector.take();
// Declares `A2` instead of `A1`.
addMacroFile('A2');
driver.changeFile2(a);
await collector.nextStatusIdle();
// There are no cached errors for `MyMacro` with `A2`.
// So, we analyze the whole library.
// We produce both the library, and its macro-generated file.
// Note, the macro-generated file has `A2`.
configuration.withMacroFileContent();
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.macro.dart
uri: package:test/b.macro.dart
flags: exists isAugmentation isMacroAugmentation
content
---
augment library 'package:test/b.dart';
class A2 {}
---
[status] idle
''');
// Declares again `A1`, was `A2`.
addMacroFile('A1');
driver.changeFile2(a);
await collector.nextStatusIdle();
// There are cached errors for `MyMacro` with `A1`.
// So, we don't have to analyze anything, we can produce from bytes.
// We produce both the library, and its macro-generated file.
// Note, the macro-generated file has `A1`.
configuration.withMacroFileContent();
await assertEventsText(collector, r'''
[status] working
[operation] getErrorsFromBytes
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ErrorsResult #2
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: isLibrary
[operation] getErrorsFromBytes
file: /home/test/lib/b.macro.dart
library: /home/test/lib/b.dart
[stream]
ErrorsResult #3
path: /home/test/lib/b.macro.dart
uri: package:test/b.macro.dart
flags: isAugmentation isMacroAugmentation
content
---
augment library 'package:test/b.dart';
class A1 {}
---
[status] idle
''');
}
test_changeFile_notAbsolutePath() async {
var driver = driverFor(testFile);
expect(() {
driver.changeFile('not_absolute.dart');
}, throwsArgumentError);
}
test_changeFile_notExisting_toEmpty() async {
var b = newFile('$testPackageLibPath/b.dart', '''
// ignore:unused_import
import 'a.dart';
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(b);
// `b` is analyzed, has an error.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
errors
31 +8 URI_DOES_NOT_EXIST
[status] idle
''');
// Create `a`, empty.
var a = newFile('$testPackageLibPath/a.dart', '');
driver.addFile2(a);
// Both `a` and `b` are analyzed.
// No errors anymore.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #2
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[status] idle
''');
}
test_changeFile_notPriority_errorsFromBytes() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var driver = driverFor(a);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
// Initial analysis, no errors.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[status] idle
''');
// Update the file, has an error.
// Note, we analyze the file.
modifyFile2(a, ';');
driver.changeFile2(a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
errors
0 +1 UNEXPECTED_TOKEN
[status] idle
''');
// Update the file, no errors.
// Note, we return errors from bytes.
// We must update latest signatures, not reflected in the text.
// If we don't, the next assert will fail.
modifyFile2(a, '');
driver.changeFile2(a);
await assertEventsText(collector, r'''
[status] working
[operation] getErrorsFromBytes
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ErrorsResult #2
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: isLibrary
[status] idle
''');
// Update the file, has an error.
// Note, we return errors from bytes.
modifyFile2(a, ';');
driver.changeFile2(a);
await assertEventsText(collector, r'''
[status] working
[operation] getErrorsFromBytes
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ErrorsResult #3
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: isLibrary
errors
0 +1 UNEXPECTED_TOKEN
[status] idle
''');
}
test_changeFile_notUsed() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var b = newFile('$testPackageLibPath/b.dart', 'class B1 {}');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
// Nothing interesting, "a" is analyzed.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[status] idle
''');
// Change "b" and notify.
modifyFile2(b, 'class B2 {}');
driver.changeFile2(b);
// Nothing depends on "b", so nothing is analyzed.
await assertEventsText(collector, r'''
[status] working
[status] idle
''');
}
test_changeFile_potentiallyAffected_imported() async {
newFile('$testPackageLibPath/a.dart', '');
var b = newFile('$testPackageLibPath/b.dart', '''
import 'a.dart';
''');
var c = newFile('$testPackageLibPath/c.dart', '''
import 'b.dart';
''');
var d = newFile('$testPackageLibPath/d.dart', '''
import 'c.dart';
''');
newFile('$testPackageLibPath/e.dart', '');
var driver = driverFor(testFile);
Future<LibraryElementImpl> getLibrary(String shortName) async {
var uriStr = 'package:test/$shortName';
var result = await driver.getLibraryByUriValid(uriStr);
return result.element as LibraryElementImpl;
}
var a_element = await getLibrary('a.dart');
var b_element = await getLibrary('b.dart');
var c_element = await getLibrary('c.dart');
var d_element = await getLibrary('d.dart');
var e_element = await getLibrary('e.dart');
// We have all libraries loaded after analysis.
driver.assertLoadedLibraryUriSet(
included: [
'package:test/a.dart',
'package:test/b.dart',
'package:test/c.dart',
'package:test/d.dart',
'package:test/e.dart',
],
);
// All libraries have the current session.
var session1 = driver.currentSession;
expect(a_element.session, session1);
expect(b_element.session, session1);
expect(c_element.session, session1);
expect(d_element.session, session1);
expect(e_element.session, session1);
// Change `b.dart`, also removes `c.dart` and `d.dart` that import it.
// But `a.dart` and `d.dart` is not affected.
driver.changeFile2(b);
var affectedPathList = await driver.applyPendingFileChanges();
expect(affectedPathList, unorderedEquals([b.path, c.path, d.path]));
// We have a new session.
var session2 = driver.currentSession;
expect(session2, isNot(session1));
driver.assertLoadedLibraryUriSet(
excluded: [
'package:test/b.dart',
'package:test/c.dart',
'package:test/d.dart',
],
included: [
'package:test/a.dart',
'package:test/e.dart',
],
);
// `a.dart` and `e.dart` moved to the new session.
// Invalidated libraries stuck with the old session.
expect(a_element.session, session2);
expect(b_element.session, session1);
expect(c_element.session, session1);
expect(d_element.session, session1);
expect(e_element.session, session2);
}
test_changeFile_potentiallyAffected_part() async {
var a = newFile('$testPackageLibPath/a.dart', '''
part of 'b.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', '''
part 'a.dart';
''');
var c = newFile('$testPackageLibPath/c.dart', '''
import 'b.dart';
''');
newFile('$testPackageLibPath/d.dart', '');
var driver = driverFor(testFile);
Future<LibraryElementImpl> getLibrary(String shortName) async {
var uriStr = 'package:test/$shortName';
var result = await driver.getLibraryByUriValid(uriStr);
return result.element as LibraryElementImpl;
}
var b_element = await getLibrary('b.dart');
var c_element = await getLibrary('c.dart');
var d_element = await getLibrary('d.dart');
// We have all libraries loaded after analysis.
driver.assertLoadedLibraryUriSet(
included: [
'package:test/b.dart',
'package:test/c.dart',
'package:test/d.dart',
],
);
// All libraries have the current session.
var session1 = driver.currentSession;
expect(b_element.session, session1);
expect(c_element.session, session1);
expect(d_element.session, session1);
// Change `a.dart`, remove `b.dart` that part it.
// Removes `c.dart` that imports `b.dart`.
// But `d.dart` is not affected.
driver.changeFile2(a);
var affectedPathList = await driver.applyPendingFileChanges();
expect(affectedPathList, unorderedEquals([a.path, b.path, c.path]));
// We have a new session.
var session2 = driver.currentSession;
expect(session2, isNot(session1));
driver.assertLoadedLibraryUriSet(
excluded: [
'package:test/b.dart',
'package:test/c.dart',
],
included: [
'package:test/d.dart',
],
);
// `d.dart` moved to the new session.
// Invalidated libraries stuck with the old session.
expect(b_element.session, session1);
expect(c_element.session, session1);
expect(d_element.session, session2);
}
test_changeFile_selfConsistent() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
import 'b.dart';
final A1 = 1;
final A2 = B1;
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
import 'a.dart';
final B1 = A1;
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.priorityFiles2 = [a, b];
driver.addFile2(a);
driver.addFile2(b);
configuration.libraryConfiguration.unitConfiguration.variableTypesSelector =
(result) {
switch (result.uriStr) {
case 'package:test/a.dart':
return [
result.findElement.topVar('A1'),
result.findElement.topVar('A2'),
];
case 'package:test/b.dart':
return [
result.findElement.topVar('B1'),
];
default:
return [];
}
};
// We have results for both "a" and "b".
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
selectedVariableTypes
A1: int
A2: int
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
selectedVariableTypes
B1: int
[status] idle
''');
// Update "a".
modifyFile2(a, r'''
import 'b.dart';
final A1 = 1.2;
final A2 = B1;
''');
driver.changeFile2(a);
// We again get results for both "a" and "b".
// The results are consistent.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #2
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
selectedVariableTypes
A1: double
A2: double
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #3
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
selectedVariableTypes
B1: double
[status] idle
''');
}
test_changeFile_single() async {
var a = newFile('$testPackageLibPath/a.dart', 'var V = 1;');
var driver = driverFor(a);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
driver.priorityFiles2 = [a];
configuration.libraryConfiguration.unitConfiguration.variableTypesSelector =
(result) {
switch (result.uriStr) {
case 'package:test/a.dart':
return [
result.findElement.topVar('V'),
];
default:
return [];
}
};
// Initial analysis.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
selectedVariableTypes
V: int
[status] idle
''');
// Update the file, but don't notify the driver.
// No new results.
modifyFile2(a, 'var V = 1.2;');
await assertEventsText(collector, r'''
''');
// Notify the driver about the change.
// We get a new result.
driver.changeFile2(a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
selectedVariableTypes
V: double
[status] idle
''');
}
test_currentSession() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
final v = 0;
''');
var driver = driverFor(testFile);
await driver.getResolvedUnit2(a);
var session1 = driver.currentSession;
expect(session1, isNotNull);
modifyFile2(a, r'''
final v = 2;
''');
driver.changeFile2(a);
await driver.getResolvedUnit2(a);
var session2 = driver.currentSession;
expect(session2, isNotNull);
// We get a new session.
expect(session2, isNot(session1));
}
test_discoverAvailableFiles_packages() async {
writeTestPackageConfig(
PackageConfigFileBuilder()
..add(name: 'aaa', rootPath: '$packagesRootPath/aaa')
..add(name: 'bbb', rootPath: '$packagesRootPath/bbb'),
);
var t1 = newFile('$testPackageLibPath/t1.dart', '');
var a1 = newFile('$packagesRootPath/aaa/lib/a1.dart', '');
var a2 = newFile('$packagesRootPath/aaa/lib/src/a2.dart', '');
var a3 = newFile('$packagesRootPath/aaa/lib/a3.txt', '');
var b1 = newFile('$packagesRootPath/bbb/lib/b1.dart', '');
var c1 = newFile('$packagesRootPath/ccc/lib/c1.dart', '');
var driver = driverFor(testFile);
driver.addFile2(t1);
// Don't add `a1`, `a2`, or `b1` - they should be discovered.
// And `c` is not in the package config, so should not be discovered.
await driver.discoverAvailableFiles();
var knownFiles = driver.knownFiles.resources;
expect(knownFiles, contains(t1));
expect(knownFiles, contains(a1));
expect(knownFiles, contains(a2));
expect(knownFiles, isNot(contains(a3)));
expect(knownFiles, contains(b1));
expect(knownFiles, isNot(contains(c1)));
// We can wait for discovery more than once.
await driver.discoverAvailableFiles();
}
test_discoverAvailableFiles_sdk() async {
var driver = driverFor(testFile);
await driver.discoverAvailableFiles();
expect(
driver.knownFiles.resources,
containsAll([
sdkRoot.getChildAssumingFile('lib/async/async.dart'),
sdkRoot.getChildAssumingFile('lib/collection/collection.dart'),
sdkRoot.getChildAssumingFile('lib/core/core.dart'),
sdkRoot.getChildAssumingFile('lib/math/math.dart'),
]),
);
}
test_getCachedResolvedUnit() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var driver = driverFor(a);
var collector = DriverEventCollector(driver);
// Not cached.
// Note, no analysis.
collector.getCachedResolvedUnit('A1', a);
await assertEventsText(collector, r'''
[future] getCachedResolvedUnit A1
null
''');
driver.priorityFiles2 = [a];
collector.getResolvedUnit('A2', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A2
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[status] idle
''');
// Has cached.
// Note, no analysis.
collector.getCachedResolvedUnit('A3', a);
await assertEventsText(collector, r'''
[future] getCachedResolvedUnit A3
ResolvedUnitResult #0
''');
}
test_getErrors() async {
var a = newFile('$testPackageLibPath/a.dart', '''
var v = 0
''');
var driver = driverFor(a);
var collector = DriverEventCollector(driver);
collector.getErrors('A1', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getErrors A1
ErrorsResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: isLibrary
errors
8 +1 EXPECTED_TOKEN
[stream]
ResolvedUnitResult #1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
errors
8 +1 EXPECTED_TOKEN
[status] idle
''');
// The result is produced from bytes.
collector.getErrors('A2', a);
await assertEventsText(collector, r'''
[status] working
[operation] getErrorsFromBytes
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getErrors A2
ErrorsResult #2
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: isLibrary
errors
8 +1 EXPECTED_TOKEN
[status] idle
''');
}
test_getErrors_library_part() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
part 'b.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of 'a.dart';
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
collector.getErrors('A1', a);
collector.getErrors('B1', b);
// Note, both `getErrors()` returned during the library analysis.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getErrors A1
ErrorsResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: isLibrary
[stream]
ResolvedUnitResult #1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getErrors B1
ErrorsResult #2
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: isPart
[stream]
ResolvedUnitResult #3
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[status] idle
''');
}
test_getErrors_macroGenerated() async {
if (!configureWithCommonMacros()) {
return;
}
newFile('$testPackageLibPath/a.dart', r'''
import 'append.dart';
@DeclareTypesPhase('B', 'class B {}')
class A {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
var a_macro = getFile('$testPackageLibPath/a.macro.dart');
collector.getErrors('AM1', a_macro);
await collector.nextStatusIdle();
// The library was analyzed.
// The future for the macro generated file completed.
configuration.withMacroFileContent();
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getErrors AM1
ErrorsResult #1
path: /home/test/lib/a.macro.dart
uri: package:test/a.macro.dart
flags: isAugmentation isMacroAugmentation
content
---
augment library 'package:test/a.dart';
class B {}
---
[stream]
ResolvedUnitResult #2
path: /home/test/lib/a.macro.dart
uri: package:test/a.macro.dart
flags: exists isAugmentation isMacroAugmentation
content
---
augment library 'package:test/a.dart';
class B {}
---
[status] idle
''');
}
test_getErrors_notAbsolutePath() async {
var driver = driverFor(testFile);
var result = await driver.getErrors('not_absolute.dart');
expect(result, isA<InvalidPathResult>());
}
test_getFilesDefiningClassMemberName_class() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
class A {
void m1() {}
}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
class B {
void m2() {}
}
''');
var c = newFile('$testPackageLibPath/c.dart', r'''
class C {
void m2() {}
}
''');
var d = newFile('$testPackageLibPath/d.dart', r'''
class D {
void m3() {}
}
''');
var driver = driverFor(testFile);
driver.addFile2(a);
driver.addFile2(b);
driver.addFile2(c);
driver.addFile2(d);
await driver.assertFilesDefiningClassMemberName('m1', [a]);
await driver.assertFilesDefiningClassMemberName('m2', [b, c]);
await driver.assertFilesDefiningClassMemberName('m3', [d]);
}
test_getFilesDefiningClassMemberName_macroGenerated() async {
if (!configureWithCommonMacros()) {
return;
}
var a = newFile('$testPackageLibPath/a.dart', r'''
import 'append.dart';
@DeclareInType(' void foo() {}')
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
import 'append.dart';
@DeclareInType(' void bar() {}')
class B {}
''');
var c = newFile('$testPackageLibPath/c.dart', r'''
import 'append.dart';
@DeclareInType(' void foo() {}')
class C {}
''');
// Run twice: when linking, and when reading.
for (var i = 0; i < 2; i++) {
var driver = driverFor(testFile);
driver.addFile2(a);
driver.addFile2(b);
driver.addFile2(c);
await driver.assertFilesDefiningClassMemberName('foo', [
a.macroForLibrary,
c.macroForLibrary,
]);
await driver.assertFilesDefiningClassMemberName('bar', [
b.macroForLibrary,
]);
await disposeAnalysisContextCollection();
}
}
test_getFilesDefiningClassMemberName_mixin() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
mixin A {
void m1() {}
}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
mixin B {
void m2() {}
}
''');
var c = newFile('$testPackageLibPath/c.dart', r'''
mixin C {
void m2() {}
}
''');
var d = newFile('$testPackageLibPath/d.dart', r'''
mixin D {
void m3() {}
}
''');
var driver = driverFor(testFile);
driver.addFile2(a);
driver.addFile2(b);
driver.addFile2(c);
driver.addFile2(d);
await driver.assertFilesDefiningClassMemberName('m1', [a]);
await driver.assertFilesDefiningClassMemberName('m2', [b, c]);
await driver.assertFilesDefiningClassMemberName('m3', [d]);
}
test_getFilesReferencingName() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
import 'a.dart';
void f(A a) {}
''');
var c = newFile('$testPackageLibPath/c.dart', r'''
import 'a.dart';
void f(A a) {}
''');
var d = newFile('$testPackageLibPath/d.dart', r'''
class A {}
void f(A a) {}
''');
var e = newFile('$testPackageLibPath/e.dart', r'''
import 'a.dart';
void main() {}
''');
var driver = driverFor(testFile);
driver.addFile2(a);
driver.addFile2(b);
driver.addFile2(c);
driver.addFile2(d);
driver.addFile2(e);
// `b` references an external `A`.
// `c` references an external `A`.
// `d` references the local `A`.
// `e` does not reference `A` at all.
await driver.assertFilesReferencingName(
'A',
includesAll: [b, c],
excludesAll: [d, e],
);
// We get the same results second time.
await driver.assertFilesReferencingName(
'A',
includesAll: [b, c],
excludesAll: [d, e],
);
}
test_getFilesReferencingName_discover() async {
writeTestPackageConfig(
PackageConfigFileBuilder()
..add(name: 'aaa', rootPath: '$packagesRootPath/aaa')
..add(name: 'bbb', rootPath: '$packagesRootPath/bbb'),
);
var t = newFile('$testPackageLibPath/t.dart', '''
int t = 0;
''');
var a = newFile('$packagesRootPath/aaa/lib/a.dart', '''
int a = 0;
''');
var b = newFile('$packagesRootPath/bbb/lib/b.dart', '''
int b = 0;
''');
var c = newFile('$packagesRootPath/ccc/lib/c.dart', '''
int c = 0;
''');
var driver = driverFor(testFile);
driver.addFile2(t);
await driver.assertFilesReferencingName(
'int',
includesAll: [t, a, b],
excludesAll: [c],
);
}
test_getFilesReferencingName_macroGenerated() async {
if (!configureWithCommonMacros()) {
return;
}
var a = newFile('$testPackageLibPath/a.dart', r'''
import 'append.dart';
@DeclareInLibrary('{{dart:core@int}} get foo => 0;')
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
import 'append.dart';
@DeclareInLibrary('{{dart:core@double}} get foo => 1.2;')
class B {}
''');
var c = newFile('$testPackageLibPath/c.dart', r'''
import 'append.dart';
@DeclareInLibrary('{{dart:core@int}} get foo => 0;')
class C {}
''');
// Run twice: when linking, and when reading.
for (var i = 0; i < 2; i++) {
var driver = driverFor(testFile);
driver.addFile2(a);
driver.addFile2(b);
driver.addFile2(c);
await driver.assertFilesReferencingName(
'int',
includesAll: [a.macroForLibrary, c.macroForLibrary],
excludesAll: [b.macroForLibrary],
);
await driver.assertFilesReferencingName(
'double',
includesAll: [b.macroForLibrary],
excludesAll: [a.macroForLibrary, c.macroForLibrary],
);
await disposeAnalysisContextCollection();
}
}
test_getFileSync_changedFile() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var b = newFile('$testPackageLibPath/b.dart', r'''
import 'a.dart';
void f(A a) {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// Ensure that `a` library cycle is loaded.
// So, `a` is in the library context.
collector.getResolvedUnit('A1', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[status] idle
''');
// Update the file, changing its API signature.
// Note that we don't call `changeFile`.
modifyFile2(a, 'class A {}\n');
// Get the file.
// We have not called `changeFile(a)`, so we should not read the file.
// Moreover, doing this will create a new library cycle [a.dart].
// Library cycles are compared by their identity, so we would try to
// reload linked summary for [a.dart], and crash.
expect(driver.getFileSyncValid(a).lineInfo.lineCount, 1);
// We have not read `a.dart`, so `A` is still not declared.
collector.getResolvedUnit('B1', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[future] getResolvedUnit B1
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
errors
25 +1 UNDEFINED_CLASS
7 +8 UNUSED_IMPORT
[stream]
ResolvedUnitResult #1
[status] idle
''');
// Notify the driver that the file was changed.
driver.changeFile2(a);
// ...and apply this change.
await driver.applyPendingFileChanges();
await assertEventsText(collector, r'''
[status] working
[status] idle
''');
// So, `class A {}` is declared now.
expect(driver.getFileSyncValid(a).lineInfo.lineCount, 2);
// ...and `b` has no errors.
collector.getResolvedUnit('B2', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[future] getResolvedUnit B2
ResolvedUnitResult #2
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #2
[status] idle
''');
}
test_getFileSync_library() async {
var content = 'class A {}';
var a = newFile('$testPackageLibPath/a.dart', content);
var driver = driverFor(testFile);
var result = driver.getFileSyncValid(a);
expect(result.path, a.path);
expect(result.uri.toString(), 'package:test/a.dart');
expect(result.content, content);
expect(result.isLibrary, isTrue);
expect(result.isPart, isFalse);
}
test_getFileSync_notAbsolutePath() async {
var driver = driverFor(testFile);
var result = driver.getFileSync('not_absolute.dart');
expect(result, isA<InvalidPathResult>());
}
test_getFileSync_part() async {
var content = 'part of lib;';
var a = newFile('$testPackageLibPath/a.dart', content);
var driver = driverFor(testFile);
var result = driver.getFileSyncValid(a);
expect(result.path, a.path);
expect(result.uri.toString(), 'package:test/a.dart');
expect(result.content, content);
expect(result.isLibrary, isFalse);
expect(result.isPart, isTrue);
}
test_getIndex() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
void foo() {}
void f() {
foo();
}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
collector.getIndex('A1', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getIndex A1
strings
--nullString--
foo
package:test/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[status] idle
''');
}
test_getIndex_macroGenerated() async {
if (!configureWithCommonMacros()) {
return;
}
newFile('$testPackageLibPath/a.dart', r'''
import 'append.dart';
@DeclareInLibrary('void f() { foo(); }')
@DeclareInLibrary('void foo() {}')
class A {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
var a_macro = getFile('$testPackageLibPath/a.macro.dart');
collector.getIndex('AM1', a_macro);
await collector.nextStatusIdle();
// The library, and the macro generated file were analyzed.
configuration.withMacroFileContent();
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getIndex AM1
strings
--nullString--
foo
package:test/a.dart
package:test/a.macro.dart
[stream]
ResolvedUnitResult #1
path: /home/test/lib/a.macro.dart
uri: package:test/a.macro.dart
flags: exists isAugmentation isMacroAugmentation
content
---
augment library 'package:test/a.dart';
void foo() {}
void f() { foo(); }
---
[status] idle
''');
}
test_getIndex_notAbsolutePath() async {
var driver = driverFor(testFile);
expect(() async {
await driver.getIndex('not_absolute.dart');
}, throwsArgumentError);
}
test_getLibraryByUri() async {
var aUriStr = 'package:test/a.dart';
var bUriStr = 'package:test/b.dart';
newFile('$testPackageLibPath/a.dart', r'''
part 'b.dart';
class A {}
''');
newFile('$testPackageLibPath/b.dart', r'''
part of 'a.dart';
class B {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
var result = await driver.getLibraryByUri(aUriStr);
result as LibraryElementResult;
expect(result.element.getClass('A'), isNotNull);
expect(result.element.getClass('B'), isNotNull);
// It is an error to ask for a library when we know that it is a part.
expect(
await driver.getLibraryByUri(bUriStr),
isA<NotLibraryButPartResult>(),
);
// No analysis.
await assertEventsText(collector, r'''
[status] working
[status] idle
''');
}
test_getLibraryByUri_cannotResolveUri() async {
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
collector.getLibraryByUri('X', 'foo:bar');
await assertEventsText(collector, r'''
[future] getLibraryByUri X
CannotResolveUriResult
''');
}
test_getLibraryByUri_notLibrary_augmentation() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
augment library 'package:test/b.dart';
''');
var driver = driverFor(a);
var collector = DriverEventCollector(driver);
var uriStr = 'package:test/a.dart';
collector.getLibraryByUri('X', uriStr);
await assertEventsText(collector, r'''
[future] getLibraryByUri X
NotLibraryButAugmentationResult
''');
}
test_getLibraryByUri_notLibrary_part() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
part of 'b.dart';
''');
var driver = driverFor(a);
var collector = DriverEventCollector(driver);
var uriStr = 'package:test/a.dart';
collector.getLibraryByUri('X', uriStr);
await assertEventsText(collector, r'''
[future] getLibraryByUri X
NotLibraryButPartResult
''');
}
test_getLibraryByUri_unresolvedUri() async {
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
var result = await driver.getLibraryByUri('package:foo/foo.dart');
expect(result, isA<CannotResolveUriResult>());
// No analysis.
await assertEventsText(collector, '');
}
test_getParsedLibrary() async {
var content = 'class A {}';
var a = newFile('$testPackageLibPath/a.dart', content);
var driver = driverFor(testFile);
var result = driver.getParsedLibrary2(a);
result as ParsedLibraryResult;
expect(result.units, hasLength(1));
expect(result.units[0].path, a.path);
expect(result.units[0].content, content);
expect(result.units[0].unit, isNotNull);
expect(result.units[0].errors, isEmpty);
}
test_getParsedLibrary_invalidPath_notAbsolute() async {
var driver = driverFor(testFile);
var result = driver.getParsedLibrary('not_absolute.dart');
expect(result, isA<InvalidPathResult>());
}
test_getParsedLibrary_notLibraryButPart() async {
var driver = driverFor(testFile);
var a = newFile('$testPackageLibPath/a.dart', 'part of my;');
var result = driver.getParsedLibrary2(a);
expect(result, isA<NotLibraryButPartResult>());
}
test_getParsedLibraryByUri() async {
var content = 'class A {}';
var a = newFile('$testPackageLibPath/a.dart', content);
var driver = driverFor(testFile);
var uri = Uri.parse('package:test/a.dart');
var result = driver.getParsedLibraryByUri(uri);
result as ParsedLibraryResult;
expect(result.units, hasLength(1));
expect(result.units[0].uri, uri);
expect(result.units[0].path, a.path);
expect(result.units[0].content, content);
}
test_getParsedLibraryByUri_cannotResolveUri() async {
var driver = driverFor(testFile);
var uri = Uri.parse('foo:bar');
expect(
driver.getParsedLibraryByUri(uri),
isA<CannotResolveUriResult>(),
);
}
test_getParsedLibraryByUri_notLibrary_augmentation() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
augment library 'package:test/b.dart';
''');
var driver = driverFor(a);
var uri = Uri.parse('package:test/a.dart');
expect(
driver.getParsedLibraryByUri(uri),
isA<NotLibraryButAugmentationResult>(),
);
}
test_getParsedLibraryByUri_notLibrary_part() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
part of 'b.dart';
''');
var driver = driverFor(a);
var uri = Uri.parse('package:test/a.dart');
expect(
driver.getParsedLibraryByUri(uri),
isA<NotLibraryButPartResult>(),
);
}
test_getParsedLibraryByUri_notLibraryButPart() async {
newFile('$testPackageLibPath/a.dart', 'part of my;');
var driver = driverFor(testFile);
var uri = Uri.parse('package:test/a.dart');
var result = driver.getParsedLibraryByUri(uri);
expect(result, isA<NotLibraryButPartResult>());
}
test_getParsedLibraryByUri_unresolvedUri() async {
var driver = driverFor(testFile);
var uri = Uri.parse('package:unknown/a.dart');
var result = driver.getParsedLibraryByUri(uri);
expect(result, isA<CannotResolveUriResult>());
}
test_getResolvedLibrary() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
class A {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
collector.getResolvedLibrary('A1', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getResolvedLibrary A1
ResolvedLibraryResult #1
element: package:test/a.dart
units
ResolvedUnitResult #0
[status] idle
''');
}
test_getResolvedLibrary_cachePriority() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
part 'b.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of 'a.dart';
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.priorityFiles2 = [a];
collector.getResolvedLibrary('A1', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getResolvedLibrary A1
ResolvedLibraryResult #1
element: package:test/a.dart
units
ResolvedUnitResult #0
ResolvedUnitResult #2
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[stream]
ResolvedUnitResult #2
[status] idle
''');
// Ask again, the same cached instance should be returned.
// Note, no analysis.
// Note, the result is cached.
collector.getResolvedLibrary('A2', a);
await assertEventsText(collector, r'''
[future] getResolvedLibrary A2
ResolvedLibraryResult #1
''');
// Ask `a`, returns cached.
// Note, no analysis.
collector.getResolvedUnit('A3', a);
await assertEventsText(collector, r'''
[future] getResolvedUnit A3
ResolvedUnitResult #0
''');
// Ask `b`, returns cached.
// Note, no analysis.
collector.getResolvedUnit('B1', b);
await assertEventsText(collector, r'''
[future] getResolvedUnit B1
ResolvedUnitResult #2
''');
}
test_getResolvedLibrary_notAbsolutePath() async {
var driver = driverFor(testFile);
var result = await driver.getResolvedLibrary('not_absolute.dart');
expect(result, isA<InvalidPathResult>());
}
test_getResolvedLibrary_notLibrary_augmentation() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
augment library 'package:test/b.dart';
''');
var driver = driverFor(a);
var collector = DriverEventCollector(driver);
collector.getResolvedLibrary('X', a);
await assertEventsText(collector, r'''
[status] working
[future] getResolvedLibrary X
NotLibraryButAugmentationResult
[status] idle
''');
}
test_getResolvedLibrary_notLibrary_part() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
part of 'b.dart';
''');
var driver = driverFor(a);
var collector = DriverEventCollector(driver);
collector.getResolvedLibrary('X', a);
await assertEventsText(collector, r'''
[status] working
[future] getResolvedLibrary X
NotLibraryButPartResult
[status] idle
''');
}
test_getResolvedLibrary_pending_changeFile() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
class A {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// Ask the resolved library.
// We used to record the request with the `LibraryFileKind`.
collector.getResolvedLibrary('A1', a);
// ...the request is pending, notify that the file changed.
// This forces its reading, and rebuilding its `kind`.
// So, the old `kind` is not valid anymore.
// This used to cause infinite processing of the request.
// https://github.com/dart-lang/sdk/issues/54708
driver.changeFile2(a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getResolvedLibrary A1
ResolvedLibraryResult #1
element: package:test/a.dart
units
ResolvedUnitResult #0
[status] idle
''');
}
test_getResolvedLibrary_withMacroGenerated() async {
if (!configureWithCommonMacros()) {
return;
}
var a = newFile('$testPackageLibPath/a.dart', r'''
import 'append.dart';
@DeclareTypesPhase('B', 'class B {}')
class A {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
collector.getResolvedLibrary('A1', a);
await collector.nextStatusIdle();
// We produced both the library, and its macro-generated file.
configuration.withMacroFileContent();
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getResolvedLibrary A1
ResolvedLibraryResult #1
element: package:test/a.dart
units
ResolvedUnitResult #0
ResolvedUnitResult #2
path: /home/test/lib/a.macro.dart
uri: package:test/a.macro.dart
flags: exists isAugmentation isMacroAugmentation
content
---
augment library 'package:test/a.dart';
class B {}
---
[stream]
ResolvedUnitResult #2
[status] idle
''');
}
test_getResolvedLibraryByUri() async {
newFile('$testPackageLibPath/a.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
var uri = Uri.parse('package:test/a.dart');
collector.getResolvedLibraryByUri('A1', uri);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getResolvedLibraryByUri A1
ResolvedLibraryResult #1
element: package:test/a.dart
units
ResolvedUnitResult #0
[status] idle
''');
}
test_getResolvedLibraryByUri_cannotResolveUri() async {
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
var uri = Uri.parse('foo:bar');
collector.getResolvedLibraryByUri('X', uri);
await assertEventsText(collector, r'''
[future] getResolvedLibraryByUri X
CannotResolveUriResult
''');
}
test_getResolvedLibraryByUri_library_pending_getResolvedUnit() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
part 'b.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of 'a.dart';
''');
var driver = driverFor(a);
var collector = DriverEventCollector(driver);
collector.getResolvedUnit('A1', a);
collector.getResolvedUnit('B1', b);
var uri = Uri.parse('package:test/a.dart');
collector.getResolvedLibraryByUri('A2', uri);
// Note, the library is resolved only once.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[future] getResolvedUnit B1
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[future] getResolvedLibraryByUri A2
ResolvedLibraryResult #2
element: package:test/a.dart
units
ResolvedUnitResult #0
ResolvedUnitResult #1
[stream]
ResolvedUnitResult #1
[status] idle
''');
}
test_getResolvedLibraryByUri_notLibrary_augmentation() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
augment library 'package:test/b.dart';
''');
var driver = driverFor(a);
var collector = DriverEventCollector(driver);
var uri = Uri.parse('package:test/a.dart');
collector.getResolvedLibraryByUri('X', uri);
await assertEventsText(collector, r'''
[status] working
[future] getResolvedLibraryByUri X
NotLibraryButAugmentationResult
[status] idle
''');
}
test_getResolvedLibraryByUri_notLibrary_part() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
part of 'b.dart';
''');
var driver = driverFor(a);
var collector = DriverEventCollector(driver);
var uri = Uri.parse('package:test/a.dart');
collector.getResolvedLibraryByUri('X', uri);
await assertEventsText(collector, r'''
[status] working
[future] getResolvedLibraryByUri X
NotLibraryButPartResult
[status] idle
''');
}
test_getResolvedLibraryByUri_notLibraryButPart() async {
newFile('$testPackageLibPath/a.dart', 'part of my;');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
var uri = Uri.parse('package:test/a.dart');
collector.getResolvedLibraryByUri('A1', uri);
await assertEventsText(collector, r'''
[status] working
[future] getResolvedLibraryByUri A1
NotLibraryButPartResult
[status] idle
''');
}
test_getResolvedLibraryByUri_unresolvedUri() async {
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
var uri = Uri.parse('package:unknown/a.dart');
collector.getResolvedLibraryByUri('A1', uri);
await assertEventsText(collector, r'''
[future] getResolvedLibraryByUri A1
CannotResolveUriResult
''');
}
test_getResolvedLibraryByUri_withMacroGenerated() async {
if (!configureWithCommonMacros()) {
return;
}
newFile('$testPackageLibPath/a.dart', r'''
import 'append.dart';
@DeclareTypesPhase('B', 'class B {}')
class A {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
var uri = Uri.parse('package:test/a.dart');
collector.getResolvedLibraryByUri('A1', uri);
await collector.nextStatusIdle();
// We produced both the library, and its macro-generated file.
configuration.withMacroFileContent();
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getResolvedLibraryByUri A1
ResolvedLibraryResult #1
element: package:test/a.dart
units
ResolvedUnitResult #0
ResolvedUnitResult #2
path: /home/test/lib/a.macro.dart
uri: package:test/a.macro.dart
flags: exists isAugmentation isMacroAugmentation
content
---
augment library 'package:test/a.dart';
class B {}
---
[stream]
ResolvedUnitResult #2
[status] idle
''');
}
test_getResolvedUnit() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
collector.getResolvedUnit('A1', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[status] idle
''');
}
test_getResolvedUnit_added() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
collector.getResolvedUnit('A1', a);
// Note, no separate `ErrorsResult`.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[status] idle
''');
}
test_getResolvedUnit_augmentation_library() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
import augment 'b.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
augment library 'package:test/a.dart';
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
collector.getResolvedUnit('B1', b);
collector.getResolvedUnit('A1', a);
// Note, the library is resolved only once.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[future] getResolvedUnit B1
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isAugmentation
[stream]
ResolvedUnitResult #1
[status] idle
''');
}
test_getResolvedUnit_importLibrary_thenRemoveIt() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
class A {}''');
var b = newFile('$testPackageLibPath/b.dart', r'''
import 'a.dart';
class B extends A {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
driver.addFile2(b);
// No errors in `a` or `b`.
collector.getResolvedUnit('B1', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[future] getResolvedUnit B1
ResolvedUnitResult #0
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[status] idle
''');
// Remove `a` and reanalyze.
deleteFile(a.path);
driver.removeFile2(a);
// The unresolved URI error must be reported.
collector.getResolvedUnit('B2', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[future] getResolvedUnit B2
ResolvedUnitResult #2
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
errors
7 +8 URI_DOES_NOT_EXIST
33 +1 EXTENDS_NON_CLASS
[stream]
ResolvedUnitResult #2
[status] idle
''');
// Restore `a`.
newFile(a.path, 'class A {}');
driver.addFile2(a);
// No errors in `b` again.
collector.getResolvedUnit('B2', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[future] getResolvedUnit B2
ResolvedUnitResult #3
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #3
[operation] getErrorsFromBytes
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ErrorsResult #4
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: isLibrary
[status] idle
''');
}
test_getResolvedUnit_library_added_part() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
part 'b.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of 'a.dart';
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
driver.addFile2(b);
collector.getResolvedUnit('A1', a);
// Note, the library is resolved only once.
// Note, no separate `ErrorsResult` for `a` or `b`.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[status] idle
''');
}
test_getResolvedUnit_library_augmentation() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
import augment 'b.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
augment library 'package:test/a.dart';
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
collector.getResolvedUnit('A1', a);
collector.getResolvedUnit('B1', b);
// Note, the library is resolved only once.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[future] getResolvedUnit B1
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isAugmentation
[stream]
ResolvedUnitResult #1
[status] idle
''');
}
test_getResolvedUnit_library_part() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
part 'b.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of 'a.dart';
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
collector.getResolvedUnit('A1', a);
collector.getResolvedUnit('B1', b);
// Note, the library is resolved only once.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[future] getResolvedUnit B1
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[stream]
ResolvedUnitResult #1
[status] idle
''');
}
test_getResolvedUnit_library_pending_getErrors_part() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
part 'b.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of 'a.dart';
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
collector.getErrors('B1', b);
collector.getResolvedUnit('A1', a);
// Note, the library is resolved only once.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[future] getErrors B1
ErrorsResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: isPart
[stream]
ResolvedUnitResult #2
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[status] idle
''');
}
test_getResolvedUnit_macroGenerated_hasLibrary() async {
if (!configureWithCommonMacros()) {
return;
}
newFile('$testPackageLibPath/a.dart', r'''
import 'append.dart';
@DeclareTypesPhase('B', 'class B {}')
class A {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
var a_macro = getFile('$testPackageLibPath/a.macro.dart');
collector.getResolvedUnit('AM1', a_macro);
await collector.nextStatusIdle();
// Even though we asked the macro-generated file, the library was analyzed
// instead, and results for both produced.
configuration.withMacroFileContent();
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getResolvedUnit AM1
ResolvedUnitResult #1
path: /home/test/lib/a.macro.dart
uri: package:test/a.macro.dart
flags: exists isAugmentation isMacroAugmentation
content
---
augment library 'package:test/a.dart';
class B {}
---
[stream]
ResolvedUnitResult #1
[status] idle
''');
}
test_getResolvedUnit_macroGenerated_noLibrary() async {
if (!configureWithCommonMacros()) {
return;
}
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
var a_macro = getFile('$testPackageLibPath/a.macro.dart');
collector.getResolvedUnit('AM1', a_macro);
await collector.nextStatusIdle();
// We try to analyze `a.dart`, but it does not exist.
// Then we separately analyze `a.macro.dart`, it also does not exist.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: isLibrary
[operation] analyzeFile
file: /home/test/lib/a.macro.dart
library: /home/test/lib/a.macro.dart
[future] getResolvedUnit AM1
ResolvedUnitResult #1
path: /home/test/lib/a.macro.dart
uri: package:test/a.macro.dart
flags: isLibrary
[stream]
ResolvedUnitResult #1
[status] idle
''');
}
test_getResolvedUnit_notDartFile() async {
var a = newFile('$testPackageLibPath/a.txt', r'''
final foo = 0;
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
configuration.libraryConfiguration.unitConfiguration.variableTypesSelector =
(result) {
return [
result.findElement.topVar('foo'),
];
};
// The extension of the file does not matter.
// If asked, we analyze it as Dart.
collector.getResolvedUnit('A1', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.txt
library: /home/test/lib/a.txt
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.txt
uri: package:test/a.txt
flags: exists isLibrary
selectedVariableTypes
foo: int
[stream]
ResolvedUnitResult #0
[status] idle
''');
}
test_getResolvedUnit_part_doesNotExist_lints() async {
newFile('$testPackageRootPath/analysis_options.yaml', r'''
linter:
rules:
- omit_local_variable_types
''');
await assertErrorsInCode(r'''
library my.lib;
part 'a.dart';
''', [
error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 21, 8),
]);
}
test_getResolvedUnit_part_empty_lints() async {
newFile('$testPackageRootPath/analysis_options.yaml', r'''
linter:
rules:
- omit_local_variable_types
''');
newFile('$testPackageLibPath/a.dart', '');
await assertErrorsInCode(r'''
library my.lib;
part 'a.dart';
''', [
error(CompileTimeErrorCode.PART_OF_NON_PART, 21, 8),
]);
}
test_getResolvedUnit_part_hasPartOfName_notThisLibrary_lints() async {
newFile('$testPackageRootPath/analysis_options.yaml', r'''
linter:
rules:
- omit_local_variable_types
''');
newFile('$testPackageLibPath/a.dart', r'''
part of other.lib;
''');
await assertErrorsInCode(r'''
library my.lib;
part 'a.dart';
''', [
error(CompileTimeErrorCode.PART_OF_DIFFERENT_LIBRARY, 21, 8),
]);
}
test_getResolvedUnit_part_hasPartOfUri_notThisLibrary_lints() async {
newFile('$testPackageRootPath/analysis_options.yaml', r'''
linter:
rules:
- omit_local_variable_types
''');
newFile('$testPackageLibPath/a.dart', r'''
part of 'not_test.dart';
''');
await assertErrorsInCode(r'''
library my.lib;
part 'a.dart';
''', [
error(CompileTimeErrorCode.PART_OF_DIFFERENT_LIBRARY, 21, 8),
]);
}
test_getResolvedUnit_part_library() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
part 'b.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of 'a.dart';
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
collector.getResolvedUnit('B1', b);
collector.getResolvedUnit('A1', a);
// Note, the library is resolved only once.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[future] getResolvedUnit B1
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[stream]
ResolvedUnitResult #1
[status] idle
''');
}
test_getResolvedUnit_part_pending_getErrors_library() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
part 'b.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of 'a.dart';
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
collector.getErrors('A1', a);
collector.getResolvedUnit('B1', b);
// Note, the library is resolved only once.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/a.dart
[future] getErrors A1
ErrorsResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: isLibrary
[stream]
ResolvedUnitResult #1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getResolvedUnit B1
ResolvedUnitResult #2
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[stream]
ResolvedUnitResult #2
[status] idle
''');
}
test_getResolvedUnit_pending_getErrors() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
collector.getResolvedUnit('A1', a);
collector.getErrors('A2', a);
// Note, the library is resolved only once.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getErrors A2
ErrorsResult #1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: isLibrary
[stream]
ResolvedUnitResult #0
[status] idle
''');
}
test_getResolvedUnit_pending_getErrors2() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
collector.getErrors('A1', a);
collector.getResolvedUnit('A2', a);
// Note, the library is resolved only once.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A2
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getErrors A1
ErrorsResult #1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: isLibrary
[stream]
ResolvedUnitResult #0
[status] idle
''');
}
test_getResolvedUnit_pending_getIndex() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
collector.getIndex('A1', a);
collector.getResolvedUnit('A2', a);
// Note, no separate `getIndex` result.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A2
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getIndex A1
strings
--nullString--
[stream]
ResolvedUnitResult #0
[status] idle
''');
}
test_getResolvedUnit_thenRemove() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// Schedule resolved unit computation.
collector.getResolvedUnit('A1', a);
// ...and remove the file.
driver.removeFile2(a);
// The future with the result still completes.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[status] idle
''');
}
test_getResolvedUnit_twoPendingFutures() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// Ask the same file twice.
collector.getResolvedUnit('A1', a);
collector.getResolvedUnit('A2', a);
// Both futures complete.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getResolvedUnit A2
ResolvedUnitResult #0
[stream]
ResolvedUnitResult #0
[status] idle
''');
}
test_getUnitElement() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
void foo() {}
void bar() {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
configuration.unitElementConfiguration.elementSelector = (unitElement) {
return unitElement.functions;
};
collector.getUnitElement('A1', a);
await assertEventsText(collector, r'''
[status] working
[future] getUnitElement A1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: isLibrary
enclosing: package:test/a.dart
selectedElements
package:test/a.dart::@function::foo
package:test/a.dart::@function::bar
[status] idle
''');
}
test_getUnitElement_doesNotExist_afterResynthesized() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
import 'package:test/b.dart';
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
collector.getResolvedLibrary('A1', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
errors
7 +21 URI_DOES_NOT_EXIST
[future] getResolvedLibrary A1
ResolvedLibraryResult #1
element: package:test/a.dart
units
ResolvedUnitResult #0
[status] idle
''');
collector.getUnitElement('A2', a);
await assertEventsText(collector, r'''
[status] working
[future] getUnitElement A2
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: isLibrary
enclosing: package:test/a.dart
[status] idle
''');
}
test_getUnitElement_invalidPath_notAbsolute() async {
var driver = driverFor(testFile);
var result = await driver.getUnitElement('not_absolute.dart');
expect(result, isA<InvalidPathResult>());
}
test_getUnitElement_macroGenerated() async {
if (!configureWithCommonMacros()) {
return;
}
newFile('$testPackageLibPath/a.dart', r'''
import 'append.dart';
@DeclareTypesPhase('B', 'class B {}')
class A {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
var a_macro = getFile('$testPackageLibPath/a.macro.dart');
collector.getUnitElement('AM1', a_macro);
await collector.nextStatusIdle();
configuration.unitElementConfiguration.elementSelector = (unitElement) {
return unitElement.classes;
};
// The enclosing element is an augmentation library, in a library.
// The macro generated file has `class B`.
await assertEventsText(collector, r'''
[status] working
[future] getUnitElement AM1
path: /home/test/lib/a.macro.dart
uri: package:test/a.macro.dart
flags: isAugmentation isMacroAugmentation
enclosing: package:test/a.dart::@augmentation::package:test/a.macro.dart
selectedElements
package:test/a.dart::@augmentation::package:test/a.macro.dart::@class::B
[status] idle
''');
}
test_hermetic_modifyLibraryFile_resolvePart() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
part 'b.dart';
final A = 0;
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of 'a.dart';
final B = A;
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
configuration.libraryConfiguration.unitConfiguration.variableTypesSelector =
(result) {
switch (result.uriStr) {
case 'package:test/b.dart':
return [
result.findElement.topVar('B'),
];
default:
return [];
}
};
collector.getResolvedUnit('B1', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getResolvedUnit B1
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
selectedVariableTypes
B: int
[stream]
ResolvedUnitResult #1
[status] idle
''');
// Modify the library, but don't notify the driver.
// The driver should use the previous library content and elements.
modifyFile2(a, r'''
part 'b.dart';
final A = 1.2;
''');
// Note, still `B: int`, not `B: double` yet.
collector.getResolvedUnit('B2', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #2
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getResolvedUnit B2
ResolvedUnitResult #3
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
selectedVariableTypes
B: int
[stream]
ResolvedUnitResult #3
[status] idle
''');
}
test_importOfNonLibrary_part_afterLibrary() async {
var a = newFile('$testPackageLibPath/a.dart', '''
part 'b.dart';
''');
newFile('$testPackageLibPath/b.dart', '''
part of 'a.dart';
class B {}
''');
var c = newFile('$testPackageLibPath/c.dart', '''
import 'b.dart';
''');
var driver = driverFor(testFile);
// This ensures that `a` linked library is cached.
await driver.getResolvedUnit2(a);
// Should not fail because of considering `b` part as `a` library.
await driver.getResolvedUnit2(c);
}
test_knownFiles() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
// ignore:unused_import
import 'b.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
''');
var c = newFile('$testPackageLibPath/c.dart', r'''
''');
var driver = driverFor(testFile);
driver.addFile2(a);
driver.addFile2(c);
await pumpEventQueue(times: 5000);
expect(driver.knownFiles.resources, contains(a));
expect(driver.knownFiles.resources, contains(b));
expect(driver.knownFiles.resources, contains(c));
// Remove `a` and analyze.
// Both `a` and `b` are not known now.
driver.removeFile2(a);
await pumpEventQueue(times: 5000);
expect(driver.knownFiles.resources, isNot(contains(a)));
expect(driver.knownFiles.resources, isNot(contains(b)));
expect(driver.knownFiles.resources, contains(c));
}
test_knownFiles_beforeAnalysis() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var driver = driverFor(testFile);
// `a` is added, but not processed yet.
// So, the set of known files is empty yet.
driver.addFile2(a);
expect(driver.knownFiles, isEmpty);
}
test_missingDartLibrary_async() async {
var driver = driverFor(testFile);
sdkRoot.getChildAssumingFile('lib/async/async.dart').delete();
var a = newFile('$testPackageLibPath/a.dart', '');
var result = await driver.getErrors(a.path);
result as ErrorsResult;
assertErrorsInList(result.errors, [
error(CompileTimeErrorCode.MISSING_DART_LIBRARY, 0, 0),
]);
}
test_missingDartLibrary_core() async {
var driver = driverFor(testFile);
sdkRoot.getChildAssumingFile('lib/core/core.dart').delete();
var a = newFile('$testPackageLibPath/a.dart', '');
var result = await driver.getErrors(a.path);
result as ErrorsResult;
assertErrorsInList(result.errors, [
error(CompileTimeErrorCode.MISSING_DART_LIBRARY, 0, 0),
]);
}
test_parseFileSync_changedFile() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
// ignore:unused_import
import 'a.dart';
void f(A a) {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// Ensure that [a] library cycle is loaded.
// So, `a` is in the library context.
collector.getResolvedUnit('A1', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[status] idle
''');
// Update the file, changing its API signature.
// Note that we don't call `changeFile`.
modifyFile2(a, r'''
class A {}
''');
// Parse the file.
// We have not called `changeFile(a)`, so we should not read the file.
// Moreover, doing this will create a new library cycle [a].
// Library cycles are compared by their identity, so we would try to
// reload linked summary for [a], and crash.
{
var parseResult = driver.parseFileSync2(a) as ParsedUnitResult;
expect(parseResult.unit.declarations, isEmpty);
}
// We have not read `a`, so `A` is still not declared.
collector.getResolvedUnit('B1', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[future] getResolvedUnit B1
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
errors
48 +1 UNDEFINED_CLASS
[stream]
ResolvedUnitResult #1
[status] idle
''');
// Notify the driver that `a` was changed.
driver.changeFile2(a);
// Pending changes are no applied yes, so `a` is empty.
{
var result = driver.parseFileSync2(a) as ParsedUnitResult;
assertParsedNodeText(result.unit, r'''
CompilationUnit
''');
}
// The pending change to `a` declares `A`.
// So, `b` does not have errors anymore.
collector.getResolvedUnit('B2', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[future] getResolvedUnit B2
ResolvedUnitResult #2
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #2
[status] idle
''');
// We apply pending changes while handling request.
// So, now `class A {}` is declared.
{
var result = driver.parseFileSync2(a) as ParsedUnitResult;
assertParsedNodeText(result.unit, r'''
CompilationUnit
declarations
ClassDeclaration
classKeyword: class
name: A
leftBracket: {
rightBracket: }
''');
}
}
test_parseFileSync_doesNotReadImportedFiles() async {
newFile('$testPackageLibPath/a.dart', r'''
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
// ignore:unused_import
import 'a.dart';
''');
var driver = driverFor(testFile);
expect(driver.knownFiles, isEmpty);
// Don't read `a` when parse.
driver.parseFileSync2(b);
expect(driver.knownFiles.resources, unorderedEquals([b]));
// Still don't read `a.dart` when parse the second time.
driver.parseFileSync2(b);
expect(driver.knownFiles.resources, unorderedEquals([b]));
}
test_parseFileSync_notAbsolutePath() async {
var driver = driverFor(testFile);
var result = driver.parseFileSync('not_absolute.dart');
expect(result, isA<InvalidPathResult>());
}
test_parseFileSync_notDart() async {
var a = newFile('$testPackageLibPath/a.txt', r'''
class A {}
''');
var driver = driverFor(testFile);
var result = driver.parseFileSync2(a) as ParsedUnitResult;
assertParsedNodeText(result.unit, r'''
CompilationUnit
declarations
ClassDeclaration
classKeyword: class
name: A
leftBracket: {
rightBracket: }
''');
expect(driver.knownFiles.resources, unorderedEquals([a]));
}
test_partOfName_getErrors_afterLibrary() async {
// Note, we put the library into a different directory.
// Otherwise we will discover it.
var a = newFile('$testPackageLibPath/hidden/a.dart', r'''
library a;
part '../b.dart';
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of a;
final a = A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// Process `a` so that we know that it's a library for `b`.
collector.getErrors('A1', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/hidden/a.dart
library: /home/test/lib/hidden/a.dart
[future] getErrors A1
ErrorsResult #0
path: /home/test/lib/hidden/a.dart
uri: package:test/hidden/a.dart
flags: isLibrary
[stream]
ResolvedUnitResult #1
path: /home/test/lib/hidden/a.dart
uri: package:test/hidden/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #2
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[status] idle
''');
// We return cached errors.
// TODO(scheglov): don't switch to analysis?
collector.getErrors('B1', b);
await assertEventsText(collector, r'''
[status] working
[operation] getErrorsFromBytes
file: /home/test/lib/b.dart
library: /home/test/lib/hidden/a.dart
[future] getErrors B1
ErrorsResult #3
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: isPart
[status] idle
''');
}
test_partOfName_getErrors_beforeLibrary_addedFiles() async {
var a = newFile('$testPackageLibPath/hidden/a.dart', r'''
library a;
part '../b.dart';
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of a;
final a = A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// We discover all added files are maybe libraries.
driver.addFile2(a);
driver.addFile2(b);
// Because `a` is added, we know how to analyze `b`.
// So, it has no errors.
collector.getErrors('B1', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/hidden/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/hidden/a.dart
uri: package:test/hidden/a.dart
flags: exists isLibrary
[future] getErrors B1
ErrorsResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: isPart
[stream]
ResolvedUnitResult #2
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[status] idle
''');
}
test_partOfName_getErrors_beforeLibrary_discovered() async {
newFile('$testPackageLibPath/a.dart', r'''
library a;
part 'b.dart';
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of a;
final a = new A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// We discover sibling files as libraries.
// So, we know that `a` is the library of `b`.
// So, no errors.
collector.getErrors('B1', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getErrors B1
ErrorsResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: isPart
[stream]
ResolvedUnitResult #2
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[status] idle
''');
}
test_partOfName_getErrors_beforeLibrary_notDiscovered() async {
newFile('$testPackageLibPath/hidden/a.dart', r'''
library a;
part '../b.dart';
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of a;
final a = new A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// We don't know that `a` is the library of `b`.
// So, we treat it as its own library, has errors.
collector.getErrors('B1', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[future] getErrors B1
ErrorsResult #0
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: isPart
errors
25 +1 CREATION_WITH_NON_TYPE
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
errors
25 +1 CREATION_WITH_NON_TYPE
[status] idle
''');
}
test_partOfName_getResolvedUnit_afterLibrary() async {
var a = newFile('$testPackageLibPath/hidden/a.dart', r'''
library a;
part '../b.dart';
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of a;
final a = new A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// Process `a` so that we know that it's a library for `b`.
collector.getResolvedUnit('A1', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/hidden/a.dart
library: /home/test/lib/hidden/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/hidden/a.dart
uri: package:test/hidden/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[status] idle
''');
// We know that `b` is analyzed as part of `a`.
collector.getResolvedUnit('B1', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/hidden/a.dart
[stream]
ResolvedUnitResult #2
path: /home/test/lib/hidden/a.dart
uri: package:test/hidden/a.dart
flags: exists isLibrary
[future] getResolvedUnit B1
ResolvedUnitResult #3
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[stream]
ResolvedUnitResult #3
[status] idle
''');
}
test_partOfName_getResolvedUnit_beforeLibrary_addedFiles() async {
var a = newFile('$testPackageLibPath/hidden/a.dart', r'''
library a;
part '../b.dart';
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of a;
final a = new A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// We discover all added files are maybe libraries.
driver.addFile2(a);
driver.addFile2(b);
// Because `a` is added, we know how to analyze `b`.
collector.getResolvedUnit('B1', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/hidden/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/hidden/a.dart
uri: package:test/hidden/a.dart
flags: exists isLibrary
[future] getResolvedUnit B1
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[stream]
ResolvedUnitResult #1
[status] idle
''');
}
test_partOfName_getResolvedUnit_beforeLibrary_notDiscovered() async {
newFile('$testPackageLibPath/hidden/a.dart', r'''
library a;
part '../b.dart';
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of a;
final a = new A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// We don't know that `a` is the library of `b`.
// So, we treat it as its own library.
collector.getResolvedUnit('B1', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[future] getResolvedUnit B1
ResolvedUnitResult #0
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
errors
25 +1 CREATION_WITH_NON_TYPE
[stream]
ResolvedUnitResult #0
[status] idle
''');
}
test_partOfName_getResolvedUnit_changePart_invalidatesLibraryCycle() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
import 'dart:async';
part 'b.dart';
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
// Analyze the library without the part.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
errors
26 +8 URI_DOES_NOT_EXIST
7 +12 UNUSED_IMPORT
[status] idle
''');
// Create the part file.
// This should invalidate library file state (specifically the library
// cycle), so that we can re-link the library, and get new dependencies.
var b = newFile('$testPackageLibPath/b.dart', r'''
part of 'a.dart';
Future<int>? f;
''');
driver.changeFile2(b);
// This should not crash.
collector.getResolvedUnit('B1', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[future] getResolvedUnit B1
ResolvedUnitResult #2
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[stream]
ResolvedUnitResult #2
[status] idle
''');
}
test_partOfName_getResolvedUnit_hasLibrary_noPart() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
library my.lib;
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of my.lib;
final a = new A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// Discover the library.
driver.getFileSync2(a);
// There is no library which `b` is a part of, so `A` is unresolved.
collector.getResolvedUnit('B1', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[future] getResolvedUnit B1
ResolvedUnitResult #0
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
errors
30 +1 CREATION_WITH_NON_TYPE
[stream]
ResolvedUnitResult #0
[status] idle
''');
}
test_partOfName_getResolvedUnit_noLibrary() async {
var b = newFile('$testPackageLibPath/b.dart', r'''
part of my.lib;
var a = new A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// There is no library which `b` is a part of, so `A` is unresolved.
collector.getResolvedUnit('B1', b);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[future] getResolvedUnit B1
ResolvedUnitResult #0
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
errors
28 +1 CREATION_WITH_NON_TYPE
[stream]
ResolvedUnitResult #0
[status] idle
''');
}
test_partOfName_getUnitElement_afterLibrary() async {
var a = newFile('$testPackageLibPath/hidden/a.dart', r'''
library a;
part '../b.dart';
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of a;
final a = new A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// Process `a` so that we know that it's a library for `b`.
collector.getResolvedUnit('A1', a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/hidden/a.dart
library: /home/test/lib/hidden/a.dart
[future] getResolvedUnit A1
ResolvedUnitResult #0
path: /home/test/lib/hidden/a.dart
uri: package:test/hidden/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #0
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[status] idle
''');
// We know that `a` is the library for `b`.
collector.getUnitElement('B1', b);
await assertEventsText(collector, r'''
[status] working
[future] getUnitElement B1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: isPart
enclosing: package:test/hidden/a.dart
[status] idle
''');
}
test_partOfName_getUnitElement_beforeLibrary_addedFiles() async {
var a = newFile('$testPackageLibPath/hidden/a.dart', r'''
library a;
part '../b.dart';
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of a;
final a = new A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// We discover all added files are maybe libraries.
driver.addFile2(a);
driver.addFile2(b);
// Because `a` is added, we know how to analyze `b`.
collector.getUnitElement('B1', b);
await assertEventsText(collector, r'''
[status] working
[future] getUnitElement B1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: isPart
enclosing: package:test/hidden/a.dart
[operation] analyzeFile
file: /home/test/lib/hidden/a.dart
library: /home/test/lib/hidden/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/hidden/a.dart
uri: package:test/hidden/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[status] idle
''');
}
test_partOfName_getUnitElement_noLibrary() async {
var b = newFile('$testPackageLibPath/b.dart', r'''
part of a;
final a = new A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// We don't know the library for `b`.
// So, we treat it as its own library.
collector.getUnitElement('B1', b);
await assertEventsText(collector, r'''
[status] working
[future] getUnitElement B1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: isPart
enclosing: package:test/b.dart
[status] idle
''');
}
test_partOfName_results_afterLibrary() async {
// Note, we put the library into a different directory.
// Otherwise we will discover it.
var a = newFile('$testPackageLibPath/hidden/a.dart', r'''
library a;
part '../b.dart';
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of a;
final a = new A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// The order does not matter.
// It used to matter, but not anymore.
driver.addFile2(a);
driver.addFile2(b);
// We discover all added libraries.
// So, we know that `a` is the library of `b`.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/hidden/a.dart
library: /home/test/lib/hidden/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/hidden/a.dart
uri: package:test/hidden/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[status] idle
''');
}
test_partOfName_results_beforeLibrary() async {
// Note, we put the library into a different directory.
// Otherwise we will discover it.
var a = newFile('$testPackageLibPath/hidden/a.dart', r'''
library a;
part '../b.dart';
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of a;
final a = new A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// The order does not matter.
// It used to matter, but not anymore.
driver.addFile2(b);
driver.addFile2(a);
// We discover all added libraries.
// So, we know that `a` is the library of `b`.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/hidden/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/hidden/a.dart
uri: package:test/hidden/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[status] idle
''');
}
test_partOfName_results_beforeLibrary_priority() async {
// Note, we put the library into a different directory.
// Otherwise we will discover it.
var a = newFile('$testPackageLibPath/hidden/a.dart', r'''
library a;
part '../b.dart';
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
part of a;
final a = new A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// The order does not matter.
// It used to matter, but not anymore.
driver.addFile2(b);
driver.addFile2(a);
driver.priorityFiles2 = [b];
// We discover all added libraries.
// So, we know that `a` is the library of `b`.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/hidden/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/hidden/a.dart
uri: package:test/hidden/a.dart
flags: exists isLibrary
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
[status] idle
''');
}
test_partOfName_results_noLibrary() async {
var b = newFile('$testPackageLibPath/b.dart', r'''
part of a;
final a = new A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(b);
// There is no library for `b`.
// So, we analyze `b` as its own library.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
errors
25 +1 CREATION_WITH_NON_TYPE
[status] idle
''');
}
test_partOfName_results_noLibrary_priority() async {
var b = newFile('$testPackageLibPath/b.dart', r'''
part of a;
final a = new A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(b);
driver.priorityFiles2 = [b];
// There is no library for `b`.
// So, we analyze `b` as its own library.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isPart
errors
25 +1 CREATION_WITH_NON_TYPE
[status] idle
''');
}
test_priorities_changed_importing_rest() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
import 'c.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
class B {}
''');
var c = newFile('$testPackageLibPath/c.dart', r'''
import 'b.dart';
''');
var driver = driverFor(a);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
driver.addFile2(b);
driver.addFile2(c);
// Discard results so far.
await collector.nextStatusIdle();
collector.take();
modifyFile2(b, r'''
class B2 {}
''');
driver.changeFile2(b);
// We analyze `b` first, because it was changed.
// Then we analyze `c`, because it imports `b`.
// Then we analyze `a`, because it also affected.
// Note, there is no specific rule that says when `a` is analyzed.
configuration.withStreamResolvedUnitResults = false;
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[operation] analyzeFile
file: /home/test/lib/c.dart
library: /home/test/lib/c.dart
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[status] idle
''');
}
test_priorities_changed_importing_withErrors_rest() async {
// Note, is affected by `b`, but does not import it.
var a = newFile('$testPackageLibPath/a.dart', r'''
export 'b.dart';
''');
// We will change this file.
var b = newFile('$testPackageLibPath/b.dart', r'''
class B {}
''');
// Note, does not import `b` directly.
var c = newFile('$testPackageLibPath/c.dart', r'''
import 'a.dart';
class C extends X {}
''');
// Note, does import `b`.
var d = newFile('$testPackageLibPath/d.dart', r'''
import 'b.dart';
''');
var driver = driverFor(a);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
driver.addFile2(b);
driver.addFile2(c);
driver.addFile2(d);
// Discard results so far.
await collector.nextStatusIdle();
collector.take();
modifyFile2(b, r'''
class B2 {}
''');
driver.changeFile2(b);
// We analyze `b` first, because it was changed.
// The we analyze `d` because it import `b`.
// Then we analyze `c` because it has errors.
// Then we analyze `a` because it is affected.
// For `a` because it just exports, there are no special rules.
configuration.withStreamResolvedUnitResults = false;
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[operation] analyzeFile
file: /home/test/lib/d.dart
library: /home/test/lib/d.dart
[operation] analyzeFile
file: /home/test/lib/c.dart
library: /home/test/lib/c.dart
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[status] idle
''');
}
test_priorities_changedAll() async {
// Make sure that `test2` is its own analysis context.
var test1Path = '$workspaceRootPath/test1';
writePackageConfig(
test1Path,
PackageConfigFileBuilder()..add(name: 'test1', rootPath: test1Path),
);
// Make sure that `test2` is its own analysis context.
var test2Path = '$workspaceRootPath/test2';
writePackageConfig(
test2Path,
PackageConfigFileBuilder()..add(name: 'test2', rootPath: test2Path),
);
// `b` imports `a`, so `b` is reanalyzed when `a` API changes.
var a = newFile('$test1Path/lib/a.dart', 'class A {}');
var b = newFile('$test1Path/lib/b.dart', "import 'a.dart';");
// `d` imports `c`, so `d` is reanalyzed when `b` API changes.
var c = newFile('$test2Path/lib/c.dart', 'class C {}');
var d = newFile('$test2Path/lib/d.dart', "import 'c.dart';");
var collector = DriverEventCollector.forCollection(
analysisContextCollection,
);
var driver1 = driverFor(a);
var driver2 = driverFor(c);
// Ensure that we actually have two separate analysis contexts.
expect(driver1, isNot(same(driver2)));
// Subscribe for analysis.
driver1.addFile2(a);
driver1.addFile2(b);
driver2.addFile2(c);
driver2.addFile2(d);
// Discard results so far.
await collector.nextStatusIdle();
collector.take();
// Change `a` and `c` in a way that changed their API signatures.
modifyFile2(a, 'class A2 {}');
modifyFile2(c, 'class C2 {}');
driver1.changeFile2(a);
driver2.changeFile2(c);
// Note, `a` and `c` analyzed first, because they were changed.
// Even though they are in different drivers.
configuration.withStreamResolvedUnitResults = false;
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test1/lib/a.dart
library: /home/test1/lib/a.dart
[operation] analyzeFile
file: /home/test2/lib/c.dart
library: /home/test2/lib/c.dart
[operation] analyzeFile
file: /home/test1/lib/b.dart
library: /home/test1/lib/b.dart
[operation] analyzeFile
file: /home/test2/lib/d.dart
library: /home/test2/lib/d.dart
[status] idle
''');
}
test_priorities_getResolvedUnit_beforePriority() async {
// Make sure that `test1` is its own analysis context.
var test1Path = '$workspaceRootPath/test1';
writePackageConfig(
test1Path,
PackageConfigFileBuilder()..add(name: 'test1', rootPath: test1Path),
);
// Make sure that `test2` is its own analysis context.
var test2Path = '$workspaceRootPath/test2';
writePackageConfig(
test2Path,
PackageConfigFileBuilder()..add(name: 'test2', rootPath: test2Path),
);
var a = newFile('$test1Path/lib/a.dart', '');
var b = newFile('$test2Path/lib/b.dart', '');
var c = newFile('$test2Path/lib/c.dart', '');
var collector = DriverEventCollector.forCollection(
analysisContextCollection,
);
var driver1 = driverFor(a);
var driver2 = driverFor(c);
// Ensure that we actually have two separate analysis contexts.
expect(driver1, isNot(same(driver2)));
// Subscribe for analysis.
driver1.addFile2(a);
driver2.addFile2(b);
driver2.addFile2(c);
driver1.priorityFiles2 = [a];
driver2.priorityFiles2 = [c];
collector.driver = driver2;
collector.getResolvedUnit('B1', b);
// We asked for `b`, so it is analyzed.
// Even if it is not a priority file.
// Even if it is in the `driver2`.
configuration.withStreamResolvedUnitResults = false;
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test2/lib/b.dart
library: /home/test2/lib/b.dart
[future] getResolvedUnit B1
ResolvedUnitResult #0
path: /home/test2/lib/b.dart
uri: package:test2/b.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test1/lib/a.dart
library: /home/test1/lib/a.dart
[operation] analyzeFile
file: /home/test2/lib/c.dart
library: /home/test2/lib/c.dart
[status] idle
''');
}
test_priorities_priority_rest() async {
// Make sure that `test1` is its own analysis context.
var test1Path = '$workspaceRootPath/test1';
writePackageConfig(
test1Path,
PackageConfigFileBuilder()..add(name: 'test1', rootPath: test1Path),
);
// Make sure that `test2` is its own analysis context.
var test2Path = '$workspaceRootPath/test2';
writePackageConfig(
test2Path,
PackageConfigFileBuilder()..add(name: 'test2', rootPath: test2Path),
);
var a = newFile('$test1Path/lib/a.dart', '');
var b = newFile('$test1Path/lib/b.dart', '');
var c = newFile('$test2Path/lib/c.dart', '');
var d = newFile('$test2Path/lib/d.dart', '');
var collector = DriverEventCollector.forCollection(
analysisContextCollection,
);
var driver1 = driverFor(a);
var driver2 = driverFor(c);
// Ensure that we actually have two separate analysis contexts.
expect(driver1, isNot(same(driver2)));
driver1.addFile2(a);
driver1.addFile2(b);
driver1.priorityFiles2 = [a];
driver2.addFile2(c);
driver2.addFile2(d);
driver2.priorityFiles2 = [c];
configuration.withStreamResolvedUnitResults = false;
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test1/lib/a.dart
library: /home/test1/lib/a.dart
[operation] analyzeFile
file: /home/test2/lib/c.dart
library: /home/test2/lib/c.dart
[operation] analyzeFile
file: /home/test1/lib/b.dart
library: /home/test1/lib/b.dart
[operation] analyzeFile
file: /home/test2/lib/d.dart
library: /home/test2/lib/d.dart
[status] idle
''');
}
test_removeFile_addFile() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
// Initial analysis.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[status] idle
''');
driver.removeFile2(a);
driver.addFile2(a);
// The cache key for `a` errors is the same, return from bytes.
// Note, no analysis.
await assertEventsText(collector, r'''
[status] working
[operation] getErrorsFromBytes
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ErrorsResult #1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: isLibrary
[status] idle
''');
}
test_removeFile_changeFile_implicitlyAnalyzed() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
import 'b.dart';
final A = B;
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
final B = 0;
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.priorityFiles2 = [a, b];
driver.addFile2(a);
driver.addFile2(b);
configuration.libraryConfiguration.unitConfiguration.variableTypesSelector =
(result) {
switch (result.uriStr) {
case 'package:test/a.dart':
return [
result.findElement.topVar('A'),
];
case 'package:test/b.dart':
return [
result.findElement.topVar('B'),
];
default:
return [];
}
};
// We have results for both `a` and `b`.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
selectedVariableTypes
A: int
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
selectedVariableTypes
B: int
[status] idle
''');
// Remove `b` and send the change notification.
modifyFile2(b, r'''
final B = 1.2;
''');
driver.removeFile2(b);
driver.changeFile2(b);
// While `b` is not analyzed explicitly, it is analyzed implicitly.
// We don't get a result for `b`.
// But the change causes `a` to be reanalyzed.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #2
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
selectedVariableTypes
A: double
[status] idle
''');
}
test_removeFile_changeFile_notAnalyzed() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
class A {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// We don't analyze `a`, so we get nothing.
await assertEventsText(collector, r'''
''');
// Remove `a`, and also change it.
// Still nothing, we still don't analyze `a`.
driver.removeFile2(a);
driver.changeFile2(a);
await assertEventsText(collector, r'''
[status] working
[status] idle
''');
}
test_removeFile_invalidate_importers() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
import 'a.dart';
final a = new A();
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
driver.addFile2(b);
// No errors in `b`.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[status] idle
''');
// Remove `a`, so `b` is reanalyzed and has an error.
deleteFile2(a);
driver.removeFile2(a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #2
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
errors
7 +8 URI_DOES_NOT_EXIST
31 +1 CREATION_WITH_NON_TYPE
[status] idle
''');
}
test_removeFile_notAbsolutePath() async {
var driver = driverFor(testFile);
expect(() {
driver.removeFile('not_absolute.dart');
}, throwsArgumentError);
}
test_results_order() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
// ignore:unused_import
import 'd.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', '');
var c = newFile('$testPackageLibPath/c.dart', r'''
// ignore:unused_import
import 'd.dart';
''');
var d = newFile('$testPackageLibPath/d.dart', r'''
// ignore:unused_import
import 'b.dart';
''');
var e = newFile('$testPackageLibPath/e.dart', r'''
// ignore:unused_import
export 'b.dart';
''');
// This file intentionally has an error.
var f = newFile('$testPackageLibPath/f.dart', r'''
// ignore:unused_import
import 'e.dart';
class F extends X {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
driver.addFile2(b);
driver.addFile2(c);
driver.addFile2(d);
driver.addFile2(e);
driver.addFile2(f);
// Initial analysis, all files analyzed in order of adding.
// Note, `f` has an error.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/c.dart
library: /home/test/lib/c.dart
[stream]
ResolvedUnitResult #2
path: /home/test/lib/c.dart
uri: package:test/c.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/d.dart
library: /home/test/lib/d.dart
[stream]
ResolvedUnitResult #3
path: /home/test/lib/d.dart
uri: package:test/d.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/e.dart
library: /home/test/lib/e.dart
[stream]
ResolvedUnitResult #4
path: /home/test/lib/e.dart
uri: package:test/e.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/f.dart
library: /home/test/lib/f.dart
[stream]
ResolvedUnitResult #5
path: /home/test/lib/f.dart
uri: package:test/f.dart
flags: exists isLibrary
errors
57 +1 EXTENDS_NON_CLASS
[status] idle
''');
// Update `b` with changing its API signature.
modifyFile2(b, r'''
class B {}
''');
driver.changeFile2(b);
// 1. The changed `b` is the first.
// 2. Then `d` that imports the changed `b`.
// 3. Then `f` that has an error (even if it is unrelated).
// 4. Then the rest, in order of adding.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #6
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/d.dart
library: /home/test/lib/d.dart
[stream]
ResolvedUnitResult #7
path: /home/test/lib/d.dart
uri: package:test/d.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/f.dart
library: /home/test/lib/f.dart
[stream]
ResolvedUnitResult #8
path: /home/test/lib/f.dart
uri: package:test/f.dart
flags: exists isLibrary
errors
57 +1 EXTENDS_NON_CLASS
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #9
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/c.dart
library: /home/test/lib/c.dart
[stream]
ResolvedUnitResult #10
path: /home/test/lib/c.dart
uri: package:test/c.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/e.dart
library: /home/test/lib/e.dart
[stream]
ResolvedUnitResult #11
path: /home/test/lib/e.dart
uri: package:test/e.dart
flags: exists isLibrary
[status] idle
''');
}
test_results_order_allChangedFirst_thenImports() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
class B {}
''');
var c = newFile('$testPackageLibPath/c.dart', r'''
''');
var d = newFile('$testPackageLibPath/d.dart', r'''
// ignore:unused_import
import 'a.dart';
''');
var e = newFile('$testPackageLibPath/e.dart', r'''
// ignore:unused_import
import 'b.dart';
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
driver.addFile2(b);
driver.addFile2(c);
driver.addFile2(d);
driver.addFile2(e);
// Initial analysis, all files analyzed in order of adding.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/c.dart
library: /home/test/lib/c.dart
[stream]
ResolvedUnitResult #2
path: /home/test/lib/c.dart
uri: package:test/c.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/d.dart
library: /home/test/lib/d.dart
[stream]
ResolvedUnitResult #3
path: /home/test/lib/d.dart
uri: package:test/d.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/e.dart
library: /home/test/lib/e.dart
[stream]
ResolvedUnitResult #4
path: /home/test/lib/e.dart
uri: package:test/e.dart
flags: exists isLibrary
[status] idle
''');
// Change b.dart and then a.dart files.
modifyFile2(a, r'''
class A2 {}
''');
modifyFile2(b, r'''
class B2 {}
''');
driver.changeFile2(b);
driver.changeFile2(a);
// First `a` and `b`.
// Then `d` and `e` because they import `a` and `b`.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #5
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #6
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/d.dart
library: /home/test/lib/d.dart
[stream]
ResolvedUnitResult #7
path: /home/test/lib/d.dart
uri: package:test/d.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/e.dart
library: /home/test/lib/e.dart
[stream]
ResolvedUnitResult #8
path: /home/test/lib/e.dart
uri: package:test/e.dart
flags: exists isLibrary
[status] idle
''');
}
test_results_removeFile_changeFile() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
final v = 0;
''');
var b = getFile('$testPackageLibPath/b.dart');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
// Initial analysis.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[status] idle
''');
// Update `a` to have an error.
modifyFile2(a, r'''
final v = 0
''');
// It does not matter what we do with `b`, it is not analyzed anyway.
// But we notify that `a` was changed, so it is analyzed.
driver.removeFile2(b);
driver.changeFile2(a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #1
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
errors
10 +1 EXPECTED_TOKEN
[status] idle
''');
}
test_results_skipNotAffected() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
class A {}
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
class B {}
''');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
driver.addFile2(b);
// Initial analysis.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[stream]
ResolvedUnitResult #1
path: /home/test/lib/b.dart
uri: package:test/b.dart
flags: exists isLibrary
[status] idle
''');
// Update `a` and notify.
modifyFile2(a, r'''
class A2 {}
''');
driver.changeFile2(a);
// Only `a` is analyzed, `b` is not affected.
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #2
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[status] idle
''');
}
test_schedulerStatus_hasAddedFile() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[stream]
ResolvedUnitResult #0
path: /home/test/lib/a.dart
uri: package:test/a.dart
flags: exists isLibrary
[status] idle
''');
}
test_schedulerStatus_noAddedFile() async {
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
// No files, so no status changes.
await assertEventsText(collector, r'''
''');
}
test_status_anyWorkTransitionsToAnalyzing() async {
var a = newFile('$testPackageLibPath/a.dart', '');
var b = newFile('$testPackageLibPath/b.dart', '');
var driver = driverFor(testFile);
var collector = DriverEventCollector(driver);
driver.addFile2(a);
driver.addFile2(b);
// Initial analysis.
configuration.withStreamResolvedUnitResults = false;
await assertEventsText(collector, r'''
[status] working
[operation] analyzeFile
file: /home/test/lib/a.dart
library: /home/test/lib/a.dart
[operation] analyzeFile
file: /home/test/lib/b.dart
library: /home/test/lib/b.dart
[status] idle
''');
// Any work transitions to analyzing, and back to idle.
await driver.getFilesReferencingName('X');
await assertEventsText(collector, r'''
[status] working
[status] idle
''');
}
}
/// Tracks events reported into the `results` stream, and results of `getXyz`
/// requests. We are interested in relative orders, identity of the objects,
/// absence of duplicate events, etc.
class DriverEventCollector {
final idProvider = IdProvider();
late AnalysisDriver driver;
List<DriverEvent> events = [];
final List<Completer<void>> statusIdleCompleters = [];
DriverEventCollector(this.driver) {
_listenSchedulerEvents(driver.scheduler);
}
DriverEventCollector.forCollection(
AnalysisContextCollectionImpl collection,
) {
_listenSchedulerEvents(collection.scheduler);
}
void getCachedResolvedUnit(String name, File file) {
var value = driver.getCachedResolvedUnit2(file);
events.add(
GetCachedResolvedUnitEvent(
name: name,
result: value,
),
);
}
void getErrors(String name, File file) {
var future = driver.getErrors(file.path);
unawaited(future.then((value) {
events.add(
GetErrorsEvent(
name: name,
result: value,
),
);
}));
}
void getIndex(String name, File file) async {
var value = await driver.getIndex(file.path);
events.add(
GetIndexEvent(
name: name,
result: value,
),
);
}
void getLibraryByUri(String name, String uriStr) {
var future = driver.getLibraryByUri(uriStr);
unawaited(future.then((value) {
events.add(
GetLibraryByUriEvent(
name: name,
result: value,
),
);
}));
}
void getResolvedLibrary(String name, File file) {
var future = driver.getResolvedLibrary(file.path);
unawaited(future.then((value) {
events.add(
GetResolvedLibraryEvent(
name: name,
result: value,
),
);
}));
}
void getResolvedLibraryByUri(String name, Uri uri) {
var future = driver.getResolvedLibraryByUri(uri);
unawaited(future.then((value) {
events.add(
GetResolvedLibraryByUriEvent(
name: name,
result: value,
),
);
}));
}
void getResolvedUnit(
String name,
File file, {
bool sendCachedToStream = false,
}) {
var future = driver.getResolvedUnit(
file.path,
sendCachedToStream: sendCachedToStream,
);
unawaited(future.then((value) {
events.add(
GetResolvedUnitEvent(
name: name,
result: value,
),
);
}));
}
void getUnitElement(String name, File file) {
var future = driver.getUnitElement2(file);
unawaited(future.then((value) {
events.add(
GetUnitElementEvent(
name: name,
result: value,
),
);
}));
}
Future<void> nextStatusIdle() {
var completer = Completer<void>();
statusIdleCompleters.add(completer);
return completer.future;
}
List<DriverEvent> take() {
var result = events;
events = [];
return result;
}
void _listenSchedulerEvents(AnalysisDriverScheduler scheduler) {
scheduler.events.listen((event) {
switch (event) {
case AnalysisStatus():
events.add(
SchedulerStatusEvent(event),
);
if (event.isIdle) {
statusIdleCompleters.completeAll();
statusIdleCompleters.clear();
}
case driver_events.AnalyzeFile():
case driver_events.GetErrorsFromBytes():
case ErrorsResult():
case ResolvedUnitResult():
events.add(
ResultStreamEvent(
object: event,
),
);
}
});
}
}
extension on AnalysisDriver {
Future<void> assertFilesDefiningClassMemberName(
String name,
List<File?> expected,
) async {
var fileStateList = await getFilesDefiningClassMemberName(name);
var files = fileStateList.resources;
expect(files, unorderedEquals(expected));
}
Future<void> assertFilesReferencingName(
String name, {
required List<File?> includesAll,
required List<File?> excludesAll,
}) async {
var fileStateList = await getFilesReferencingName(name);
var files = fileStateList.resources;
for (var expected in includesAll) {
expect(files, contains(expected));
}
for (var expected in excludesAll) {
expect(files, isNot(contains(expected)));
}
}
void assertLoadedLibraryUriSet({
Iterable<String>? included,
Iterable<String>? excluded,
}) {
var uriSet = testView!.loadedLibraryUriSet;
if (included != null) {
expect(uriSet, containsAll(included));
}
if (excluded != null) {
for (var excludedUri in excluded) {
expect(uriSet, isNot(contains(excludedUri)));
}
}
}
FileResult getFileSyncValid(File file) {
return getFileSync2(file) as FileResult;
}
Future<LibraryElementResult> getLibraryByUriValid(String uriStr) async {
return await getLibraryByUri(uriStr) as LibraryElementResult;
}
}
extension on DriverEventsPrinterConfiguration {
void withMacroFileContent() {
errorsConfiguration.withContentPredicate = (result) {
return result.isMacroAugmentation;
};
libraryConfiguration.unitConfiguration.withContentPredicate = (result) {
return result.isMacroAugmentation;
};
}
}