Basic support for linking with macro-generated code.

Only classes and methods for now.

Change-Id: Iacca78a25b34ef8ebd7f74eca0876996009025be
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/207260
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index c7726fb..4743b03 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -80,7 +80,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 = 161;
+  static const int DATA_VERSION = 162;
 
   /// 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 740d067..4c232e6 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -969,6 +969,13 @@
   @override
   LineInfo? lineInfo;
 
+  /// The path of the file which is derived from the [source], and in addition
+  /// to source declarations contains also declarations added by running
+  /// macro(s).
+  ///
+  /// Might be `null` if there is no corresponding macro-produced file.
+  String? macroPath;
+
   /// The source of the library containing this compilation unit.
   ///
   /// This is the same as the source of the containing [LibraryElement],
@@ -2361,6 +2368,16 @@
   /// children of this element's parent.
   String get identifier => name!;
 
+  /// Return `true` if this element was created from a declaration that
+  /// exists in a macro-generated code, but not in the source code.
+  bool get isFromMacro {
+    return hasModifier(Modifier.IS_FROM_MACRO);
+  }
+
+  set isFromMacro(bool isFromMacro) {
+    setModifier(Modifier.IS_FROM_MACRO, isFromMacro);
+  }
+
   bool get isNonFunctionTypeAliasesEnabled {
     return library!.featureSet.isEnabled(Feature.nonfunction_type_aliases);
   }
@@ -4281,23 +4298,26 @@
   /// type being referred to is the return type.
   static const Modifier IMPLICIT_TYPE = Modifier('IMPLICIT_TYPE', 16);
 
+  /// Indicates that this element was created from macro-generated code.
+  static const Modifier IS_FROM_MACRO = Modifier('IS_FROM_MACRO', 17);
+
   /// Indicates that modifier 'lazy' was applied to the element.
-  static const Modifier LATE = Modifier('LATE', 17);
+  static const Modifier LATE = Modifier('LATE', 18);
 
   /// Indicates that a class is a mixin application.
-  static const Modifier MIXIN_APPLICATION = Modifier('MIXIN_APPLICATION', 18);
+  static const Modifier MIXIN_APPLICATION = Modifier('MIXIN_APPLICATION', 19);
 
   /// Indicates that the pseudo-modifier 'set' was applied to the element.
-  static const Modifier SETTER = Modifier('SETTER', 19);
+  static const Modifier SETTER = Modifier('SETTER', 20);
 
   /// Indicates that the modifier 'static' was applied to the element.
-  static const Modifier STATIC = Modifier('STATIC', 20);
+  static const Modifier STATIC = Modifier('STATIC', 21);
 
   /// Indicates that the element does not appear in the source code but was
   /// implicitly created. For example, if a class does not define any
   /// constructors, an implicit zero-argument constructor will be created and it
   /// will be marked as being synthetic.
-  static const Modifier SYNTHETIC = Modifier('SYNTHETIC', 21);
+  static const Modifier SYNTHETIC = Modifier('SYNTHETIC', 22);
 
   static const List<Modifier> values = [
     ABSTRACT,
@@ -4316,6 +4336,7 @@
     HAS_INITIALIZER,
     HAS_PART_OF_DIRECTIVE,
     IMPLICIT_TYPE,
+    IS_FROM_MACRO,
     LATE,
     MIXIN_APPLICATION,
     SETTER,
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index cccbbb3..dd65232 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -31,6 +31,7 @@
 class BundleReader {
   final SummaryDataReader _reader;
   final Map<Uri, Uint8List> _unitsInformativeBytes;
+  final Map<Uri, Uint8List> _macroUnitsInformativeBytes;
 
   final Map<String, LibraryReader> libraryMap = {};
 
@@ -38,8 +39,10 @@
     required LinkedElementFactory elementFactory,
     required Uint8List resolutionBytes,
     Map<Uri, Uint8List> unitsInformativeBytes = const {},
+    Map<Uri, Uint8List> macroUnitsInformativeBytes = const {},
   })  : _reader = SummaryDataReader(resolutionBytes),
-        _unitsInformativeBytes = unitsInformativeBytes {
+        _unitsInformativeBytes = unitsInformativeBytes,
+        _macroUnitsInformativeBytes = macroUnitsInformativeBytes {
     _reader.offset = _reader.bytes.length - 4 * 4;
     var baseResolutionOffset = _reader.readUInt32();
     var librariesOffset = _reader.readUInt32();
@@ -70,6 +73,7 @@
         elementFactory: elementFactory,
         reader: _reader,
         unitsInformativeBytes: _unitsInformativeBytes,
+        macroUnitsInformativeBytes: _macroUnitsInformativeBytes,
         baseResolutionOffset: baseResolutionOffset,
         referenceReader: referenceReader,
         reference: reference,
@@ -84,6 +88,7 @@
   ApplyConstantOffsets? applyConstantOffsets;
   void Function()? _readMembers;
   void Function()? applyInformativeDataToMembers;
+  void Function()? applyInformativeDataToMacroMembers;
 
   ClassElementLinkedData({
     required Reference reference,
@@ -106,6 +111,9 @@
 
       applyInformativeDataToMembers?.call();
       applyInformativeDataToMembers = null;
+
+      applyInformativeDataToMacroMembers?.call();
+      applyInformativeDataToMacroMembers = null;
     }
   }
 
@@ -416,6 +424,7 @@
   final LinkedElementFactory _elementFactory;
   final SummaryDataReader _reader;
   final Map<Uri, Uint8List> _unitsInformativeBytes;
+  final Map<Uri, Uint8List> _macroUnitsInformativeBytes;
   final int _baseResolutionOffset;
   final _ReferenceReader _referenceReader;
   final Reference _reference;
@@ -430,6 +439,7 @@
     required LinkedElementFactory elementFactory,
     required SummaryDataReader reader,
     required Map<Uri, Uint8List> unitsInformativeBytes,
+    required Map<Uri, Uint8List> macroUnitsInformativeBytes,
     required int baseResolutionOffset,
     required _ReferenceReader referenceReader,
     required Reference reference,
@@ -438,6 +448,7 @@
   })  : _elementFactory = elementFactory,
         _reader = reader,
         _unitsInformativeBytes = unitsInformativeBytes,
+        _macroUnitsInformativeBytes = macroUnitsInformativeBytes,
         _baseResolutionOffset = baseResolutionOffset,
         _referenceReader = referenceReader,
         _reference = reference,
@@ -496,6 +507,10 @@
     InformativeDataApplier(_elementFactory, _unitsInformativeBytes)
         .applyTo(libraryElement);
 
+    InformativeDataApplier(_elementFactory, _macroUnitsInformativeBytes,
+            onlyIfFromMacro: true)
+        .applyTo(libraryElement);
+
     return libraryElement;
   }
 
@@ -1208,6 +1223,7 @@
     unitElement.uri = _reader.readOptionalStringReference();
     unitElement.isSynthetic = _reader.readBool();
     unitElement.sourceContent = _reader.readOptionalStringUtf8();
+    unitElement.macroPath = _reader.readOptionalStringUtf8();
 
     _readClasses(unitElement, unitReference);
     _readEnums(unitElement, unitReference);
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index 528b9d2..cb33459 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -441,6 +441,7 @@
     _sink._writeOptionalStringReference(unitElement.uri);
     _sink.writeBool(unitElement.isSynthetic);
     _sink.writeOptionalStringUtf8(unitElement.sourceContent);
+    _sink.writeOptionalStringUtf8(unitElement.macroPath);
     _resolutionSink._writeAnnotationList(unitElement.metadata);
     _writeList(unitElement.classes, _writeClassElement);
     _writeList(unitElement.enums, _writeEnumElement);
diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart
index 3737f6e..2d5d9c2 100644
--- a/pkg/analyzer/lib/src/summary2/element_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/element_builder.dart
@@ -56,6 +56,21 @@
     _unitElement.typeAliases = _enclosingContext.typeAliases;
   }
 
+  void buildDeclarationElementsMacro(CompilationUnit? unit) {
+    if (unit == null) {
+      return;
+    }
+
+    _visitPropertyFirst<TopLevelVariableDeclaration>(unit.declarations);
+
+    _unitElement.classes = _mergeElements(
+      _unitElement.classes,
+      _enclosingContext.classes,
+    );
+
+    // TODO(scheglov) other top-level elements
+  }
+
   /// Build exports and imports, metadata into [_libraryElement].
   void buildLibraryElementChildren(CompilationUnit unit) {
     unit.directives.accept(this);
@@ -972,6 +987,41 @@
     node?.accept(this);
   }
 
+  /// Return a new list that includes [sourceElements] plus elements
+  /// with not yet existing names from [macroElements].
+  List<T> _mergeElements<T extends Element>(
+    List<T> sourceElements,
+    List<T> macroElements,
+  ) {
+    var result = <T>[];
+
+    var sourceMap = <String, T>{};
+    for (var element in sourceElements) {
+      var name = element.name;
+      if (name != null) {
+        result.add(element);
+        sourceMap[name] = element;
+      }
+    }
+
+    for (var element in macroElements) {
+      var sourceElement = sourceMap[element.name];
+      if (sourceElement == null) {
+        (element as ElementImpl).isFromMacro = true;
+        result.add(element);
+      } else if (sourceElement is ClassElementImpl &&
+          element is ClassElementImpl) {
+        sourceElement.methods = _mergeElements(
+          sourceElement.methods,
+          element.methods,
+        );
+      }
+      // TODO(scheglov) Other class members.
+    }
+
+    return result;
+  }
+
   Uri? _selectAbsoluteUri(NamespaceDirective directive) {
     var relativeUriStr = _selectRelativeUri(
       directive.configurations,
diff --git a/pkg/analyzer/lib/src/summary2/element_flags.dart b/pkg/analyzer/lib/src/summary2/element_flags.dart
index e808000..a2bce77 100644
--- a/pkg/analyzer/lib/src/summary2/element_flags.dart
+++ b/pkg/analyzer/lib/src/summary2/element_flags.dart
@@ -8,12 +8,14 @@
 
 class ClassElementFlags {
   static const int _isAbstract = 1 << 0;
-  static const int _isMixinApplication = 1 << 1;
-  static const int _isSimplyBounded = 1 << 2;
+  static const int _isFromMacro = 1 << 1;
+  static const int _isMixinApplication = 1 << 2;
+  static const int _isSimplyBounded = 1 << 3;
 
   static void read(SummaryDataReader reader, ClassElementImpl element) {
     var byte = reader.readByte();
     element.isAbstract = (byte & _isAbstract) != 0;
+    element.isFromMacro = (byte & _isFromMacro) != 0;
     element.isMixinApplication = (byte & _isMixinApplication) != 0;
     element.isSimplyBounded = (byte & _isSimplyBounded) != 0;
   }
@@ -21,6 +23,7 @@
   static void write(BufferedSink sink, ClassElementImpl element) {
     var result = 0;
     result |= element.isAbstract ? _isAbstract : 0;
+    result |= element.isFromMacro ? _isFromMacro : 0;
     result |= element.isMixinApplication ? _isMixinApplication : 0;
     result |= element.isSimplyBounded ? _isSimplyBounded : 0;
     sink.writeByte(result);
@@ -161,8 +164,9 @@
   static const int _isAbstract = 1 << 1;
   static const int _isAsynchronous = 1 << 2;
   static const int _isExternal = 1 << 3;
-  static const int _isGenerator = 1 << 4;
-  static const int _isStatic = 1 << 5;
+  static const int _isFromMacro = 1 << 4;
+  static const int _isGenerator = 1 << 5;
+  static const int _isStatic = 1 << 6;
 
   static void read(SummaryDataReader reader, MethodElementImpl element) {
     var byte = reader.readByte();
@@ -170,6 +174,7 @@
     element.isAbstract = (byte & _isAbstract) != 0;
     element.isAsynchronous = (byte & _isAsynchronous) != 0;
     element.isExternal = (byte & _isExternal) != 0;
+    element.isFromMacro = (byte & _isFromMacro) != 0;
     element.isGenerator = (byte & _isGenerator) != 0;
     element.isStatic = (byte & _isStatic) != 0;
   }
@@ -180,6 +185,7 @@
     result |= element.isAbstract ? _isAbstract : 0;
     result |= element.isAsynchronous ? _isAsynchronous : 0;
     result |= element.isExternal ? _isExternal : 0;
+    result |= element.isFromMacro ? _isFromMacro : 0;
     result |= element.isGenerator ? _isGenerator : 0;
     result |= element.isStatic ? _isStatic : 0;
     sink.writeByte(result);
diff --git a/pkg/analyzer/lib/src/summary2/informative_data.dart b/pkg/analyzer/lib/src/summary2/informative_data.dart
index 1dd1e5f..fda2dbc 100644
--- a/pkg/analyzer/lib/src/summary2/informative_data.dart
+++ b/pkg/analyzer/lib/src/summary2/informative_data.dart
@@ -55,12 +55,16 @@
 
 class InformativeDataApplier {
   final LinkedElementFactory _elementFactory;
-  final Map<Uri, Uint8List> _unitsInformativeBytes2;
+  final Map<Uri, Uint8List> _unitsInformativeBytes;
+
+  /// Apply only to elements that are from macro-generated code.
+  final bool _onlyIfFromMacro;
 
   InformativeDataApplier(
     this._elementFactory,
-    this._unitsInformativeBytes2,
-  );
+    this._unitsInformativeBytes, {
+    bool onlyIfFromMacro = false,
+  }) : _onlyIfFromMacro = onlyIfFromMacro;
 
   void applyTo(LibraryElementImpl libraryElement) {
     if (_elementFactory.isApplyingInformativeData) {
@@ -72,7 +76,7 @@
     for (var i = 0; i < unitElements.length; i++) {
       var unitElement = unitElements[i] as CompilationUnitElementImpl;
       var unitUri = unitElement.source.uri;
-      var unitInfoBytes = _unitsInformativeBytes2[unitUri];
+      var unitInfoBytes = _unitsInformativeBytes[unitUri];
       if (unitInfoBytes != null) {
         var unitReader = SummaryDataReader(unitInfoBytes);
         var unitInfo = _InfoUnit(unitReader);
@@ -177,28 +181,37 @@
     _InfoClassDeclaration info,
   ) {
     element as ClassElementImpl;
-    element.setCodeRange(info.codeOffset, info.codeLength);
-    element.nameOffset = info.nameOffset;
-    element.documentationComment = info.documentationComment;
-    _applyToTypeParameters(
-      element.typeParameters_unresolved,
-      info.typeParameters,
-    );
-
     var linkedData = element.linkedData as ClassElementLinkedData;
-    linkedData.applyConstantOffsets = ApplyConstantOffsets(
-      info.constantOffsets,
-      (applier) {
-        applier.applyToMetadata(element);
-        applier.applyToTypeParameters(element.typeParameters);
-      },
-    );
-    linkedData.applyInformativeDataToMembers = () {
-      _applyToConstructors(element.constructors, info.constructors);
-      _applyToFields(element.fields, info.fields);
-      _applyToAccessors(element.accessors, info.accessors);
-      _applyToMethods(element.methods, info.methods);
-    };
+    if (_shouldApply(element)) {
+      element.setCodeRange(info.codeOffset, info.codeLength);
+      element.nameOffset = info.nameOffset;
+      element.documentationComment = info.documentationComment;
+      _applyToTypeParameters(
+        element.typeParameters_unresolved,
+        info.typeParameters,
+      );
+
+      linkedData.applyConstantOffsets = ApplyConstantOffsets(
+        info.constantOffsets,
+        (applier) {
+          applier.applyToMetadata(element);
+          applier.applyToTypeParameters(element.typeParameters);
+        },
+      );
+      linkedData.applyInformativeDataToMembers = () {
+        _applyToConstructors(element.constructors, info.constructors);
+        _applyToFields(element.fields, info.fields);
+        _applyToAccessors(element.accessors, info.accessors);
+        _applyToMethods(element.methods, info.methods);
+      };
+    } else {
+      linkedData.applyInformativeDataToMacroMembers = () {
+        _applyToConstructors(element.constructors, info.constructors);
+        _applyToFields(element.fields, info.fields);
+        _applyToAccessors(element.accessors, info.accessors);
+        _applyToMethods(element.methods, info.methods);
+      };
+    }
   }
 
   void _applyToClassTypeAlias(
@@ -508,6 +521,10 @@
       infoList,
       (element, info) {
         element as MethodElementImpl;
+        if (!_shouldApply(element)) {
+          return;
+        }
+
         element.setCodeRange(info.codeOffset, info.codeLength);
         element.nameOffset = info.nameOffset;
         element.documentationComment = info.documentationComment;
@@ -627,6 +644,10 @@
       },
     );
   }
+
+  bool _shouldApply(ElementImpl element) {
+    return !_onlyIfFromMacro || element.isFromMacro;
+  }
 }
 
 class _InfoClassDeclaration {
diff --git a/pkg/analyzer/lib/src/summary2/library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart
index 2c1a0b3..3340f8a 100644
--- a/pkg/analyzer/lib/src/summary2/library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/library_builder.dart
@@ -110,6 +110,12 @@
         elementBuilder.buildLibraryElementChildren(linkingUnit.node);
       }
       elementBuilder.buildDeclarationElements(linkingUnit.node);
+
+      ElementBuilder(
+        libraryBuilder: this,
+        unitReference: linkingUnit.reference,
+        unitElement: linkingUnit.element,
+      ).buildDeclarationElementsMacro(linkingUnit.macroNode);
     }
     if ('$uri' == 'dart:core') {
       localScope.declare('dynamic', reference.getChild('dynamic'));
@@ -171,6 +177,7 @@
         linkingUnit.node.featureSet.isEnabled(Feature.non_nullable),
       );
       linkingUnit.node.accept(resolver);
+      linkingUnit.macroNode?.accept(resolver);
     }
   }
 
@@ -236,6 +243,7 @@
     var linkingUnits = <LinkingUnit>[];
     for (var inputUnit in inputLibrary.units) {
       var unitNode = inputUnit.unit as ast.CompilationUnitImpl;
+      var unitMacroNode = inputUnit.macro?.unit as ast.CompilationUnitImpl?;
 
       var unitElement = CompilationUnitElementImpl();
       unitElement.isSynthetic = inputUnit.isSynthetic;
@@ -243,6 +251,7 @@
       unitElement.lineInfo = unitNode.lineInfo;
       unitElement.source = inputUnit.source;
       unitElement.sourceContent = inputUnit.sourceContent;
+      unitElement.macroPath = inputUnit.macro?.path;
       unitElement.uri = inputUnit.partUriStr;
       unitElement.setCodeRange(0, unitNode.length);
 
@@ -256,6 +265,7 @@
           isDefiningUnit: isDefiningUnit,
           reference: unitReference,
           node: unitNode,
+          macroNode: unitMacroNode,
           element: unitElement,
         ),
       );
@@ -287,6 +297,7 @@
   final bool isDefiningUnit;
   final Reference reference;
   final ast.CompilationUnitImpl node;
+  final ast.CompilationUnitImpl? macroNode;
   final CompilationUnitElementImpl element;
 
   LinkingUnit({
@@ -294,6 +305,7 @@
     required this.isDefiningUnit,
     required this.reference,
     required this.node,
+    required this.macroNode,
     required this.element,
   });
 }
diff --git a/pkg/analyzer/lib/src/summary2/link.dart b/pkg/analyzer/lib/src/summary2/link.dart
index f0b0174..3b51acc 100644
--- a/pkg/analyzer/lib/src/summary2/link.dart
+++ b/pkg/analyzer/lib/src/summary2/link.dart
@@ -251,6 +251,7 @@
   final String? sourceContent;
   final bool isSynthetic;
   final ast.CompilationUnit unit;
+  final LinkInputUnitMacro? macro;
 
   LinkInputUnit({
     required this.partDirectiveIndex,
@@ -259,6 +260,7 @@
     this.sourceContent,
     required this.isSynthetic,
     required this.unit,
+    this.macro,
   });
 
   Uri get uri => source.uri;
@@ -266,6 +268,19 @@
   String get uriStr => '$uri';
 }
 
+class LinkInputUnitMacro {
+  /// The path of the file that was parsed into [unit].
+  /// We don't need complete [Source] because this file does not have a
+  /// separate [Uri], it is a reflection of the source file.
+  final String path;
+  final ast.CompilationUnit unit;
+
+  LinkInputUnitMacro({
+    required this.path,
+    required this.unit,
+  });
+}
+
 class LinkResult {
   @Deprecated('This field is not used anymore')
   final Uint8List astBytes = Uint8List(0);
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index 4243b45..61f9169 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -269,6 +269,7 @@
 
   void _writeClassElement(ClassElement e) {
     _writeIndentedLine(() {
+      _writeFromMacro(e);
       _writeIf(e.isAbstract && !e.isMixin, 'abstract ');
       _writeIf(!e.isSimplyBounded, 'notSimplyBounded ');
 
@@ -470,6 +471,10 @@
     _assertNonSyntheticElementSelf(e);
   }
 
+  void _writeFromMacro(Element e) {
+    _writeIf((e as ElementImpl).isFromMacro, 'fromMacro ');
+  }
+
   void _writeFunctionElement(FunctionElement e) {
     _writeIndentedLine(() {
       _writeIf(e.isExternal, 'external ');
@@ -541,6 +546,7 @@
 
   void _writeMethodElement(MethodElement e) {
     _writeIndentedLine(() {
+      _writeFromMacro(e);
       _writeIf(e.isSynthetic, 'synthetic ');
       _writeIf(e.isStatic, 'static ');
       _writeIf(e.isAbstract, 'abstract ');
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
index 3a95b46..2466ab4 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
@@ -100,10 +100,17 @@
     _addNonDartLibraries({}, inputLibraries, source);
 
     var unitsInformativeBytes = <Uri, Uint8List>{};
+    var macroUnitsInformativeBytes = <Uri, Uint8List>{};
     for (var inputLibrary in inputLibraries) {
       for (var inputUnit in inputLibrary.units) {
         var informativeBytes = writeUnitInformative(inputUnit.unit);
         unitsInformativeBytes[inputUnit.uri] = informativeBytes;
+
+        var macroUnit = inputUnit.macro?.unit;
+        if (macroUnit != null) {
+          var informativeBytes = writeUnitInformative(macroUnit);
+          macroUnitsInformativeBytes[inputUnit.uri] = informativeBytes;
+        }
       }
     }
 
@@ -138,6 +145,7 @@
         BundleReader(
           elementFactory: elementFactory,
           unitsInformativeBytes: unitsInformativeBytes,
+          macroUnitsInformativeBytes: macroUnitsInformativeBytes,
           resolutionBytes: linkResult.resolutionBytes,
         ),
       );
@@ -156,12 +164,31 @@
     List<LinkInputUnit> units,
     FeatureSet featureSet,
   ) {
+    LinkInputUnitMacro? definingUnitMacro;
+    {
+      var macroSource = sourceFactory.resolveUri(
+        definingSource,
+        definingSource.shortName.replaceAll('.dart', '.macro_dart'),
+      );
+      var macroPath = macroSource?.fullName;
+      if (macroPath != null) {
+        var text = _readSafely(macroPath);
+        if (text.isNotEmpty) {
+          definingUnitMacro = LinkInputUnitMacro(
+            path: macroPath,
+            unit: parseText(text, featureSet),
+          );
+        }
+      }
+    }
+
     units.add(
       LinkInputUnit(
         partDirectiveIndex: null,
         source: definingSource,
         isSynthetic: false,
         unit: definingUnit,
+        macro: definingUnitMacro,
       ),
     );
 
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 3859042..fe2372d 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -21246,6 +21246,96 @@
 ''');
   }
 
+  test_macro_addClass() async {
+    newFile('/test.macro_dart', content: r'''
+class A {}
+class B {}
+''');
+    var library = await checkLibrary('''
+class A {}
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @6
+        constructors
+          synthetic @-1
+      fromMacro class B @17
+        constructors
+          synthetic @-1
+''');
+    _assertMacroPath(
+      library.definingCompilationUnit,
+      convertPath('/test.macro_dart'),
+    );
+  }
+
+  test_macro_addToClass_addMethod() async {
+    newFile('/test.macro_dart', content: r'''
+class A {
+  void foo() {}
+  void bar(int a) {}
+}
+''');
+    var library = await checkLibrary('''
+class A {
+  void foo() {}
+}
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @6
+        constructors
+          synthetic @-1
+        methods
+          foo @17
+            returnType: void
+          fromMacro bar @33
+            parameters
+              requiredPositional a @41
+                type: int
+            returnType: void
+''');
+  }
+
+  test_macro_addToClass_addMethod_offsets() async {
+    newFile('/test.macro_dart', content: r'''
+class A {
+  void foo() {}
+  void bar(int a) {}
+}
+''');
+    var library = await checkLibrary('''
+/// shift
+class A {
+  void foo() {}
+}
+''');
+    // The source code has an additional comment, and offsets of the
+    // elements that are declared in the source correspond to the state
+    // of the source code, not a (slightly) out of date macro-generated code.
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @16
+        documentationComment: /// shift
+        constructors
+          synthetic @-1
+        methods
+          foo @27
+            returnType: void
+          fromMacro bar @33
+            parameters
+              requiredPositional a @41
+                type: int
+            returnType: void
+''');
+  }
+
   test_main_class() async {
     var library = await checkLibrary('class main {}');
     checkElementText(library, r'''
@@ -33578,6 +33668,11 @@
 ''');
   }
 
+  void _assertMacroPath(CompilationUnitElement unitElement, String expected) {
+    unitElement as CompilationUnitElementImpl;
+    expect(unitElement.macroPath, expected);
+  }
+
   void _assertTypeStr(DartType type, String expected) {
     var typeStr = type.getDisplayString(withNullability: true);
     expect(typeStr, expected);