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;