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