Macro. Introspection of type methods during declarations phase runs the target type macros. Change-Id: Ibaccebe04463481b9f1db2fbb68f5e513fa1c6df Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/340641 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 9e3b6b7..ccad2a7 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 = 323; + static const int DATA_VERSION = 324; /// 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/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart index 38c17e0..c4342cd 100644 --- a/pkg/analyzer/lib/src/generated/error_verifier.dart +++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -5897,6 +5897,9 @@ case ArgumentMacroDiagnostic(): // TODO(scheglov): implement throw UnimplementedError(); + case DeclarationsIntrospectionCycleDiagnostic(): + // TODO(scheglov): implement + throw UnimplementedError(); case ExceptionMacroDiagnostic(): // TODO(scheglov): implement throw UnimplementedError();
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart index 99cdf5e..9cbca0d 100644 --- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart +++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -2310,7 +2310,16 @@ argumentIndex: readUInt30(), message: _reader.readStringUtf8(), ); - case 0x02: + case 0x01: + return DeclarationsIntrospectionCycleDiagnostic( + components: readTypedList(() { + return DeclarationsIntrospectionCycleComponent( + element: readElement() as ElementImpl, + annotationIndex: readUInt30(), + ); + }), + ); + case 0x03: return MacroDiagnostic( severity: macro.Severity.values[readByte()], message: _readMacroDiagnosticMessage(),
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart index 2873254..0a148e7 100644 --- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart +++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -952,11 +952,17 @@ writeUInt30(diagnostic.annotationIndex); writeUInt30(diagnostic.argumentIndex); writeStringUtf8(diagnostic.message); + case DeclarationsIntrospectionCycleDiagnostic(): + writeByte(0x01); + writeList(diagnostic.components, (component) { + writeElement(component.element); + writeUInt30(component.annotationIndex); + }); case ExceptionMacroDiagnostic(): // TODO(scheglov): Handle this case. throw UnimplementedError(); case MacroDiagnostic(): - writeByte(0x02); + writeByte(0x03); writeByte(diagnostic.severity.index); _writeMacroDiagnosticMessage(diagnostic.message); writeList(
diff --git a/pkg/analyzer/lib/src/summary2/library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart index 54fca7e..5d227eb 100644 --- a/pkg/analyzer/lib/src/summary2/library_builder.dart +++ b/pkg/analyzer/lib/src/summary2/library_builder.dart
@@ -362,7 +362,7 @@ /// of interfaces declared in other libraries that, and we have not run yet /// declarations phase macro applications for them. Future<bool> executeMacroDeclarationsPhase({ - required OperationPerformanceImpl performance, + required Element? targetElement, }) async { final macroApplier = linker.macroApplier; if (macroApplier == null) { @@ -371,6 +371,7 @@ final results = await macroApplier.executeDeclarationsPhase( library: element, + targetElement: targetElement, ); // No more applications to execute.
diff --git a/pkg/analyzer/lib/src/summary2/link.dart b/pkg/analyzer/lib/src/summary2/link.dart index c69e296..5012771 100644 --- a/pkg/analyzer/lib/src/summary2/link.dart +++ b/pkg/analyzer/lib/src/summary2/link.dart
@@ -136,6 +136,7 @@ macroExecutor: macroExecutor, isLibraryBeingLinked: (uri) => builders.containsKey(uri), declarationBuilder: macroDeclarationBuilder, + runDeclarationsPhase: _executeMacroDeclarationsPhase, ); for (final library in builders.values) { @@ -167,7 +168,7 @@ 'executeMacroDeclarationsPhase', (performance) async { await _executeMacroDeclarationsPhase( - performance: performance, + targetElement: null, ); }, ); @@ -316,13 +317,13 @@ } Future<void> _executeMacroDeclarationsPhase({ - required OperationPerformanceImpl performance, + required Element? targetElement, }) async { while (true) { var hasProgress = false; for (final library in builders.values) { hasProgress |= await library.executeMacroDeclarationsPhase( - performance: performance, + targetElement: targetElement, ); } if (!hasProgress) {
diff --git a/pkg/analyzer/lib/src/summary2/macro_application.dart b/pkg/analyzer/lib/src/summary2/macro_application.dart index afdf869..4153d5c 100644 --- a/pkg/analyzer/lib/src/summary2/macro_application.dart +++ b/pkg/analyzer/lib/src/summary2/macro_application.dart
@@ -73,6 +73,11 @@ final bool Function(Uri) isLibraryBeingLinked; final DeclarationBuilder declarationBuilder; + /// The callback to run declarations phase if the type. + /// We do it out-of-order when the type is introspected. + final Future<void> Function({required Element? targetElement}) + runDeclarationsPhase; + /// The reversed queue of macro applications to apply. /// /// We add classes before methods, and methods in the reverse order, @@ -85,6 +90,18 @@ /// 3. source order final List<_MacroApplication> _applications = []; + /// The applications that currently run the declarations phase. + final List<_MacroApplication> _declarationsPhaseRunning = []; + + /// The identifier of the next cycle error. + int _declarationsPhaseCycleIndex = 0; + + /// Information about a found declarations phase introspection cycle. + /// We use it when receive diagnostics from the macro executor to report + /// a more specific diagnostic than the exception. + final Map<String, List<_MacroApplication>> + _declarationsPhaseCycleApplications = {}; + /// The map from [InstanceElement] to the applications associated with it. /// This includes applications on the class itself, and on the methods of /// the class. @@ -99,6 +116,7 @@ required this.macroExecutor, required this.isLibraryBeingLinked, required this.declarationBuilder, + required this.runDeclarationsPhase, }); Future<void> add({ @@ -202,23 +220,39 @@ Future<List<macro.MacroExecutionResult>?> executeDeclarationsPhase({ required LibraryElementImpl library, + required Element? targetElement, }) async { + if (targetElement != null) { + for (final running in _declarationsPhaseRunning.indexed) { + if (running.$2.target.element == targetElement) { + final id = 'DPI${_declarationsPhaseCycleIndex++}'; + _declarationsPhaseCycleApplications[id] = + _declarationsPhaseRunning.skip(running.$1).toList(); + throw StateError('[$id] Declarations phase introspection cycle.'); + } + } + } + final application = _nextForDeclarationsPhase( library: library, + targetElement: targetElement, ); if (application == null) { return null; } + _declarationsPhaseRunning.add(application); + final results = <macro.MacroExecutionResult>[]; await _runWithCatchingExceptions( () async { - final declaration = _buildDeclaration(application.targetNode); + final declaration = _buildDeclaration(application.target.node); final introspector = _DeclarationPhaseIntrospector( elementFactory, declarationBuilder, + this, library.typeSystem, ); @@ -233,10 +267,11 @@ results.add(result); } }, - targetElement: application.targetElement, + targetElement: application.target.element, annotationIndex: application.annotationIndex, ); + _declarationsPhaseRunning.remove(application); return results; } @@ -250,12 +285,13 @@ await _runWithCatchingExceptions( () async { - final declaration = _buildDeclaration(application.targetNode); + final declaration = _buildDeclaration(application.target.node); final introspector = _DefinitionPhaseIntrospector( elementFactory, declarationBuilder, - application.libraryElement.typeSystem, + this, + application.target.library.typeSystem, ); final result = await macroExecutor.executeDefinitionsPhase( @@ -269,7 +305,7 @@ results.add(result); } }, - targetElement: application.targetElement, + targetElement: application.target.element, annotationIndex: application.annotationIndex, ); @@ -286,7 +322,7 @@ await _runWithCatchingExceptions( () async { - final declaration = _buildDeclaration(application.targetNode); + final declaration = _buildDeclaration(application.target.node); final result = await macroExecutor.executeTypesPhase( application.instance, @@ -299,7 +335,7 @@ results.add(result); } }, - targetElement: application.targetElement, + targetElement: application.target.element, annotationIndex: application.annotationIndex, ); @@ -334,6 +370,13 @@ return; } + final macroTarget = _MacroTarget( + library: libraryElement, + declarationsPhaseElement: declarationsPhaseElement, + node: targetNode, + element: targetElement, + ); + for (final (annotationIndex, annotation) in annotations.indexed) { final importedMacro = _importedMacro( container: container, @@ -369,10 +412,7 @@ }).toSet(); final application = _MacroApplication( - libraryElement: libraryElement, - declarationsPhaseElement: declarationsPhaseElement, - targetNode: targetNode, - targetElement: targetElement, + target: macroTarget, annotationIndex: annotationIndex, annotationNode: annotation, instance: instance, @@ -450,8 +490,44 @@ ); } + bool addAsDeclarationsPhaseIntrospectionCycle( + macro.Diagnostic diagnostic, + ) { + final pattern = RegExp(r'\[(DPI\d+)\] '); + final match = pattern.firstMatch(diagnostic.message.message); + if (match == null) { + return false; + } + + final id = match.group(1); + final applications = _declarationsPhaseCycleApplications[id]; + if (applications == null) { + return false; + } + + final components = applications.map((application) { + return DeclarationsIntrospectionCycleComponent( + element: application.target.element, + annotationIndex: application.annotationIndex, + ); + }).toList(); + + // Report the cycle at the first element. + final firstElement = applications.first.target.element; + firstElement.addMacroDiagnostic( + DeclarationsIntrospectionCycleDiagnostic( + components: components, + ), + ); + return true; + } + for (final diagnostic in result.diagnostics) { - application.targetElement.addMacroDiagnostic( + if (addAsDeclarationsPhaseIntrospectionCycle(diagnostic)) { + continue; + } + + application.target.element.addMacroDiagnostic( MacroDiagnostic( severity: diagnostic.severity, message: convertMessage(diagnostic.message), @@ -466,28 +542,6 @@ return declarationBuilder.buildDeclaration(node); } - bool _hasInterfaceDependenciesSatisfied(_MacroApplication application) { - final dependencyElements = _interfaceDependencies( - application.declarationsPhaseElement, - ); - if (dependencyElements == null) { - return true; - } - - for (final dependencyElement in dependencyElements) { - final applications = _interfaceApplications[dependencyElement]; - if (applications != null) { - for (final dependencyApplication in applications) { - if (dependencyApplication.hasDeclarationsPhase) { - return false; - } - } - } - } - - return true; - } - /// If [annotation] references a macro, invokes the right callback. _AnnotationMacro? _importedMacro({ required LibraryOrAugmentationElementImpl container, @@ -569,58 +623,22 @@ throw UnimplementedError(); } - Set<InstanceElement>? _interfaceDependencies(InstanceElement? element) { - // TODO(scheglov): other elements - switch (element) { - case ExtensionElement(): - // TODO(scheglov): implement - throw UnimplementedError(); - case MixinElement(): - final augmented = element.augmented; - switch (augmented) { - case null: - return const {}; - default: - return [ - ...augmented.superclassConstraints.map((e) => e.element), - ...augmented.interfaces.map((e) => e.element), - ].whereNotNull().toSet(); - } - case InterfaceElement(): - final augmented = element.augmented; - switch (augmented) { - case null: - return const {}; - default: - return [ - element.supertype?.element, - ...augmented.mixins.map((e) => e.element), - ...augmented.interfaces.map((e) => e.element), - ].whereNotNull().toSet(); - } - default: - return null; - } - } - _MacroApplication? _nextForDeclarationsPhase({ required LibraryElementImpl library, + required Element? targetElement, }) { for (final application in _applications.reversed) { - if (!application.hasDeclarationsPhase) { - continue; + if (targetElement != null) { + final applicationElement = application.target.element; + if (applicationElement != targetElement && + applicationElement.enclosingElement != targetElement) { + continue; + } } - if (application.libraryElement != library) { - continue; + if (application.phasesToExecute.remove(macro.Phase.declarations)) { + return application; } - if (!_hasInterfaceDependenciesSatisfied(application)) { - continue; - } - // The application has no dependencies to run. - application.removeDeclarationsPhase(); - return application; } - return null; } @@ -794,11 +812,13 @@ class _DeclarationPhaseIntrospector extends _TypePhaseIntrospector implements macro.DeclarationPhaseIntrospector { + final LibraryMacroApplier applier; final TypeSystemImpl typeSystem; _DeclarationPhaseIntrospector( super.elementFactory, super.declarationBuilder, + this.applier, this.typeSystem, ); @@ -837,6 +857,15 @@ macro.TypeDeclaration type, ) async { final element = (type as HasElement).element; + + // TODO(scheglov): test it? + if (element != + applier._declarationsPhaseRunning.lastOrNull?.target.element) { + await applier.runDeclarationsPhase( + targetElement: element, + ); + } + if (element case InstanceElement(:final augmented?)) { return [ ...augmented.accessors.whereNot((e) => e.isSynthetic), @@ -904,6 +933,7 @@ _DefinitionPhaseIntrospector( super.elementFactory, super.declarationBuilder, + super.applier, super.typeSystem, ); @@ -940,20 +970,14 @@ } class _MacroApplication { - final LibraryElementImpl libraryElement; - final InstanceElement? declarationsPhaseElement; - final ast.AstNode targetNode; - final MacroTargetElement targetElement; + final _MacroTarget target; final int annotationIndex; final ast.Annotation annotationNode; final macro.MacroInstanceIdentifier instance; final Set<macro.Phase> phasesToExecute; _MacroApplication({ - required this.libraryElement, - required this.declarationsPhaseElement, - required this.targetNode, - required this.targetElement, + required this.target, required this.annotationIndex, required this.annotationNode, required this.instance, @@ -969,6 +993,20 @@ } } +class _MacroTarget { + final LibraryElementImpl library; + final InstanceElement? declarationsPhaseElement; + final ast.Declaration node; + final MacroTargetElement element; + + _MacroTarget({ + required this.library, + required this.declarationsPhaseElement, + required this.node, + required this.element, + }); +} + class _StaticTypeImpl implements macro.StaticType { final TypeSystemImpl typeSystem; final DartType type;
diff --git a/pkg/analyzer/lib/src/summary2/macro_application_error.dart b/pkg/analyzer/lib/src/summary2/macro_application_error.dart index e95915a..e9b98fe 100644 --- a/pkg/analyzer/lib/src/summary2/macro_application_error.dart +++ b/pkg/analyzer/lib/src/summary2/macro_application_error.dart
@@ -29,6 +29,26 @@ }); } +final class DeclarationsIntrospectionCycleComponent { + final ElementImpl element; + final int annotationIndex; + + DeclarationsIntrospectionCycleComponent({ + required this.element, + required this.annotationIndex, + }); +} + +/// A cycle during declarations phase introspection. +final class DeclarationsIntrospectionCycleDiagnostic + extends AnalyzerMacroDiagnostic { + final List<DeclarationsIntrospectionCycleComponent> components; + + DeclarationsIntrospectionCycleDiagnostic({ + required this.components, + }); +} + final class ElementMacroDiagnosticTarget extends MacroDiagnosticTarget { final ElementImpl element;
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart index 5974aab..6f1d42c 100644 --- a/pkg/analyzer/test/src/summary/element_text.dart +++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -789,6 +789,28 @@ ); _sink.writelnWithIndent('message: ${diagnostic.message}'); }); + case DeclarationsIntrospectionCycleDiagnostic(): + _sink.writelnWithIndent( + 'DeclarationsIntrospectionCycleDiagnostic', + ); + _sink.writeElements( + 'components', + diagnostic.components, + (component) { + _sink.writelnWithIndent( + 'DeclarationsIntrospectionCycleComponent', + ); + _sink.withIndent(() { + _elementPrinter.writeNamedElement( + 'element', + component.element, + ); + _sink.writelnWithIndent( + 'annotationIndex: ${component.annotationIndex}', + ); + }); + }, + ); case ExceptionMacroDiagnostic(): _sink.writelnWithIndent('ExceptionMacroDiagnostic'); _sink.withIndent(() {
diff --git a/pkg/analyzer/test/src/summary/macro/order.dart b/pkg/analyzer/test/src/summary/macro/order.dart index 86f72d0..eccd2c0 100644 --- a/pkg/analyzer/test/src/summary/macro/order.dart +++ b/pkg/analyzer/test/src/summary/macro/order.dart
@@ -62,29 +62,60 @@ } } -/*macro*/ class AddHierarchyMethod implements ClassDeclarationsMacro { +/*macro*/ class AddMethod + implements + ClassDeclarationsMacro, + MethodDeclarationsMacro, + MixinDeclarationsMacro { final String name; - const AddHierarchyMethod(this.name); + const AddMethod(this.name); @override buildDeclarationsForClass(clazz, builder) async { - // builder.typeDeclarationOf(identifier); - final methods = (await Future.wait( - clazz.interfaces.map( - (interface) async { - final type = await builder.typeDeclarationOf(interface.identifier); - return await builder.methodsOf(type); - }, - ), - )) - .expand((element) => element) - .toList(); - final methodsStr = methods.map((e) => e.identifier.name).join('_'); + _add(builder); + } - final compoundName = methodsStr.isEmpty ? name : '${methodsStr}_$name'; - final code = ' void $compoundName() {}'; + @override + buildDeclarationsForMethod(method, builder) { + _add(builder); + } + + @override + buildDeclarationsForMixin(method, builder) { + _add(builder); + } + + void _add(MemberDeclarationBuilder builder) { + final code = ' void $name() {}'; final declaration = DeclarationCode.fromString(code); builder.declareInType(declaration); } } + +/*macro*/ class DeclarationsIntrospectMethods + implements ClassDeclarationsMacro { + final String targetName; + + const DeclarationsIntrospectMethods(this.targetName); + + @override + Future<void> buildDeclarationsForClass(declaration, builder) async { + // ignore: deprecated_member_use + final identifier = await builder.resolveIdentifier( + declaration.library.uri, + targetName, + ); + final type = await builder.typeDeclarationOf(identifier); + final methods = await builder.methodsOf(type); + for (final method in methods) { + builder.declareInType( + DeclarationCode.fromString( + ' void introspected_' + '${type.identifier.name}_' + '${method.identifier.name}();', + ), + ); + } + } +}
diff --git a/pkg/analyzer/test/src/summary/macro_test.dart b/pkg/analyzer/test/src/summary/macro_test.dart index 23a0aa7..7b227ec 100644 --- a/pkg/analyzer/test/src/summary/macro_test.dart +++ b/pkg/analyzer/test/src/summary/macro_test.dart
@@ -48,18 +48,15 @@ defineReflectiveTests(MacroDefinitionTest_fromBytes); defineReflectiveTests(MacroElementsTest_keepLinking); defineReflectiveTests(MacroElementsTest_fromBytes); - defineReflectiveTests(MacroApplicationOrderTest); + defineReflectiveTests(MacroApplicationOrderTest_keepLinking); + defineReflectiveTests(MacroApplicationOrderTest_fromBytes); defineReflectiveTests(MacroCodeGenerationTest); defineReflectiveTests(MacroExampleTest); defineReflectiveTests(UpdateNodeTextExpectations); }); } -@reflectiveTest -class MacroApplicationOrderTest extends MacroElementsBaseTest { - @override - bool get keepLinkingLibraries => true; - +abstract class MacroApplicationOrderTest extends MacroElementsBaseTest { @override Future<void> setUp() async { await super.setUp(); @@ -70,745 +67,132 @@ ); } - test_declarations_class_interfaces_backward() async { + test_declarations_class_methodsOf_alreadyDone() async { var library = await buildLibrary(r''' import 'order.dart'; -@AddFunction('f31') -@AddFunction('f32') -class X3 {} - -@AddFunction('f21') -@AddFunction('f22') -class X2 {} - -@AddFunction('f11') -@AddFunction('f12') -class X1 implements X2, X3 {} -'''); - - configuration.forOrder(); - checkElementText(library, r''' -library - imports - package:test/order.dart - augmentationImports - package:test/test.macro.dart - macroGeneratedCode ---- -library augment 'test.dart'; - -void f32() {} -void f31() {} -void f22() {} -void f21() {} -void f12() {} -void f11() {} ---- -'''); - } - - test_declarations_class_interfaces_forward() async { - var library = await buildLibrary(r''' -import 'order.dart'; - -@AddFunction('f11') -@AddFunction('f12') -class X1 implements X2, X3 {} - -@AddFunction('f21') -@AddFunction('f22') -class X2 {} - -@AddFunction('f31') -@AddFunction('f32') -class X3 {} -'''); - - configuration.forOrder(); - checkElementText(library, r''' -library - imports - package:test/order.dart - augmentationImports - package:test/test.macro.dart - macroGeneratedCode ---- -library augment 'test.dart'; - -void f22() {} -void f21() {} -void f32() {} -void f31() {} -void f12() {} -void f11() {} ---- -'''); - } - - test_declarations_class_interfaces_forward2() async { - var library = await buildLibrary(r''' -import 'order.dart'; - -@AddFunction('f11') -@AddFunction('f12') -class X1 implements X3, X4 {} - -@AddFunction('f21') -@AddFunction('f22') -class X2 implements X3, X4 {} - -@AddFunction('f31') -@AddFunction('f32') -class X3 {} - -@AddFunction('f41') -@AddFunction('f42') -class X4 {} -'''); - - configuration.forOrder(); - checkElementText(library, r''' -library - imports - package:test/order.dart - augmentationImports - package:test/test.macro.dart - macroGeneratedCode ---- -library augment 'test.dart'; - -void f32() {} -void f31() {} -void f42() {} -void f41() {} -void f12() {} -void f11() {} -void f22() {} -void f21() {} ---- -'''); - } - - test_declarations_class_interfaces_forward3() async { - var library = await buildLibrary(r''' -import 'order.dart'; - -@AddFunction('f11') -@AddFunction('f12') -class X1 implements X2, X4 {} - -@AddFunction('f21') -@AddFunction('f22') -class X2 implements X3 {} - -@AddFunction('f31') -@AddFunction('f32') -class X3 {} - -@AddFunction('f41') -@AddFunction('f42') -class X4 {} -'''); - - configuration.forOrder(); - checkElementText(library, r''' -library - imports - package:test/order.dart - augmentationImports - package:test/test.macro.dart - macroGeneratedCode ---- -library augment 'test.dart'; - -void f32() {} -void f31() {} -void f22() {} -void f21() {} -void f42() {} -void f41() {} -void f12() {} -void f11() {} ---- -'''); - } - - test_declarations_class_mixins_backward() async { - var library = await buildLibrary(r''' -import 'order.dart'; - -@AddFunction('f31') -@AddFunction('f32') -mixin X3 {} - -@AddFunction('f21') -@AddFunction('f22') -mixin X2 {} - -@AddFunction('f11') -@AddFunction('f12') -class X1 with X2, X3 {} -'''); - - configuration.forOrder(); - checkElementText(library, r''' -library - imports - package:test/order.dart - augmentationImports - package:test/test.macro.dart - macroGeneratedCode ---- -library augment 'test.dart'; - -void f32() {} -void f31() {} -void f22() {} -void f21() {} -void f12() {} -void f11() {} ---- -'''); - } - - test_declarations_class_mixins_forward() async { - var library = await buildLibrary(r''' -import 'order.dart'; - -@AddFunction('f11') -@AddFunction('f12') -class X1 with X2, X3 {} - -@AddFunction('f21') -@AddFunction('f22') -mixin X2 {} - -@AddFunction('f31') -@AddFunction('f32') -mixin X3 {} -'''); - - configuration.forOrder(); - checkElementText(library, r''' -library - imports - package:test/order.dart - augmentationImports - package:test/test.macro.dart - macroGeneratedCode ---- -library augment 'test.dart'; - -void f22() {} -void f21() {} -void f32() {} -void f31() {} -void f12() {} -void f11() {} ---- -'''); - } - - test_declarations_class_superclass_backward() async { - var library = await buildLibrary(r''' -import 'order.dart'; - -@AddFunction('f3') -class X3 extends X2 { - @AddFunction('f31') - void foo() {} - - @AddFunction('f32') - void bar() {} +@AddMethod('f12') +class A1 { + void f11() {} } -@AddFunction('f2') -class X2 extends X1 { - @AddFunction('f21') - void foo() {} +@DeclarationsIntrospectMethods('A1') +class A2 {} +'''); - @AddFunction('f22') - void bar() {} + configuration.forOrder(); + _assertMacroCode(library, r''' +library augment 'test.dart'; + +augment class A1 { + void f12() {} } +augment class A2 { + void introspected_A1_f11(); + void introspected_A1_f12(); +} +'''); + } -@AddFunction('f1') -class X1 { - @AddFunction('f11') - void foo() {} + test_declarations_class_methodsOf_cycle2() async { + var library = await buildLibrary(r''' +import 'order.dart'; - @AddFunction('f12') - void bar() {} +@DeclarationsIntrospectMethods('A2') +class A1 {} + +@DeclarationsIntrospectMethods('A1') +class A2 {} +'''); + + configuration + ..withConstructors = false + ..withMetadata = false; + checkElementText(library, r''' +library + imports + package:test/order.dart + definingUnit + classes + class A1 @65 + macroDiagnostics + DeclarationsIntrospectionCycleDiagnostic + components + DeclarationsIntrospectionCycleComponent + element: self::@class::A1 + annotationIndex: 0 + DeclarationsIntrospectionCycleComponent + element: self::@class::A2 + annotationIndex: 0 + class A2 @115 +'''); + } + + test_declarations_class_methodsOf_cycle2_withHead() async { + var library = await buildLibrary(r''' +import 'order.dart'; + +@DeclarationsIntrospectMethods('A2') +class A1 {} + +@DeclarationsIntrospectMethods('A3') +class A2 {} + +@DeclarationsIntrospectMethods('A2') +class A3 {} +'''); + + configuration + ..withConstructors = false + ..withMetadata = false; + checkElementText(library, r''' +library + imports + package:test/order.dart + definingUnit + classes + class A1 @65 + class A2 @115 + macroDiagnostics + DeclarationsIntrospectionCycleDiagnostic + components + DeclarationsIntrospectionCycleComponent + element: self::@class::A2 + annotationIndex: 0 + DeclarationsIntrospectionCycleComponent + element: self::@class::A3 + annotationIndex: 0 + class A3 @165 +'''); + } + + test_declarations_class_methodsOf_notYetDone() async { + var library = await buildLibrary(r''' +import 'order.dart'; + +@DeclarationsIntrospectMethods('A2') +class A1 {} + +@AddMethod('f23') +class A2 { + @AddMethod('f22') + void f21() {} } '''); configuration.forOrder(); - checkElementText(library, r''' -library - imports - package:test/order.dart - augmentationImports - package:test/test.macro.dart - macroGeneratedCode ---- + _assertMacroCode(library, r''' library augment 'test.dart'; -void f11() {} -void f12() {} -void f1() {} -void f21() {} -void f22() {} -void f2() {} -void f31() {} -void f32() {} -void f3() {} ---- -'''); - } - - test_declarations_class_superclass_forward() async { - var library = await buildLibrary(r''' -import 'order.dart'; - -@AddFunction('f1') -class X1 { - @AddFunction('f11') - void foo() {} - - @AddFunction('f12') - void bar() {} +augment class A2 { + void f22() {} + void f23() {} } - -@AddFunction('f2') -class X2 extends X1 { - @AddFunction('f21') - void foo() {} - - @AddFunction('f22') - void bar() {} +augment class A1 { + void introspected_A2_f21(); + void introspected_A2_f22(); + void introspected_A2_f23(); } - -@AddFunction('f3') -class X3 extends X2 { - @AddFunction('f31') - void foo() {} - - @AddFunction('f32') - void bar() {} -} -'''); - - configuration.forOrder(); - checkElementText(library, r''' -library - imports - package:test/order.dart - augmentationImports - package:test/test.macro.dart - macroGeneratedCode ---- -library augment 'test.dart'; - -void f11() {} -void f12() {} -void f1() {} -void f21() {} -void f22() {} -void f2() {} -void f31() {} -void f32() {} -void f3() {} ---- -'''); - } - - test_declarations_class_superClass_mixins_interfaces_backward() async { - var library = await buildLibrary(r''' -import 'order.dart'; - -@AddFunction('f41') -@AddFunction('f42') -class X4 {} - -@AddFunction('f31') -@AddFunction('f32') -mixin X3 {} - -@AddFunction('f21') -@AddFunction('f22') -class X2 {} - -@AddFunction('f11') -@AddFunction('f12') -class X1 extends X2 with X3 implements X4 {} -'''); - - configuration.forOrder(); - checkElementText(library, r''' -library - imports - package:test/order.dart - augmentationImports - package:test/test.macro.dart - macroGeneratedCode ---- -library augment 'test.dart'; - -void f42() {} -void f41() {} -void f32() {} -void f31() {} -void f22() {} -void f21() {} -void f12() {} -void f11() {} ---- -'''); - } - - test_declarations_class_superClass_mixins_interfaces_forward() async { - var library = await buildLibrary(r''' -import 'order.dart'; - -@AddFunction('f11') -@AddFunction('f12') -class X1 extends X2 with X3 implements X4 {} - -@AddFunction('f21') -@AddFunction('f22') -class X2 {} - -@AddFunction('f31') -@AddFunction('f32') -mixin X3 {} - -@AddFunction('f41') -@AddFunction('f42') -class X4 {} -'''); - - configuration.forOrder(); - checkElementText(library, r''' -library - imports - package:test/order.dart - augmentationImports - package:test/test.macro.dart - macroGeneratedCode ---- -library augment 'test.dart'; - -void f22() {} -void f21() {} -void f32() {} -void f31() {} -void f42() {} -void f41() {} -void f12() {} -void f11() {} ---- -'''); - } - - test_declarations_libraryCycle_class_interfaces() async { - useEmptyByteStore(); - - newFile('$testPackageLibPath/x2.dart', r''' -import 'test.dart'; -import 'order.dart'; - -@AddHierarchyMethod('f211') -@AddHierarchyMethod('f212') -class X21 {} - -@AddHierarchyMethod('f221') -@AddHierarchyMethod('f222') -class X22 {} -'''); - - final testLibrary = await buildLibrary(r''' -import 'order.dart'; -import 'x2.dart'; - -@AddHierarchyMethod('f11') -@AddHierarchyMethod('f12') -class X1 implements X22 {} -'''); - - // When we process `X1`, we see macro generated methods of `X22`. - // This shows that we processed `X22` before `X1`. - configuration.forOrder(); - checkElementText(testLibrary, r''' -library - imports - package:test/order.dart - package:test/x2.dart - augmentationImports - package:test/test.macro.dart - macroGeneratedCode ---- -library augment 'test.dart'; - -augment class X1 { - void f222_f221_f12() {} - void f222_f221_f11() {} -} ---- -'''); - - // There are no dependencies between `X21` and `X22`, so they are - // processed in the source order. - // We see `f212` before `f211`, this shows that we process annotations - // from right to left. - final x2Library = await testContextLibrary('package:test/x2.dart'); - checkElementText(x2Library, r''' -library - imports - package:test/test.dart - package:test/order.dart - augmentationImports - package:test/x2.macro.dart - macroGeneratedCode ---- -library augment 'x2.dart'; - -augment class X21 { - void f212() {} - void f211() {} -} -augment class X22 { - void f222() {} - void f221() {} -} ---- -'''); - } - - test_declarations_mixin_interfaces_backward() async { - var library = await buildLibrary(r''' -import 'order.dart'; - -@AddFunction('f31') -@AddFunction('f32') -class X3 {} - -@AddFunction('f21') -@AddFunction('f22') -class X2 {} - -@AddFunction('f11') -@AddFunction('f12') -mixin X1 implements X2, X3 {} -'''); - - configuration.forOrder(); - checkElementText(library, r''' -library - imports - package:test/order.dart - augmentationImports - package:test/test.macro.dart - macroGeneratedCode ---- -library augment 'test.dart'; - -void f32() {} -void f31() {} -void f22() {} -void f21() {} -void f12() {} -void f11() {} ---- -'''); - } - - test_declarations_mixin_interfaces_forward() async { - var library = await buildLibrary(r''' -import 'order.dart'; - -@AddFunction('f11') -@AddFunction('f12') -mixin X1 implements X2, X3 {} - -@AddFunction('f21') -@AddFunction('f22') -class X2 {} - -@AddFunction('f31') -@AddFunction('f32') -class X3 {} -'''); - - configuration.forOrder(); - checkElementText(library, r''' -library - imports - package:test/order.dart - augmentationImports - package:test/test.macro.dart - macroGeneratedCode ---- -library augment 'test.dart'; - -void f22() {} -void f21() {} -void f32() {} -void f31() {} -void f12() {} -void f11() {} ---- -'''); - } - - test_declarations_mixin_superclassConstraints_backward() async { - var library = await buildLibrary(r''' -import 'order.dart'; - -@AddFunction('f31') -@AddFunction('f32') -class X3 {} - -@AddFunction('f21') -@AddFunction('f22') -class X2 {} - -@AddFunction('f11') -@AddFunction('f12') -mixin X1 on X2, X3 {} -'''); - - configuration.forOrder(); - checkElementText(library, r''' -library - imports - package:test/order.dart - augmentationImports - package:test/test.macro.dart - macroGeneratedCode ---- -library augment 'test.dart'; - -void f32() {} -void f31() {} -void f22() {} -void f21() {} -void f12() {} -void f11() {} ---- -'''); - } - - test_declarations_mixin_superclassConstraints_forward() async { - var library = await buildLibrary(r''' -import 'order.dart'; - -@AddFunction('f11') -@AddFunction('f12') -mixin X1 on X2, X3 {} - -@AddFunction('f21') -@AddFunction('f22') -class X2 {} - -@AddFunction('f31') -@AddFunction('f32') -class X3 {} -'''); - - configuration.forOrder(); - checkElementText(library, r''' -library - imports - package:test/order.dart - augmentationImports - package:test/test.macro.dart - macroGeneratedCode ---- -library augment 'test.dart'; - -void f22() {} -void f21() {} -void f32() {} -void f31() {} -void f12() {} -void f11() {} ---- -'''); - } - - test_declarations_mixin_superclassConstraints_interfaces_backward() async { - var library = await buildLibrary(r''' -import 'order.dart'; - -@AddFunction('f31') -@AddFunction('f32') -class X3 {} - -@AddFunction('f21') -@AddFunction('f22') -class X2 {} - -@AddFunction('f11') -@AddFunction('f12') -mixin X1 on X2 implements X3 {} -'''); - - configuration.forOrder(); - checkElementText(library, r''' -library - imports - package:test/order.dart - augmentationImports - package:test/test.macro.dart - macroGeneratedCode ---- -library augment 'test.dart'; - -void f32() {} -void f31() {} -void f22() {} -void f21() {} -void f12() {} -void f11() {} ---- -'''); - } - - test_declarations_mixin_superclassConstraints_interfaces_forward() async { - var library = await buildLibrary(r''' -import 'order.dart'; - -@AddFunction('f11') -@AddFunction('f12') -mixin X1 on X2 implements X3 {} - -@AddFunction('f21') -@AddFunction('f22') -class X2 {} - -@AddFunction('f31') -@AddFunction('f32') -class X3 {} -'''); - - configuration.forOrder(); - checkElementText(library, r''' -library - imports - package:test/order.dart - augmentationImports - package:test/test.macro.dart - macroGeneratedCode ---- -library augment 'test.dart'; - -void f22() {} -void f21() {} -void f32() {} -void f31() {} -void f12() {} -void f11() {} ---- '''); } @@ -1120,6 +504,18 @@ } @reflectiveTest +class MacroApplicationOrderTest_fromBytes extends MacroApplicationOrderTest { + @override + bool get keepLinkingLibraries => false; +} + +@reflectiveTest +class MacroApplicationOrderTest_keepLinking extends MacroApplicationOrderTest { + @override + bool get keepLinkingLibraries => true; +} + +@reflectiveTest class MacroArgumentsTest extends MacroElementsBaseTest { @override bool get keepLinkingLibraries => true;