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';