Macro. Support for getUnitElement()
Change-Id: Iefeb5594279e768031e88fb31ae59b983b35b705
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/346686
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Phil Quitslund <pquitslund@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 17cb3db..f91922e 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -818,9 +818,8 @@
// If a macro generated file, request its library instead.
var file = resourceProvider.getFile(path);
- if (file.path.removeSuffix('.macro.dart') case var noExtPath?) {
- var libraryPath = '$noExtPath.dart';
- _indexRequestedFiles.putIfAbsent(libraryPath, () => []);
+ if (file.libraryForMacro case var library?) {
+ _indexRequestedFiles.putIfAbsent(library.path, () => []);
}
// Schedule analysis.
@@ -1065,9 +1064,8 @@
// If a macro generated file, request its library instead.
var file = resourceProvider.getFile(path);
- if (file.path.removeSuffix('.macro.dart') case var noExtPath?) {
- var libraryPath = '$noExtPath.dart';
- _requestedFiles.putIfAbsent(libraryPath, () => []);
+ if (file.libraryForMacro case var library?) {
+ _requestedFiles.putIfAbsent(library.path, () => []);
}
// Schedule analysis.
@@ -1107,6 +1105,14 @@
);
}
+ // If a macro generated file, request its library.
+ // Once the library is ready, we can return the requested result.
+ var file = resourceProvider.getFile(path);
+ if (file.libraryForMacro case var library?) {
+ _unitElementRequestedFiles.putIfAbsent(library.path, () => []);
+ }
+
+ // Schedule analysis.
var completer = Completer<SomeUnitElementResult>();
_unitElementRequestedFiles.putIfAbsent(path, () => []).add(completer);
_scheduler.notify();
@@ -1198,7 +1204,7 @@
if (_unitElementRequestedFiles.isNotEmpty) {
String path = _unitElementRequestedFiles.keys.first;
var completers = _unitElementRequestedFiles.remove(path)!;
- final result = (await _computeUnitElement(path))!;
+ final result = await _computeUnitElement(path);
for (var completer in completers) {
completer.complete(result);
}
@@ -1514,7 +1520,7 @@
_resolvedLibraryCache.clear();
}
- Future<UnitElementResult?> _computeUnitElement(String path) async {
+ Future<UnitElementResult> _computeUnitElement(String path) async {
FileState file = _fsState.getFileForPath(path);
// Prepare the library - the file itself, or the known library.
@@ -2729,3 +2735,13 @@
remove(key)?.completeAll(value);
}
}
+
+extension on File {
+ File? get libraryForMacro {
+ if (path.removeSuffix('.macro.dart') case var noExtPath?) {
+ var libraryPath = '$noExtPath.dart';
+ return provider.getFile(libraryPath);
+ }
+ return null;
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index a585fe5..b00d8eb 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -2541,6 +2541,59 @@
''');
}
+ test_getResolvedLibraryByUri_withMacroGenerated() async {
+ if (!_configureWithCommonMacros()) {
+ return;
+ }
+
+ newFile('$testPackageLibPath/a.dart', r'''
+import 'append.dart';
+
+@DeclareInLibrary('class B {}')
+class A {}
+''');
+
+ final driver = driverFor(testFile);
+ final collector = DriverEventCollector(driver);
+
+ final 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] analyzing
+[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
+ name: 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
+---
+library augment 'a.dart';
+
+class B {}
+---
+[stream]
+ ResolvedUnitResult #2
+[status] idle
+''');
+ }
+
test_getResolvedUnit() async {
final a = newFile('$testPackageLibPath/a.dart', '');
@@ -3411,6 +3464,44 @@
expect(result, isA<InvalidPathResult>());
}
+ test_getUnitElement_macroGenerated() async {
+ if (!_configureWithCommonMacros()) {
+ return;
+ }
+
+ newFile('$testPackageLibPath/a.dart', r'''
+import 'append.dart';
+
+@DeclareInLibrary('class B {}')
+class A {}
+''');
+
+ final driver = driverFor(testFile);
+ final collector = DriverEventCollector(driver);
+
+ final 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] analyzing
+[future] getUnitElement
+ 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 {
final a = newFile('$testPackageLibPath/a.dart', r'''
part 'b.dart';