Macro. Build actual augmentation library after the types phase.

Change-Id: Iad7825acbf42d91e0cea4cc974a6be564a2b959d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/326243
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 bd51cdd..cd5dec6 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -88,7 +88,7 @@
 /// TODO(scheglov) Clean up the list of implicitly analyzed files.
 class AnalysisDriver implements AnalysisDriverGeneric {
   /// The version of data format, should be incremented on every format change.
-  static const int DATA_VERSION = 305;
+  static const int DATA_VERSION = 306;
 
   /// The number of exception contexts allowed to write. Once this field is
   /// zero, we stop writing any new exception contexts in this process.
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 70183be..b1723cb 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:collection';
+import 'dart:typed_data';
 
 import 'package:_fe_analyzer_shared/src/scanner/string_canonicalizer.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer.dart'
@@ -3951,6 +3952,8 @@
   @override
   final LibraryOrAugmentationElementImpl augmentationTarget;
 
+  MacroGenerationAugmentationLibrary? macroGenerated;
+
   LibraryAugmentationElementLinkedData? linkedData;
 
   LibraryAugmentationElementImpl({
@@ -4800,6 +4803,17 @@
       visitor.visitLocalVariableElement(this);
 }
 
+/// Additional information for a macro generated augmentation library.
+class MacroGenerationAugmentationLibrary {
+  final String code;
+  final Uint8List informativeBytes;
+
+  MacroGenerationAugmentationLibrary({
+    required this.code,
+    required this.informativeBytes,
+  });
+}
+
 mixin MacroTargetElement {
   /// Errors registered while applying macros to this element.
   List<MacroApplicationError> macroApplicationErrors = const [];
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index efb73e7..ecbd9bf 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -633,6 +633,13 @@
     required LibraryOrAugmentationElementImpl augmentationTarget,
     required Source unitSource,
   }) {
+    final macroGenerated = _reader.readOptionalObject((reader) {
+      return MacroGenerationAugmentationLibrary(
+        code: _reader.readStringUtf8(),
+        informativeBytes: _reader.readUint8List(),
+      );
+    });
+
     final definingUnit = _readUnitElement(
       containerSource: unitSource,
       unitSource: unitSource,
@@ -645,6 +652,7 @@
     );
     augmentation.definingCompilationUnit = definingUnit;
     augmentation.reference = definingUnit.reference!;
+    augmentation.macroGenerated = macroGenerated;
 
     final resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
     _readLibraryOrAugmentationElement(augmentation);
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index 4531795..4619a84 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -140,6 +140,10 @@
   }
 
   void _writeAugmentationElement(LibraryAugmentationElementImpl augmentation) {
+    _sink.writeOptionalObject(augmentation.macroGenerated, (macroGenerated) {
+      _sink.writeStringUtf8(macroGenerated.code);
+      _sink.writeUint8List(macroGenerated.informativeBytes);
+    });
     _writeUnitElement(augmentation.definingCompilationUnit);
     // The offset where resolution for the augmentation starts.
     // We need it to skip resolution information from the unit.
diff --git a/pkg/analyzer/lib/src/summary2/informative_data.dart b/pkg/analyzer/lib/src/summary2/informative_data.dart
index f0c8cbb..a507142 100644
--- a/pkg/analyzer/lib/src/summary2/informative_data.dart
+++ b/pkg/analyzer/lib/src/summary2/informative_data.dart
@@ -76,8 +76,7 @@
     var unitElements = libraryElement.units;
     for (var i = 0; i < unitElements.length; i++) {
       var unitElement = unitElements[i];
-      var unitUri = unitElement.source.uri;
-      var unitInfoBytes = _unitsInformativeBytes2[unitUri];
+      var unitInfoBytes = _getInfoUnitBytes(unitElement);
       if (unitInfoBytes != null) {
         var unitReader = SummaryDataReader(unitInfoBytes);
         var unitInfo = _InfoUnit(_infoDeclarationStore, unitReader);
@@ -706,6 +705,20 @@
     );
   }
 
+  Uint8List? _getInfoUnitBytes(CompilationUnitElement element) {
+    final uri = element.source.uri;
+    if (_unitsInformativeBytes2[uri] case final bytes?) {
+      return bytes;
+    }
+
+    switch (element.enclosingElement) {
+      case LibraryAugmentationElementImpl(:final macroGenerated?):
+        return macroGenerated.informativeBytes;
+    }
+
+    return null;
+  }
+
   void _setupApplyConstantOffsetsForTypeAlias(
     TypeAliasElementImpl element,
     Uint32List constantOffsets, {
diff --git a/pkg/analyzer/lib/src/summary2/library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart
index 045b2ed..0e44db6 100644
--- a/pkg/analyzer/lib/src/summary2/library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/library_builder.dart
@@ -20,6 +20,7 @@
 import 'package:analyzer/src/summary2/default_value_resolver.dart';
 import 'package:analyzer/src/summary2/element_builder.dart';
 import 'package:analyzer/src/summary2/export.dart';
+import 'package:analyzer/src/summary2/informative_data.dart';
 import 'package:analyzer/src/summary2/link.dart';
 import 'package:analyzer/src/summary2/macro_application.dart';
 import 'package:analyzer/src/summary2/metadata_resolver.dart';
@@ -276,6 +277,31 @@
     }
   }
 
+  void buildClassSyntheticConstructors() {
+    bool hasConstructor(ClassElementImpl element) {
+      if (element.constructors.isNotEmpty) return true;
+      if (element.augmentation case final augmentation?) {
+        return hasConstructor(augmentation);
+      }
+      return false;
+    }
+
+    for (final classElement in element.topLevelElements) {
+      if (classElement is! ClassElementImpl) continue;
+      if (classElement.isMixinApplication) continue;
+      if (classElement.isAugmentation) continue;
+      if (hasConstructor(classElement)) continue;
+
+      final constructor = ConstructorElementImpl('', -1)..isSynthetic = true;
+      final containerRef = classElement.reference!.getChild('@constructor');
+      final reference = containerRef.getChild('new');
+      reference.element = constructor;
+      constructor.reference = reference;
+
+      classElement.constructors = [constructor].toFixedList();
+    }
+  }
+
   /// Build elements for declarations in the library units, add top-level
   /// declarations to the local scope, for combining into export scopes.
   void buildElements() {
@@ -296,7 +322,6 @@
       }
       elementBuilder.buildDeclarationElements(linkingUnit.node);
     }
-    _buildClassSyntheticConstructors();
     _declareDartCoreDynamicNever();
   }
 
@@ -453,74 +478,89 @@
       },
     );
 
-    final augmentationLibrary = await performance.runAsync(
+    final augmentationCode = await performance.runAsync(
       'executeTypesPhase',
       (performance) async {
         return await macroApplier.executeTypesPhase();
       },
     );
 
-    if (augmentationLibrary == null) {
+    if (augmentationCode == null) {
       return;
     }
 
-    var parseResult = parseString(
-      content: augmentationLibrary,
+    final libraryFileName = uri.pathSegments.lastOrNull;
+    if (libraryFileName == null) {
+      return;
+    }
+
+    if (!libraryFileName.endsWith('.dart')) {
+      return;
+    }
+
+    final augmentationFileName =
+        '${libraryFileName.substring(0, '.dart'.length - 1)}.macro.dart';
+    final augmentationUri = uri.resolve(augmentationFileName);
+    final augmentationUriStr = '$augmentationUri';
+    final augmentationSource = _sourceFactory.forUri2(augmentationUri)!;
+
+    final parseResult = parseString(
+      content: augmentationCode,
       featureSet: element.featureSet,
       throwIfDiagnostics: false,
     );
-    var unitNode = parseResult.unit as ast.CompilationUnitImpl;
+    final unitNode = parseResult.unit as ast.CompilationUnitImpl;
 
-    // For now we model augmentation libraries as parts.
-    var unitUri = uri.resolve('_macro_types.dart');
-    final unitSource = _sourceFactory.forUri2(unitUri)!;
-    var unitElement = CompilationUnitElementImpl(
-      source: unitSource,
-      librarySource: element.source,
+    final unitElement = CompilationUnitElementImpl(
+      source: augmentationSource,
+      librarySource: augmentationSource,
       lineInfo: parseResult.lineInfo,
-    )
-      ..enclosingElement = element
-      ..isSynthetic = true
-      ..uri = unitUri.toString();
+    );
+    unitElement.uri = augmentationUriStr;
 
-    var unitReference = reference.getChild('@unit').getChild('$unitUri');
-    _bindReference(unitReference, unitElement);
+    final augmentationReference =
+        reference.getChild('@augmentation').getChild(augmentationUriStr);
+    _bindReference(augmentationReference, unitElement);
 
-    element.parts = [
-      ...element.parts,
-      PartElementImpl(
-        uri: DirectiveUriWithUnitImpl(
-          relativeUriString: '_macro_types.dart',
-          relativeUri: unitUri,
-          unit: unitElement,
-        ),
+    final augmentation = LibraryAugmentationElementImpl(
+      augmentationTarget: element,
+      nameOffset: -1,
+    );
+    augmentation.definingCompilationUnit = unitElement;
+
+    augmentation.macroGenerated = MacroGenerationAugmentationLibrary(
+      code: augmentationCode,
+      informativeBytes: writeUnitInformative(unitNode),
+    );
+
+    final directiveUri = DirectiveUriWithAugmentationImpl(
+      relativeUriString: augmentationUriStr,
+      relativeUri: augmentationUri,
+      source: augmentationSource,
+      augmentation: augmentation,
+    );
+
+    element.augmentationImports = [
+      ...element.augmentationImports,
+      AugmentationImportElementImpl(
+        importKeywordOffset: -1,
+        uri: directiveUri,
       ),
     ];
 
     ElementBuilder(
       libraryBuilder: this,
-      container: element,
-      unitReference: unitReference,
+      container: augmentation,
+      unitReference: augmentationReference,
       unitElement: unitElement,
     ).buildDeclarationElements(unitNode);
 
-    // We move elements, so they don't have real offsets.
-    unitElement.accept(_FlushElementOffsets());
-
     units.add(
       LinkingUnit(
-        reference: unitReference,
+        reference: augmentationReference,
         node: unitNode,
-        container: element,
         element: unitElement,
-      ),
-    );
-
-    linker.macroGeneratedUnits.add(
-      LinkMacroGeneratedUnit(
-        uri: unitUri,
-        content: parseResult.content,
-        unit: parseResult.unit,
+        container: element,
       ),
     );
   }
@@ -692,31 +732,6 @@
     );
   }
 
-  void _buildClassSyntheticConstructors() {
-    bool hasConstructor(ClassElementImpl element) {
-      if (element.constructors.isNotEmpty) return true;
-      if (element.augmentation case final augmentation?) {
-        return hasConstructor(augmentation);
-      }
-      return false;
-    }
-
-    for (final classElement in element.topLevelElements) {
-      if (classElement is! ClassElementImpl) continue;
-      if (classElement.isMixinApplication) continue;
-      if (classElement.isAugmentation) continue;
-      if (hasConstructor(classElement)) continue;
-
-      final constructor = ConstructorElementImpl('', -1)..isSynthetic = true;
-      final containerRef = classElement.reference!.getChild('@constructor');
-      final reference = containerRef.getChild('new');
-      reference.element = constructor;
-      constructor.reference = reference;
-
-      classElement.constructors = [constructor].toFixedList();
-    }
-  }
-
   List<NamespaceCombinator> _buildCombinators(
     List<UnlinkedCombinator> combinators2,
   ) {
diff --git a/pkg/analyzer/lib/src/summary2/link.dart b/pkg/analyzer/lib/src/summary2/link.dart
index 4175031..f5b1128 100644
--- a/pkg/analyzer/lib/src/summary2/link.dart
+++ b/pkg/analyzer/lib/src/summary2/link.dart
@@ -42,7 +42,6 @@
   );
   return LinkResult(
     resolutionBytes: linker.resolutionBytes,
-    macroGeneratedUnits: linker.macroGeneratedUnits,
   );
 }
 
@@ -60,8 +59,6 @@
 
   late Uint8List resolutionBytes;
 
-  final List<LinkMacroGeneratedUnit> macroGeneratedUnits = [];
-
   Linker(this.elementFactory, this.macroExecutor);
 
   AnalysisContextImpl get analysisContext {
@@ -181,6 +178,10 @@
       },
     );
 
+    for (final library in builders.values) {
+      library.buildClassSyntheticConstructors();
+    }
+
     macroDeclarationBuilder.transferToElements();
 
     for (var library in builders.values) {
@@ -319,24 +320,10 @@
   }
 }
 
-class LinkMacroGeneratedUnit {
-  final Uri uri;
-  final String content;
-  final ast.CompilationUnit unit;
-
-  LinkMacroGeneratedUnit({
-    required this.uri,
-    required this.content,
-    required this.unit,
-  });
-}
-
 class LinkResult {
   final Uint8List resolutionBytes;
-  final List<LinkMacroGeneratedUnit> macroGeneratedUnits;
 
   LinkResult({
     required this.resolutionBytes,
-    required this.macroGeneratedUnits,
   });
 }
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index 54a2ab8..df74712 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -671,6 +671,15 @@
 
     _writeElements('exports', e.libraryExports, _writeExportElement);
 
+    if (e is LibraryAugmentationElementImpl) {
+      if (e.macroGenerated case final macroGenerated?) {
+        _sink.writelnWithIndent('macroGeneratedCode');
+        _sink.writeln('---');
+        _sink.writeln(macroGenerated.code);
+        _sink.writeln('---');
+      }
+    }
+
     _sink.writelnWithIndent('definingUnit');
     _sink.withIndent(() {
       _writeUnitElement(e.definingCompilationUnit);
diff --git a/pkg/analyzer/test/src/summary/macro_test.dart b/pkg/analyzer/test/src/summary/macro_test.dart
index edbe5a6..cbcaa8c 100644
--- a/pkg/analyzer/test/src/summary/macro_test.dart
+++ b/pkg/analyzer/test/src/summary/macro_test.dart
@@ -103,7 +103,7 @@
 class A {}
 ''');
 
-    configuration.withExportScope = true;
+    configuration.withMetadata = false;
     checkElementText(library, r'''
 library
   imports
@@ -111,29 +111,19 @@
   definingUnit
     classes
       class A @35
-        metadata
-          Annotation
-            atSign: @ @18
-            name: SimpleIdentifier
-              token: MyMacro @19
-              staticElement: package:test/a.dart::@class::MyMacro
-              staticType: null
-            arguments: ArgumentList
-              leftParenthesis: ( @26
-              rightParenthesis: ) @27
-            element: package:test/a.dart::@class::MyMacro::@constructor::new
         constructors
           synthetic @-1
-  parts
-    package:test/_macro_types.dart
-      classes
-        class MyClass @-1
-  exportedReferences
-    declared self::@class::MyClass
-    declared self::@class::A
-  exportNamespace
-    A: self::@class::A
-    MyClass: self::@class::MyClass
+  augmentationImports
+    package:test/test.macro.dart
+      macroGeneratedCode
+---
+class MyClass {}
+---
+      definingUnit
+        classes
+          class MyClass @6
+            constructors
+              synthetic @-1
 ''');
   }
 
@@ -161,7 +151,7 @@
 class A {}
 ''');
 
-    configuration.withExportScope = true;
+    configuration.withMetadata = false;
     checkElementText(library, r'''
 library
   imports
@@ -169,37 +159,19 @@
   definingUnit
     classes
       class A @41
-        metadata
-          Annotation
-            atSign: @ @18
-            name: PrefixedIdentifier
-              prefix: SimpleIdentifier
-                token: MyMacro @19
-                staticElement: package:test/a.dart::@class::MyMacro
-                staticType: null
-              period: . @26
-              identifier: SimpleIdentifier
-                token: named @27
-                staticElement: package:test/a.dart::@class::MyMacro::@constructor::named
-                staticType: null
-              staticElement: package:test/a.dart::@class::MyMacro::@constructor::named
-              staticType: null
-            arguments: ArgumentList
-              leftParenthesis: ( @32
-              rightParenthesis: ) @33
-            element: package:test/a.dart::@class::MyMacro::@constructor::named
         constructors
           synthetic @-1
-  parts
-    package:test/_macro_types.dart
-      classes
-        class MyClass @-1
-  exportedReferences
-    declared self::@class::MyClass
-    declared self::@class::A
-  exportNamespace
-    A: self::@class::A
-    MyClass: self::@class::MyClass
+  augmentationImports
+    package:test/test.macro.dart
+      macroGeneratedCode
+---
+class MyClass {}
+---
+      definingUnit
+        classes
+          class MyClass @6
+            constructors
+              synthetic @-1
 ''');
   }
 
@@ -226,7 +198,7 @@
 class A {}
 ''');
 
-    configuration.withExportScope = true;
+    configuration.withMetadata = false;
     checkElementText(library, r'''
 library
   imports
@@ -234,37 +206,19 @@
   definingUnit
     classes
       class A @52
-        metadata
-          Annotation
-            atSign: @ @28
-            name: PrefixedIdentifier
-              prefix: SimpleIdentifier
-                token: prefix @29
-                staticElement: self::@prefix::prefix
-                staticType: null
-              period: . @35
-              identifier: SimpleIdentifier
-                token: MyMacro @36
-                staticElement: package:test/a.dart::@class::MyMacro
-                staticType: null
-              staticElement: package:test/a.dart::@class::MyMacro
-              staticType: null
-            arguments: ArgumentList
-              leftParenthesis: ( @43
-              rightParenthesis: ) @44
-            element: package:test/a.dart::@class::MyMacro::@constructor::new
         constructors
           synthetic @-1
-  parts
-    package:test/_macro_types.dart
-      classes
-        class MyClass @-1
-  exportedReferences
-    declared self::@class::MyClass
-    declared self::@class::A
-  exportNamespace
-    A: self::@class::A
-    MyClass: self::@class::MyClass
+  augmentationImports
+    package:test/test.macro.dart
+      macroGeneratedCode
+---
+class MyClass {}
+---
+      definingUnit
+        classes
+          class MyClass @6
+            constructors
+              synthetic @-1
 ''');
   }
 
@@ -291,7 +245,7 @@
 class A {}
 ''');
 
-    configuration.withExportScope = true;
+    configuration.withMetadata = false;
     checkElementText(library, r'''
 library
   imports
@@ -299,42 +253,19 @@
   definingUnit
     classes
       class A @58
-        metadata
-          Annotation
-            atSign: @ @28
-            name: PrefixedIdentifier
-              prefix: SimpleIdentifier
-                token: prefix @29
-                staticElement: self::@prefix::prefix
-                staticType: null
-              period: . @35
-              identifier: SimpleIdentifier
-                token: MyMacro @36
-                staticElement: package:test/a.dart::@class::MyMacro
-                staticType: null
-              staticElement: package:test/a.dart::@class::MyMacro
-              staticType: null
-            period: . @43
-            constructorName: SimpleIdentifier
-              token: named @44
-              staticElement: package:test/a.dart::@class::MyMacro::@constructor::named
-              staticType: null
-            arguments: ArgumentList
-              leftParenthesis: ( @49
-              rightParenthesis: ) @50
-            element: package:test/a.dart::@class::MyMacro::@constructor::named
         constructors
           synthetic @-1
-  parts
-    package:test/_macro_types.dart
-      classes
-        class MyClass @-1
-  exportedReferences
-    declared self::@class::MyClass
-    declared self::@class::A
-  exportNamespace
-    A: self::@class::A
-    MyClass: self::@class::MyClass
+  augmentationImports
+    package:test/test.macro.dart
+      macroGeneratedCode
+---
+class MyClass {}
+---
+      definingUnit
+        classes
+          class MyClass @6
+            constructors
+              synthetic @-1
 ''');
   }
 
@@ -1449,8 +1380,9 @@
     }
 
     if (expected != null) {
-      final partUri = library.parts.single.uri as DirectiveUriWithUnit;
-      final x = partUri.unit.topLevelVariables.single;
+      final macroAugmentation = library.augmentations.first;
+      final macroUnit = macroAugmentation.definingCompilationUnit;
+      final x = macroUnit.topLevelVariables.single;
       expect(x.name, 'x');
       x as ConstTopLevelVariableElementImpl;
       final actual = (x.constantInitializer as SimpleStringLiteral).value;
@@ -1506,8 +1438,9 @@
       library.definingCompilationUnit.getClass('A'),
     );
 
-    final partUri = library.parts.single.uri as DirectiveUriWithUnit;
-    final x = partUri.unit.topLevelVariables.single;
+    final macroAugmentation = library.augmentations.first;
+    final macroUnit = macroAugmentation.definingCompilationUnit;
+    final x = macroUnit.topLevelVariables.single;
     expect(x.name, 'x');
     x as ConstTopLevelVariableElementImpl;
     var x_literal = x.constantInitializer as SimpleStringLiteral;