[cfe] Support extension types in macro introspection

Change-Id: I946ba3461ca2ff897cf4c1071b3aa356bf835535
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/368102
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
diff --git a/pkg/_fe_analyzer_shared/analysis_options_no_lints.yaml b/pkg/_fe_analyzer_shared/analysis_options_no_lints.yaml
index 8aede22..dcb9ebb 100644
--- a/pkg/_fe_analyzer_shared/analysis_options_no_lints.yaml
+++ b/pkg/_fe_analyzer_shared/analysis_options_no_lints.yaml
@@ -20,4 +20,3 @@
     - test/inference/inferred_type_arguments/data/**
     - test/inference/inferred_variable_types/data/**
     - test/inheritance/data/**
-    - test/macros/api/**
diff --git a/pkg/_fe_analyzer_shared/test/macros/api/api_test_data.dart b/pkg/_fe_analyzer_shared/test/macros/api/api_test_data.dart
index 1508116..79600f2 100644
--- a/pkg/_fe_analyzer_shared/test/macros/api/api_test_data.dart
+++ b/pkg/_fe_analyzer_shared/test/macros/api/api_test_data.dart
@@ -47,13 +47,25 @@
 class Class4 extends Class1 with Mixin1 {}
 
 @ClassMacro()
-class Class5 extends Class2
+abstract class Class5 extends Class2
     with Mixin1, Mixin2
     implements Interface1, Interface2 {}
 
+@MixinMacro()
 mixin Mixin1 {}
 
-mixin Mixin2 {}
+@MixinMacro()
+mixin Mixin2 {
+  var instanceField;
+  static var staticField;
+  get instanceGetter => 42;
+  set instanceSetter(int value) {}
+  static get staticGetter => 42;
+  static set staticSetter(int value) {}
+  instanceMethod() {}
+  abstractMethod();
+  static staticMethod() {}
+}
 
 @ClassMacro()
 abstract class Interface1 {}
@@ -66,3 +78,17 @@
 
 @FunctionMacro()
 external Class2 topLevelFunction2(Class1 a, [Class2? b]);
+
+@ExtensionTypeMacro()
+extension type ExtensionType1(int i) {
+  ExtensionType1.constructor(this.i);
+  factory ExtensionType1.fact(int i) => ExtensionType1(i);
+  factory ExtensionType1.redirect(int i) = ExtensionType1.constructor;
+  static var staticField;
+  get instanceGetter => 42;
+  set instanceSetter(int value) {}
+  static get staticGetter => 42;
+  static set staticSetter(int value) {}
+  instanceMethod() {}
+  static staticMethod() {}
+}
diff --git a/pkg/_fe_analyzer_shared/test/macros/api/api_test_expectations.dart b/pkg/_fe_analyzer_shared/test/macros/api/api_test_expectations.dart
index 209ea7d..0acf91c 100644
--- a/pkg/_fe_analyzer_shared/test/macros/api/api_test_expectations.dart
+++ b/pkg/_fe_analyzer_shared/test/macros/api/api_test_expectations.dart
@@ -41,12 +41,62 @@
   'Class5': ClassData(
       superclass: 'Class2',
       superSuperclass: 'Object',
+      isAbstract: true,
       mixins: ['Mixin1', 'Mixin2'],
       interfaces: ['Interface1', 'Interface2']),
   'Interface1': ClassData(isAbstract: true),
   'Interface2': ClassData(isAbstract: true),
 };
 
+const Map<String, MixinData> expectedMixinData = {
+  'Mixin1': MixinData(),
+  'Mixin2': MixinData(
+    // TODO(johnniwinther): Should we require a specific order?
+    fieldsOf: [
+      'instanceField',
+      'staticField',
+    ],
+    // TODO(johnniwinther): Should we require a specific order?
+    methodsOf: [
+      'instanceGetter',
+      'staticGetter',
+      'instanceMethod',
+      'abstractMethod',
+      'staticMethod',
+      'instanceSetter',
+      'staticSetter',
+    ],
+  ),
+};
+
+const Map<String, ExtensionTypeData> expectedExtensionTypeData = {
+  'ExtensionType1': ExtensionTypeData(
+    representationType: NamedTypeData(name: 'int'),
+    // TODO(johnniwinther): Should we require a specific order?
+    fieldsOf: [
+      'i',
+      'staticField',
+    ],
+    // TODO(johnniwinther): Should we require a specific order?
+    methodsOf: [
+      'instanceGetter',
+      'staticGetter',
+      'instanceMethod',
+      'staticMethod',
+      'instanceSetter',
+      'staticSetter',
+    ],
+    // TODO(johnniwinther): Should we require a specific order?
+    constructorsOf: [
+      // TODO(johnniwinther): Should we normalize no-name constructor names?
+      '',
+      'constructor',
+      'fact',
+      'redirect',
+    ],
+  ),
+};
+
 const Map<String, FunctionData> expectedFunctionData = {
   'topLevelFunction1': FunctionData(
       returnType: NamedTypeData(name: 'void'),
@@ -187,7 +237,105 @@
             '$name.constructorsOf[$i]');
       }
     }
-    // TODO(johnniwinther): Test more properties when there are supported.
+    // TODO(johnniwinther): Test more properties when they are supported.
+  } else {
+    throw 'Unexpected class declaration "${name}"';
+  }
+}
+
+Future<void> checkMixinDeclaration(MixinDeclaration declaration,
+    {DeclarationPhaseIntrospector? introspector}) async {
+  String name = declaration.identifier.name;
+  MixinData? expected = expectedMixinData[name];
+  if (expected != null) {
+    expect(expected.hasBase, declaration.hasBase, '$name.hasBase');
+    if (introspector != null) {
+      List<TypeDeclaration> superClassConstraints = [
+        for (NamedTypeAnnotation superclassConstraint
+            in declaration.superclassConstraints)
+          await introspector.typeDeclarationOf(superclassConstraint.identifier),
+      ];
+      expect(expected.superclassConstraints.length,
+          superClassConstraints.length, '$name.superClassConstraints.length');
+      for (int i = 0; i < superClassConstraints.length; i++) {
+        expect(
+            expected.superclassConstraints[i],
+            superClassConstraints[i].identifier.name,
+            '$name.superClassConstraints[$i]');
+      }
+
+      List<TypeDeclaration> interfaces = [
+        for (NamedTypeAnnotation interface in declaration.interfaces)
+          await introspector.typeDeclarationOf(interface.identifier),
+      ];
+      expect(expected.interfaces.length, interfaces.length,
+          '$name.interfaces.length');
+      for (int i = 0; i < interfaces.length; i++) {
+        expect(expected.interfaces[i], interfaces[i].identifier.name,
+            '$name.interfaces[$i]');
+      }
+    }
+    if (introspector != null) {
+      List<FieldDeclaration> fieldsOf =
+          await introspector.fieldsOf(declaration);
+      expect(
+          expected.fieldsOf.length, fieldsOf.length, '$name.fieldsOf.length');
+      for (int i = 0; i < fieldsOf.length; i++) {
+        expect(expected.fieldsOf[i], fieldsOf[i].identifier.name,
+            '$name.fieldsOf[$i]');
+      }
+
+      List<MethodDeclaration> methodsOf =
+          await introspector.methodsOf(declaration);
+      expect(expected.methodsOf.length, methodsOf.length,
+          '$name.methodsOf.length');
+      for (int i = 0; i < methodsOf.length; i++) {
+        expect(expected.methodsOf[i], methodsOf[i].identifier.name,
+            '$name.methodsOf[$i]');
+      }
+    }
+    // TODO(johnniwinther): Test more properties when they are supported.
+  } else {
+    throw 'Unexpected mixin declaration "${name}"';
+  }
+}
+
+Future<void> checkExtensionTypeDeclaration(ExtensionTypeDeclaration declaration,
+    {DeclarationPhaseIntrospector? introspector}) async {
+  String name = declaration.identifier.name;
+  ExtensionTypeData? expected = expectedExtensionTypeData[name];
+  if (expected != null) {
+    checkTypeAnnotation(expected.representationType,
+        declaration.representationType, '$name.representationType');
+    if (introspector != null) {
+      List<FieldDeclaration> fieldsOf =
+          await introspector.fieldsOf(declaration);
+      expect(
+          expected.fieldsOf.length, fieldsOf.length, '$name.fieldsOf.length');
+      for (int i = 0; i < fieldsOf.length; i++) {
+        expect(expected.fieldsOf[i], fieldsOf[i].identifier.name,
+            '$name.fieldsOf[$i]');
+      }
+
+      List<MethodDeclaration> methodsOf =
+          await introspector.methodsOf(declaration);
+      expect(expected.methodsOf.length, methodsOf.length,
+          '$name.methodsOf.length');
+      for (int i = 0; i < methodsOf.length; i++) {
+        expect(expected.methodsOf[i], methodsOf[i].identifier.name,
+            '$name.methodsOf[$i]');
+      }
+
+      List<ConstructorDeclaration> constructorsOf =
+          await introspector.constructorsOf(declaration);
+      expect(expected.constructorsOf.length, constructorsOf.length,
+          '$name.constructorsOf.length');
+      for (int i = 0; i < constructorsOf.length; i++) {
+        expect(expected.constructorsOf[i], constructorsOf[i].identifier.name,
+            '$name.constructorsOf[$i]');
+      }
+    }
+    // TODO(johnniwinther): Test more properties when they are supported.
   } else {
     throw 'Unexpected class declaration "${name}"';
   }
@@ -232,9 +380,11 @@
   Future<void> check(Uri uri, String name, {bool expectThrows = false}) async {
     if (expectThrows) {
       await throws(() async {
+        // ignore: deprecated_member_use
         await introspector.resolveIdentifier(uri, name);
       }, '$name from $uri');
     } else {
+      // ignore: deprecated_member_use
       Identifier result = await introspector.resolveIdentifier(uri, name);
       expect(name, result.name, '$name from $uri');
     }
@@ -265,7 +415,8 @@
         await introspector.typeDeclarationOf(identifier);
       }, '$name from $identifier',
           expectedError: (e) => e is! MacroImplementationException
-              ? 'Expected MacroImplementationException, got ${e.runtimeType}: $e'
+              ? 'Expected MacroImplementationException, got ${e.runtimeType}: '
+                  '$e'
               : null);
     } else {
       TypeDeclaration result = await introspector.typeDeclarationOf(identifier);
@@ -302,6 +453,34 @@
       this.constructorsOf = const []});
 }
 
+class MixinData {
+  final bool hasBase;
+  final List<String> interfaces;
+  final List<String> superclassConstraints;
+  final List<String> fieldsOf;
+  final List<String> methodsOf;
+
+  const MixinData(
+      {this.hasBase = false,
+      this.interfaces = const [],
+      this.superclassConstraints = const [],
+      this.fieldsOf = const [],
+      this.methodsOf = const []});
+}
+
+class ExtensionTypeData {
+  final TypeData representationType;
+  final List<String> fieldsOf;
+  final List<String> methodsOf;
+  final List<String> constructorsOf;
+
+  const ExtensionTypeData(
+      {required this.representationType,
+      this.fieldsOf = const [],
+      this.methodsOf = const [],
+      this.constructorsOf = const []});
+}
+
 class FunctionData {
   final bool isAbstract;
   final bool isExternal;
@@ -333,8 +512,7 @@
   final String? name;
   final List<TypeData>? typeArguments;
 
-  const NamedTypeData({bool isNullable = false, this.name, this.typeArguments})
-      : super(isNullable: isNullable);
+  const NamedTypeData({super.isNullable, this.name, this.typeArguments});
 }
 
 class ParameterData {
diff --git a/pkg/_fe_analyzer_shared/test/macros/api/api_test_macro.dart b/pkg/_fe_analyzer_shared/test/macros/api/api_test_macro.dart
index fa20e54..c05a9f0 100644
--- a/pkg/_fe_analyzer_shared/test/macros/api/api_test_macro.dart
+++ b/pkg/_fe_analyzer_shared/test/macros/api/api_test_macro.dart
@@ -2,29 +2,32 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// ignore_for_file: experiment_not_enabled
+
 import 'dart:async';
 import 'package:macros/macros.dart';
 import 'api_test_expectations.dart';
 
-macro
-
-class ClassMacro
+macro class ClassMacro
     implements ClassTypesMacro, ClassDeclarationsMacro, ClassDefinitionMacro {
   const ClassMacro();
 
+  @override
   FutureOr<void> buildTypesForClass(ClassDeclaration clazz,
       TypeBuilder builder) async {
     await checkClassDeclaration(clazz);
   }
 
-  FutureOr<void> buildDeclarationsForClass(
-      ClassDeclaration clazz, MemberDeclarationBuilder builder) async {
+  @override
+  FutureOr<void> buildDeclarationsForClass(ClassDeclaration clazz,
+      MemberDeclarationBuilder builder) async {
     await checkClassDeclaration(
-      clazz, introspector: builder);
+        clazz, introspector: builder);
   }
 
-  FutureOr<void> buildDefinitionForClass(
-      ClassDeclaration clazz, TypeDefinitionBuilder builder) async {
+  @override
+  FutureOr<void> buildDefinitionForClass(ClassDeclaration clazz,
+      TypeDefinitionBuilder builder) async {
     await checkClassDeclaration(clazz, introspector: builder);
     await checkIdentifierResolver(builder);
     await checkTypeDeclarationResolver(builder,
@@ -32,27 +35,88 @@
   }
 }
 
-macro
+macro class MixinMacro
+    implements MixinTypesMacro, MixinDeclarationsMacro, MixinDefinitionMacro {
+  const MixinMacro();
 
-class FunctionMacro
+  @override
+  FutureOr<void> buildTypesForMixin(MixinDeclaration mixin,
+      MixinTypeBuilder builder) async {
+    await checkMixinDeclaration(mixin);
+  }
+
+  @override
+  FutureOr<void> buildDeclarationsForMixin(MixinDeclaration mixin,
+      MemberDeclarationBuilder builder) async {
+    await checkMixinDeclaration(
+        mixin, introspector: builder);
+  }
+
+  @override
+  FutureOr<void> buildDefinitionForMixin(MixinDeclaration mixin,
+      TypeDefinitionBuilder builder) async {
+    await checkMixinDeclaration(mixin, introspector: builder);
+    await checkIdentifierResolver(builder);
+    await checkTypeDeclarationResolver(builder,
+        {mixin.identifier: mixin.identifier.name});
+  }
+}
+
+macro class ExtensionTypeMacro
+    implements
+        ExtensionTypeTypesMacro,
+        ExtensionTypeDeclarationsMacro,
+        ExtensionTypeDefinitionMacro {
+  const ExtensionTypeMacro();
+
+  @override
+  FutureOr<void> buildTypesForExtensionType(
+      ExtensionTypeDeclaration extensionType,
+      TypeBuilder builder) async {
+    await checkExtensionTypeDeclaration(extensionType);
+  }
+
+  @override
+  FutureOr<void> buildDeclarationsForExtensionType(
+      ExtensionTypeDeclaration extensionType,
+      MemberDeclarationBuilder builder) async {
+    await checkExtensionTypeDeclaration(
+        extensionType, introspector: builder);
+  }
+
+  @override
+  FutureOr<void> buildDefinitionForExtensionType(
+      ExtensionTypeDeclaration extensionType,
+      TypeDefinitionBuilder builder) async {
+    await checkExtensionTypeDeclaration(extensionType, introspector: builder);
+    await checkIdentifierResolver(builder);
+    await checkTypeDeclarationResolver(builder,
+        {extensionType.identifier: extensionType.identifier.name});
+  }
+}
+
+macro class FunctionMacro
     implements
         FunctionTypesMacro,
         FunctionDeclarationsMacro,
         FunctionDefinitionMacro {
   const FunctionMacro();
 
+  @override
   FutureOr<void> buildTypesForFunction(FunctionDeclaration function,
       TypeBuilder builder) async {
     checkFunctionDeclaration(function);
     await checkIdentifierResolver(builder);
   }
 
+  @override
   FutureOr<void> buildDeclarationsForFunction(FunctionDeclaration function,
       DeclarationBuilder builder) async {
     checkFunctionDeclaration(function);
     await checkIdentifierResolver(builder);
   }
 
+  @override
   FutureOr<void> buildDefinitionForFunction(FunctionDeclaration function,
       FunctionDefinitionBuilder builder) async {
     checkFunctionDeclaration(function);
diff --git a/pkg/front_end/lib/src/fasta/builder/augmentation_iterator.dart b/pkg/front_end/lib/src/fasta/builder/augmentation_iterator.dart
new file mode 100644
index 0000000..2389b44
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/augmentation_iterator.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2024, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Iterator for iterating through an origin and all its augmentations.
+class AugmentationIterator<T> implements Iterator<T> {
+  final T _origin;
+  final List<T>? _augmentations;
+  Iterator<T>? _augmentationsIterator;
+  T? _current;
+
+  AugmentationIterator(this._origin, this._augmentations);
+
+  @override
+  T get current =>
+      _augmentationsIterator?.current ??
+      _current ??
+      (throw new StateError('No element'));
+
+  @override
+  bool moveNext() {
+    if (_augmentationsIterator == null) {
+      if (_current == null) {
+        _current = _origin;
+        return true;
+      }
+      _augmentationsIterator =
+          _augmentations?.iterator ?? const Iterable<Never>.empty().iterator;
+    }
+    return _augmentationsIterator!.moveNext();
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index a36d3fd..a3a7529 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -382,13 +382,17 @@
     loader.resolveConstructors(augmentationLibraries);
   }
 
-  Future<void> _applyMacroPhase2(MacroApplications macroApplications,
-      List<SourceClassBuilder> sortedSourceClassBuilders) async {
+  Future<void> _applyMacroPhase2(
+      MacroApplications macroApplications,
+      List<SourceClassBuilder> sortedSourceClassBuilders,
+      List<SourceExtensionTypeDeclarationBuilder>
+          sortedSourceExtensionTypeBuilders) async {
     benchmarker?.enterPhase(BenchmarkPhases.outline_applyDeclarationMacros);
     macroApplications.enterDeclarationsMacroPhase(loader.hierarchyBuilder);
 
     Future<void> applyDeclarationMacros() async {
-      await macroApplications.applyDeclarationsMacros(sortedSourceClassBuilders,
+      await macroApplications.applyDeclarationsMacros(
+          sortedSourceClassBuilders, sortedSourceExtensionTypeBuilders,
           (SourceLibraryBuilder augmentationLibrary) async {
         List<SourceLibraryBuilder> augmentationLibraries = [
           augmentationLibrary
@@ -503,7 +507,8 @@
           underscoreEnumClass);
 
       if (macroApplications != null) {
-        await _applyMacroPhase2(macroApplications, sortedSourceClassBuilders);
+        await _applyMacroPhase2(macroApplications, sortedSourceClassBuilders,
+            sortedSourceExtensionTypeBuilders);
       }
 
       benchmarker
diff --git a/pkg/front_end/lib/src/fasta/kernel/macro/identifiers.dart b/pkg/front_end/lib/src/fasta/kernel/macro/identifiers.dart
index 169b4e5..e63aaca 100644
--- a/pkg/front_end/lib/src/fasta/kernel/macro/identifiers.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/macro/identifiers.dart
@@ -40,14 +40,14 @@
           uri = typeDeclarationBuilder.libraryBuilder.origin.importUri;
         case TypeAliasBuilder():
           uri = typeDeclarationBuilder.libraryBuilder.origin.importUri;
+        case ExtensionTypeDeclarationBuilder():
+          uri = typeDeclarationBuilder.libraryBuilder.origin.importUri;
         case NominalVariableBuilder():
         // TODO(johnniwinther): Handle this case.
         case StructuralVariableBuilder():
         // TODO(johnniwinther): Handle this case.
         case ExtensionBuilder():
         // TODO(johnniwinther): Handle this case.
-        case ExtensionTypeDeclarationBuilder():
-        // TODO(johnniwinther): Handle this case.
         case InvalidTypeDeclarationBuilder():
         case BuiltinTypeDeclarationBuilder():
           if (name == 'dynamic') {
@@ -72,13 +72,15 @@
     switch (typeDeclarationBuilder) {
       case ClassBuilder():
         return macroIntrospection.getClassDeclaration(typeDeclarationBuilder);
+      case ExtensionTypeDeclarationBuilder():
+        return macroIntrospection
+            .getExtensionTypeDeclaration(typeDeclarationBuilder);
       case TypeAliasBuilder():
         return macroIntrospection
             .getTypeAliasDeclaration(typeDeclarationBuilder);
       case NominalVariableBuilder():
       case StructuralVariableBuilder():
       case ExtensionBuilder():
-      case ExtensionTypeDeclarationBuilder():
       case InvalidTypeDeclarationBuilder():
       case BuiltinTypeDeclarationBuilder():
       // TODO(johnniwinther): How should we handle this case?
diff --git a/pkg/front_end/lib/src/fasta/kernel/macro/introspectors.dart b/pkg/front_end/lib/src/fasta/kernel/macro/introspectors.dart
index 1808b2e..ec50958 100644
--- a/pkg/front_end/lib/src/fasta/kernel/macro/introspectors.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/macro/introspectors.dart
@@ -36,6 +36,10 @@
 
   Map<ClassBuilder, macro.ParameterizedTypeDeclaration> _classDeclarations = {};
   Map<macro.ParameterizedTypeDeclaration, ClassBuilder> _classBuilders = {};
+  Map<ExtensionTypeDeclarationBuilder, macro.ParameterizedTypeDeclaration>
+      _extensionTypeDeclarations = {};
+  Map<macro.ExtensionTypeDeclaration, ExtensionTypeDeclarationBuilder>
+      _extensionTypeBuilders = {};
   Map<NominalVariableBuilder, macro.TypeParameterDeclarationImpl>
       _typeParameters = {};
   Map<TypeAliasBuilder, macro.TypeAliasDeclaration> _typeAliasDeclarations = {};
@@ -65,6 +69,8 @@
     _libraries.clear();
     _classDeclarations.clear();
     _classBuilders.clear();
+    _extensionTypeDeclarations.clear();
+    _extensionTypeBuilders.clear();
     _memberDeclarations.clear();
     _typeAliasDeclarations.clear();
     _declarationOffsets.clear();
@@ -89,6 +95,14 @@
     return _classDeclarations[builder] ??= _createClassDeclaration(builder);
   }
 
+  /// Returns the [macro.ParameterizedTypeDeclaration] corresponding to
+  /// [builder].
+  macro.ParameterizedTypeDeclaration getExtensionTypeDeclaration(
+      ExtensionTypeDeclarationBuilder builder) {
+    return _extensionTypeDeclarations[builder] ??=
+        _createExtensionTypeDeclaration(builder);
+  }
+
   /// Returns the [macro.TypeAliasDeclaration] corresponding to [builder].
   macro.TypeAliasDeclaration getTypeAliasDeclaration(TypeAliasBuilder builder) {
     return _typeAliasDeclarations[builder] ??=
@@ -101,6 +115,13 @@
     return _classBuilders[declaration]!;
   }
 
+  /// Returns the [ExtensionTypeDeclarationBuilder] corresponding to
+  /// [declaration].
+  ExtensionTypeDeclarationBuilder _getExtensionTypeDeclarationBuilder(
+      macro.ExtensionTypeDeclaration declaration) {
+    return _extensionTypeBuilders[declaration]!;
+  }
+
   /// Creates the [macro.Declaration] corresponding to [memberBuilder].
   macro.Declaration _createMemberDeclaration(MemberBuilder memberBuilder) {
     if (memberBuilder is SourceProcedureBuilder) {
@@ -266,6 +287,31 @@
     return declaration;
   }
 
+  macro.ExtensionTypeDeclaration _createExtensionTypeDeclaration(
+      ExtensionTypeDeclarationBuilder builder) {
+    final macro.LibraryImpl library = getLibrary(builder.libraryBuilder);
+    List<macro.TypeParameterDeclarationImpl> typeParameters =
+        _nominalVariableBuildersToDeclarations(
+            builder.libraryBuilder, builder.typeParameters);
+    macro.ExtensionTypeDeclarationImpl declaration =
+        new macro.ExtensionTypeDeclarationImpl(
+      id: macro.RemoteInstance.uniqueId,
+      identifier: new TypeDeclarationBuilderIdentifier(
+          typeDeclarationBuilder: builder,
+          libraryBuilder: builder.libraryBuilder,
+          id: macro.RemoteInstance.uniqueId,
+          name: builder.name),
+      library: library,
+      // TODO: Provide metadata annotations.
+      metadata: const [],
+      typeParameters: typeParameters,
+      representationType: types.getTypeAnnotation(
+          builder.libraryBuilder, builder.declaredRepresentationTypeBuilder),
+    );
+    _extensionTypeBuilders[declaration] = builder;
+    return declaration;
+  }
+
   /// Creates the [macro.TypeAliasDeclaration] corresponding to [builder].
   macro.TypeAliasDeclaration _createTypeAliasDeclaration(
       TypeAliasBuilder builder) {
@@ -360,8 +406,15 @@
       List<macro.FormalParameterDeclarationImpl> positionalParameters,
       List<macro.FormalParameterDeclarationImpl> namedParameters
     ) = _createParameters(builder.libraryBuilder, formals);
-    macro.ParameterizedTypeDeclaration definingClass =
-        getClassDeclaration(builder.classBuilder!);
+    macro.ParameterizedTypeDeclaration definingTypeDeclaration;
+    Builder? parent = builder.parent;
+    if (parent is ClassBuilder) {
+      definingTypeDeclaration = getClassDeclaration(parent);
+    } else if (parent is ExtensionTypeDeclarationBuilder) {
+      definingTypeDeclaration = getExtensionTypeDeclaration(parent);
+    } else {
+      throw new UnsupportedError("Unexpected parent of constructor: $parent");
+    }
     macro.ConstructorDeclaration declaration =
         new macro.ConstructorDeclarationImpl(
       id: macro.RemoteInstance.uniqueId,
@@ -372,7 +425,7 @@
       library: getLibrary(builder.libraryBuilder),
       // TODO: Provide metadata annotations.
       metadata: const [],
-      definingType: definingClass.identifier as macro.IdentifierImpl,
+      definingType: definingTypeDeclaration.identifier as macro.IdentifierImpl,
       isFactory: builder.isFactory,
       // TODO(johnniwinther): Real implementation of hasBody.
       hasBody: true,
@@ -398,10 +451,15 @@
       List<macro.FormalParameterDeclarationImpl> positionalParameters,
       List<macro.FormalParameterDeclarationImpl> namedParameters
     ) = _createParameters(builder.libraryBuilder, builder.formals);
-    macro.ParameterizedTypeDeclaration definingClass =
-        // TODO(johnniwinther): Support extension type factories.
-        getClassDeclaration(builder.classBuilder!);
-
+    macro.ParameterizedTypeDeclaration definingTypeDeclaration;
+    Builder? parent = builder.parent;
+    if (parent is ClassBuilder) {
+      definingTypeDeclaration = getClassDeclaration(parent);
+    } else if (parent is ExtensionTypeDeclarationBuilder) {
+      definingTypeDeclaration = getExtensionTypeDeclaration(parent);
+    } else {
+      throw new UnsupportedError("Unexpected parent of constructor: $parent");
+    }
     macro.ConstructorDeclaration declaration =
         new macro.ConstructorDeclarationImpl(
       id: macro.RemoteInstance.uniqueId,
@@ -412,7 +470,7 @@
       library: getLibrary(builder.libraryBuilder),
       // TODO: Provide metadata annotations.
       metadata: const [],
-      definingType: definingClass.identifier as macro.IdentifierImpl,
+      definingType: definingTypeDeclaration.identifier as macro.IdentifierImpl,
       isFactory: builder.isFactory,
       // TODO(johnniwinther): Real implementation of hasBody.
       hasBody: true,
@@ -437,13 +495,16 @@
       List<macro.FormalParameterDeclarationImpl> namedParameters
     ) = _createParameters(builder.libraryBuilder, builder.formals);
 
-    macro.ParameterizedTypeDeclaration? definingClass = null;
-    if (builder.classBuilder != null) {
-      definingClass = getClassDeclaration(builder.classBuilder!);
+    macro.ParameterizedTypeDeclaration? definingTypeDeclaration = null;
+    Builder? parent = builder.parent;
+    if (parent is ClassBuilder) {
+      definingTypeDeclaration = getClassDeclaration(parent);
+    } else if (parent is ExtensionTypeDeclarationBuilder) {
+      definingTypeDeclaration = getExtensionTypeDeclaration(parent);
     }
     final macro.LibraryImpl library = getLibrary(builder.libraryBuilder);
     macro.FunctionDeclaration declaration;
-    if (definingClass != null) {
+    if (definingTypeDeclaration != null) {
       // TODO(johnniwinther): Should static fields be field or variable
       //  declarations?
       declaration = new macro.MethodDeclarationImpl(
@@ -455,7 +516,8 @@
           library: library,
           // TODO(johnniwinther): Provide metadata annotations.
           metadata: const [],
-          definingType: definingClass.identifier as macro.IdentifierImpl,
+          definingType:
+              definingTypeDeclaration.identifier as macro.IdentifierImpl,
           // TODO(johnniwinther): Real implementation of hasBody.
           hasBody: true,
           hasExternal: builder.isExternal,
@@ -500,13 +562,16 @@
   /// Creates the [macro.VariableDeclaration] corresponding to [builder].
   macro.VariableDeclaration _createVariableDeclaration(
       SourceFieldBuilder builder) {
-    macro.ParameterizedTypeDeclaration? definingClass = null;
-    if (builder.classBuilder != null) {
-      definingClass = getClassDeclaration(builder.classBuilder!);
+    macro.ParameterizedTypeDeclaration? definingTypeDeclaration = null;
+    Builder? parent = builder.parent;
+    if (parent is ClassBuilder) {
+      definingTypeDeclaration = getClassDeclaration(parent);
+    } else if (parent is ExtensionTypeDeclarationBuilder) {
+      definingTypeDeclaration = getExtensionTypeDeclaration(parent);
     }
     final macro.LibraryImpl library = getLibrary(builder.libraryBuilder);
     macro.VariableDeclaration declaration;
-    if (definingClass != null) {
+    if (definingTypeDeclaration != null) {
       // TODO(johnniwinther): Should static fields be field or variable
       //  declarations?
       declaration = new macro.FieldDeclarationImpl(
@@ -518,7 +583,8 @@
           library: library,
           // TODO: Provide metadata annotations.
           metadata: const [],
-          definingType: definingClass.identifier as macro.IdentifierImpl,
+          definingType:
+              definingTypeDeclaration.identifier as macro.IdentifierImpl,
           hasAbstract: builder.isAbstract,
           hasConst: builder.isConst,
           hasExternal: builder.isExternal,
@@ -666,23 +732,40 @@
   @override
   Future<List<macro.ConstructorDeclaration>> constructorsOf(
       macro.TypeDeclaration type) {
-    if (type is! macro.ClassDeclaration) {
-      throw new UnsupportedError('Only introspection on classes is supported');
-    }
-    ClassBuilder classBuilder = _introspection
-        ._getClassBuilder(type as macro.ParameterizedTypeDeclaration);
+    // TODO(johnniwinther): Create all member declarations together so that
+    // can assert that all are handled.
     List<macro.ConstructorDeclaration> result = [];
-    Iterator<MemberBuilder> iterator = classBuilder.fullConstructorIterator();
-    while (iterator.moveNext()) {
-      MemberBuilder memberBuilder = iterator.current;
-      if (memberBuilder is DeclaredSourceConstructorBuilder) {
-        // TODO(johnniwinther): Should we support synthesized constructors?
-        result.add(_introspection.getMemberDeclaration(memberBuilder)
-            as macro.ConstructorDeclaration);
-      } else if (memberBuilder is SourceFactoryBuilder) {
-        result.add(_introspection.getMemberDeclaration(memberBuilder)
-            as macro.ConstructorDeclaration);
+    if (type is macro.ClassDeclaration) {
+      ClassBuilder classBuilder = _introspection._getClassBuilder(type);
+      Iterator<MemberBuilder> iterator = classBuilder.fullConstructorIterator();
+      while (iterator.moveNext()) {
+        MemberBuilder memberBuilder = iterator.current;
+        if (memberBuilder is DeclaredSourceConstructorBuilder) {
+          // TODO(johnniwinther): Should we support synthesized constructors?
+          result.add(_introspection.getMemberDeclaration(memberBuilder)
+              as macro.ConstructorDeclaration);
+        } else if (memberBuilder is SourceFactoryBuilder) {
+          result.add(_introspection.getMemberDeclaration(memberBuilder)
+              as macro.ConstructorDeclaration);
+        }
       }
+    } else if (type is macro.ExtensionTypeDeclaration) {
+      ExtensionTypeDeclarationBuilder extensionTypeDeclarationBuilder =
+          _introspection._getExtensionTypeDeclarationBuilder(type);
+      Iterator<MemberBuilder> iterator =
+          extensionTypeDeclarationBuilder.fullConstructorIterator();
+      while (iterator.moveNext()) {
+        MemberBuilder memberBuilder = iterator.current;
+        if (memberBuilder is SourceExtensionTypeConstructorBuilder) {
+          result.add(_introspection.getMemberDeclaration(memberBuilder)
+              as macro.ConstructorDeclaration);
+        } else if (memberBuilder is SourceFactoryBuilder) {
+          result.add(_introspection.getMemberDeclaration(memberBuilder)
+              as macro.ConstructorDeclaration);
+        }
+      }
+    } else {
+      throw new UnsupportedError('Only introspection on classes is supported');
     }
     return new Future.value(result);
   }
@@ -696,35 +779,57 @@
 
   @override
   Future<List<macro.FieldDeclaration>> fieldsOf(macro.TypeDeclaration type) {
-    if (type is! macro.ClassDeclaration) {
-      throw new UnsupportedError('Only introspection on classes is supported');
-    }
-    ClassBuilder classBuilder = _introspection._getClassBuilder(type);
     List<macro.FieldDeclaration> result = [];
-    Iterator<SourceFieldBuilder> iterator =
-        classBuilder.fullMemberIterator<SourceFieldBuilder>();
-    while (iterator.moveNext()) {
-      result.add(_introspection.getMemberDeclaration(iterator.current)
-          as macro.FieldDeclaration);
+    if (type is macro.ClassDeclaration || type is macro.MixinDeclaration) {
+      ClassBuilder classBuilder = _introspection
+          ._getClassBuilder(type as macro.ParameterizedTypeDeclaration);
+      Iterator<SourceFieldBuilder> iterator =
+          classBuilder.fullMemberIterator<SourceFieldBuilder>();
+      while (iterator.moveNext()) {
+        result.add(_introspection.getMemberDeclaration(iterator.current)
+            as macro.FieldDeclaration);
+      }
+    } else if (type is macro.ExtensionTypeDeclaration) {
+      ExtensionTypeDeclarationBuilder extensionTypeDeclarationBuilder =
+          _introspection._getExtensionTypeDeclarationBuilder(type);
+      Iterator<SourceFieldBuilder> iterator = extensionTypeDeclarationBuilder
+          .fullMemberIterator<SourceFieldBuilder>();
+      while (iterator.moveNext()) {
+        result.add(_introspection.getMemberDeclaration(iterator.current)
+            as macro.FieldDeclaration);
+      }
+    } else {
+      throw new UnsupportedError('Only introspection on classes is supported');
     }
     return new Future.value(result);
   }
 
   @override
   Future<List<macro.MethodDeclaration>> methodsOf(macro.TypeDeclaration type) {
-    if (type is! macro.ClassDeclaration && type is! macro.MixinDeclaration) {
+    List<macro.MethodDeclaration> result = [];
+    if (type is macro.ClassDeclaration || type is macro.MixinDeclaration) {
+      ClassBuilder classBuilder = _introspection
+          ._getClassBuilder(type as macro.ParameterizedTypeDeclaration);
+      Iterator<SourceProcedureBuilder> iterator =
+          classBuilder.fullMemberIterator<SourceProcedureBuilder>();
+      while (iterator.moveNext()) {
+        result.add(_introspection.getMemberDeclaration(iterator.current)
+            as macro.MethodDeclaration);
+      }
+    } else if (type is macro.ExtensionTypeDeclaration) {
+      ExtensionTypeDeclarationBuilder extensionTypeDeclarationBuilder =
+          _introspection._getExtensionTypeDeclarationBuilder(type);
+      Iterator<SourceProcedureBuilder> iterator =
+          extensionTypeDeclarationBuilder
+              .fullMemberIterator<SourceProcedureBuilder>();
+      while (iterator.moveNext()) {
+        result.add(_introspection.getMemberDeclaration(iterator.current)
+            as macro.MethodDeclaration);
+      }
+    } else {
       throw new UnsupportedError(
           'Only introspection on classes and mixins is supported');
     }
-    ClassBuilder classBuilder = _introspection
-        ._getClassBuilder(type as macro.ParameterizedTypeDeclaration);
-    List<macro.MethodDeclaration> result = [];
-    Iterator<SourceProcedureBuilder> iterator =
-        classBuilder.fullMemberIterator<SourceProcedureBuilder>();
-    while (iterator.moveNext()) {
-      result.add(_introspection.getMemberDeclaration(iterator.current)
-          as macro.MethodDeclaration);
-    }
     return new Future.value(result);
   }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/macro/macro.dart b/pkg/front_end/lib/src/fasta/kernel/macro/macro.dart
index f501416..af4eb5a 100644
--- a/pkg/front_end/lib/src/fasta/kernel/macro/macro.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/macro/macro.dart
@@ -123,6 +123,8 @@
   Map<SourceLibraryBuilder, MacroExecutionResultsForTesting> libraryResults =
       {};
   Map<SourceClassBuilder, MacroExecutionResultsForTesting> classResults = {};
+  Map<SourceExtensionTypeDeclarationBuilder, MacroExecutionResultsForTesting>
+      extensionTypeResults = {};
   Map<MemberBuilder, MacroExecutionResultsForTesting> memberResults = {};
 
   List<ApplicationDataForTesting> typesApplicationOrder = [];
@@ -137,6 +139,9 @@
     } else if (builder is SourceClassBuilder) {
       resultsForTesting =
           classResults[builder] ??= new MacroExecutionResultsForTesting();
+    } else if (builder is SourceExtensionTypeDeclarationBuilder) {
+      resultsForTesting = extensionTypeResults[builder] ??=
+          new MacroExecutionResultsForTesting();
     } else {
       resultsForTesting = memberResults[builder as MemberBuilder] ??=
           new MacroExecutionResultsForTesting();
@@ -196,6 +201,8 @@
 class LibraryMacroApplicationData {
   ApplicationData? libraryApplications;
   Map<SourceClassBuilder, ClassMacroApplicationData> classData = {};
+  Map<SourceExtensionTypeDeclarationBuilder, ExtensionTypeMacroApplicationData>
+      extensionTypeData = {};
   Map<MemberBuilder, ApplicationData> memberApplications = {};
 }
 
@@ -204,6 +211,11 @@
   Map<MemberBuilder, ApplicationData> memberApplications = {};
 }
 
+class ExtensionTypeMacroApplicationData {
+  ApplicationData? extensionTypeApplications;
+  Map<MemberBuilder, ApplicationData> memberApplications = {};
+}
+
 /// Macro classes that need to be precompiled.
 class NeededPrecompilations {
   /// Map from library uris to macro class names and the names of constructor
@@ -290,6 +302,8 @@
     }
 
     Map<Class, List<ClassMacroApplicationData>> classData = {};
+    Map<ExtensionTypeDeclaration, List<ExtensionTypeMacroApplicationData>>
+        extensionTypeData = {};
     Map<Annotatable, List<ApplicationData>> libraryMemberData = {};
     List<LibraryMacroApplicationData>? libraryMacroApplicationDataList =
         libraryData[libraryBuilder.library];
@@ -300,6 +314,12 @@
             in libraryMacroApplicationData.classData.entries) {
           (classData[entry.key.cls] ??= []).add(entry.value);
         }
+        for (MapEntry<SourceExtensionTypeDeclarationBuilder,
+                ExtensionTypeMacroApplicationData> entry
+            in libraryMacroApplicationData.extensionTypeData.entries) {
+          (extensionTypeData[entry.key.extensionTypeDeclaration] ??= [])
+              .add(entry.value);
+        }
         for (MapEntry<MemberBuilder, ApplicationData> entry
             in libraryMacroApplicationData.memberApplications.entries) {
           for (Annotatable annotatable in entry.key.annotatables) {
@@ -341,6 +361,38 @@
       }
       checkMembers(cls.members, classMemberData);
     }
+    for (ExtensionTypeDeclaration cls in library.extensionTypeDeclarations) {
+      List<ExtensionTypeMacroApplicationData>? classMacroApplications =
+          extensionTypeData[cls];
+      List<ApplicationData> applicationDataList = [];
+      if (classMacroApplications != null) {
+        for (ExtensionTypeMacroApplicationData classMacroApplicationData
+            in classMacroApplications) {
+          ApplicationData? classApplications =
+              classMacroApplicationData.extensionTypeApplications;
+          if (classApplications != null) {
+            applicationDataList.add(classApplications);
+          }
+        }
+      }
+      checkAnnotations(cls.annotations, applicationDataList,
+          fileUri: cls.fileUri);
+
+      Map<Annotatable, List<ApplicationData>> classMemberData = {};
+      if (classMacroApplications != null) {
+        for (ExtensionTypeMacroApplicationData classMacroApplicationData
+            in classMacroApplications) {
+          for (MapEntry<MemberBuilder, ApplicationData> entry
+              in classMacroApplicationData.memberApplications.entries) {
+            for (Annotatable annotatable in entry.key.annotatables) {
+              (classMemberData[annotatable] ??= []).add(entry.value);
+            }
+          }
+        }
+      }
+      // TODO(johnniwinther): Check member applications.
+      //checkMembers(cls.members, classMemberData);
+    }
   }
 }
 
@@ -398,27 +450,26 @@
     while (iterator.moveNext()) {
       Builder builder = iterator.current;
       if (builder is SourceClassBuilder) {
-        SourceClassBuilder classBuilder = builder;
         ClassMacroApplicationData classMacroApplicationData =
             new ClassMacroApplicationData();
         List<MacroApplication>? classMacroApplications = prebuildAnnotations(
             enclosingLibrary: libraryBuilder,
-            scope: classBuilder.scope,
-            fileUri: classBuilder.fileUri,
-            metadataBuilders: classBuilder.metadata,
+            scope: builder.scope,
+            fileUri: builder.fileUri,
+            metadataBuilders: builder.metadata,
             currentMacroDeclarations: currentMacroDeclarations);
         if (classMacroApplications != null) {
           classMacroApplicationData.classApplications =
               new ClassApplicationData(_macroIntrospection, libraryBuilder,
-                  classBuilder, classMacroApplications);
+                  builder, classMacroApplications);
         }
-        Iterator<Builder> memberIterator = classBuilder.localMemberIterator();
+        Iterator<Builder> memberIterator = builder.localMemberIterator();
         while (memberIterator.moveNext()) {
           Builder memberBuilder = memberIterator.current;
           if (memberBuilder is SourceProcedureBuilder) {
             List<MacroApplication>? macroApplications = prebuildAnnotations(
                 enclosingLibrary: libraryBuilder,
-                scope: classBuilder.scope,
+                scope: builder.scope,
                 fileUri: memberBuilder.fileUri,
                 metadataBuilders: memberBuilder.metadata,
                 currentMacroDeclarations: currentMacroDeclarations);
@@ -430,7 +481,7 @@
           } else if (memberBuilder is SourceFieldBuilder) {
             List<MacroApplication>? macroApplications = prebuildAnnotations(
                 enclosingLibrary: libraryBuilder,
-                scope: classBuilder.scope,
+                scope: builder.scope,
                 fileUri: memberBuilder.fileUri,
                 metadataBuilders: memberBuilder.metadata,
                 currentMacroDeclarations: currentMacroDeclarations);
@@ -445,13 +496,13 @@
           }
         }
         Iterator<MemberBuilder> constructorIterator =
-            classBuilder.localConstructorIterator();
+            builder.localConstructorIterator();
         while (constructorIterator.moveNext()) {
           MemberBuilder memberBuilder = constructorIterator.current;
           if (memberBuilder is DeclaredSourceConstructorBuilder) {
             List<MacroApplication>? macroApplications = prebuildAnnotations(
                 enclosingLibrary: libraryBuilder,
-                scope: classBuilder.scope,
+                scope: builder.scope,
                 fileUri: memberBuilder.fileUri,
                 metadataBuilders: memberBuilder.metadata,
                 currentMacroDeclarations: currentMacroDeclarations);
@@ -463,7 +514,7 @@
           } else if (memberBuilder is SourceFactoryBuilder) {
             List<MacroApplication>? macroApplications = prebuildAnnotations(
                 enclosingLibrary: libraryBuilder,
-                scope: classBuilder.scope,
+                scope: builder.scope,
                 fileUri: memberBuilder.fileUri,
                 metadataBuilders: memberBuilder.metadata,
                 currentMacroDeclarations: currentMacroDeclarations);
@@ -507,8 +558,97 @@
               new MemberApplicationData(_macroIntrospection, libraryBuilder,
                   builder, macroApplications);
         }
+      } else if (builder is SourceExtensionTypeDeclarationBuilder) {
+        ExtensionTypeMacroApplicationData extensionTypeMacroApplicationData =
+            new ExtensionTypeMacroApplicationData();
+        List<MacroApplication>? classMacroApplications = prebuildAnnotations(
+            enclosingLibrary: libraryBuilder,
+            scope: builder.scope,
+            fileUri: builder.fileUri,
+            metadataBuilders: builder.metadata,
+            currentMacroDeclarations: currentMacroDeclarations);
+        if (classMacroApplications != null) {
+          extensionTypeMacroApplicationData.extensionTypeApplications =
+              new ExtensionTypeApplicationData(_macroIntrospection,
+                  libraryBuilder, builder, classMacroApplications);
+        }
+        Iterator<Builder> memberIterator = builder.localMemberIterator();
+        while (memberIterator.moveNext()) {
+          Builder memberBuilder = memberIterator.current;
+          if (memberBuilder is SourceProcedureBuilder) {
+            List<MacroApplication>? macroApplications = prebuildAnnotations(
+                enclosingLibrary: libraryBuilder,
+                scope: builder.scope,
+                fileUri: memberBuilder.fileUri,
+                metadataBuilders: memberBuilder.metadata,
+                currentMacroDeclarations: currentMacroDeclarations);
+            if (macroApplications != null) {
+              extensionTypeMacroApplicationData
+                      .memberApplications[memberBuilder] =
+                  new MemberApplicationData(_macroIntrospection, libraryBuilder,
+                      memberBuilder, macroApplications);
+            }
+          } else if (memberBuilder is SourceFieldBuilder) {
+            List<MacroApplication>? macroApplications = prebuildAnnotations(
+                enclosingLibrary: libraryBuilder,
+                scope: builder.scope,
+                fileUri: memberBuilder.fileUri,
+                metadataBuilders: memberBuilder.metadata,
+                currentMacroDeclarations: currentMacroDeclarations);
+            if (macroApplications != null) {
+              extensionTypeMacroApplicationData
+                      .memberApplications[memberBuilder] =
+                  new MemberApplicationData(_macroIntrospection, libraryBuilder,
+                      memberBuilder, macroApplications);
+            }
+          } else {
+            throw new UnsupportedError("Unexpected class member "
+                "$memberBuilder (${memberBuilder.runtimeType})");
+          }
+        }
+        Iterator<MemberBuilder> constructorIterator =
+            builder.localConstructorIterator();
+        while (constructorIterator.moveNext()) {
+          MemberBuilder memberBuilder = constructorIterator.current;
+          if (memberBuilder is SourceExtensionTypeConstructorBuilder) {
+            List<MacroApplication>? macroApplications = prebuildAnnotations(
+                enclosingLibrary: libraryBuilder,
+                scope: builder.scope,
+                fileUri: memberBuilder.fileUri,
+                metadataBuilders: memberBuilder.metadata,
+                currentMacroDeclarations: currentMacroDeclarations);
+            if (macroApplications != null) {
+              extensionTypeMacroApplicationData
+                      .memberApplications[memberBuilder] =
+                  new MemberApplicationData(_macroIntrospection, libraryBuilder,
+                      memberBuilder, macroApplications);
+            }
+          } else if (memberBuilder is SourceFactoryBuilder) {
+            List<MacroApplication>? macroApplications = prebuildAnnotations(
+                enclosingLibrary: libraryBuilder,
+                scope: builder.scope,
+                fileUri: memberBuilder.fileUri,
+                metadataBuilders: memberBuilder.metadata,
+                currentMacroDeclarations: currentMacroDeclarations);
+            if (macroApplications != null) {
+              extensionTypeMacroApplicationData
+                      .memberApplications[memberBuilder] =
+                  new MemberApplicationData(_macroIntrospection, libraryBuilder,
+                      memberBuilder, macroApplications);
+            }
+          } else {
+            throw new UnsupportedError("Unexpected constructor "
+                "$memberBuilder (${memberBuilder.runtimeType})");
+          }
+        }
+
+        if (extensionTypeMacroApplicationData.extensionTypeApplications !=
+                null ||
+            extensionTypeMacroApplicationData.memberApplications.isNotEmpty) {
+          libraryMacroApplicationData.extensionTypeData[builder] =
+              extensionTypeMacroApplicationData;
+        }
       } else if (builder is SourceExtensionBuilder ||
-          builder is SourceExtensionTypeDeclarationBuilder ||
           builder is SourceTypeAliasBuilder) {
         // TODO(johnniwinther): Support macro applications.
       } else if (builder is PrefixBuilder) {
@@ -520,6 +660,7 @@
     }
     if (libraryMacroApplications != null ||
         libraryMacroApplicationData.classData.isNotEmpty ||
+        libraryMacroApplicationData.extensionTypeData.isNotEmpty ||
         libraryMacroApplicationData.memberApplications.isNotEmpty) {
       _libraryData[libraryBuilder] = libraryMacroApplicationData;
       dataForTesting?.libraryData[libraryBuilder] = libraryMacroApplicationData;
@@ -624,6 +765,14 @@
           await ensureMacroClassIds(applicationData);
         }
       }
+      for (ExtensionTypeMacroApplicationData extensionTypeData
+          in libraryData.extensionTypeData.values) {
+        await ensureMacroClassIds(extensionTypeData.extensionTypeApplications);
+        for (ApplicationData applicationData
+            in extensionTypeData.memberApplications.values) {
+          await ensureMacroClassIds(applicationData);
+        }
+      }
       for (ApplicationData applicationData
           in libraryData.memberApplications.values) {
         await ensureMacroClassIds(applicationData);
@@ -688,9 +837,8 @@
         executionResults.addAll(
             await _applyTypeMacros(libraryBuilder.origin, applicationData));
       }
-      for (MapEntry<ClassBuilder, ClassMacroApplicationData> entry
-          in data.classData.entries) {
-        ClassMacroApplicationData classApplicationData = entry.value;
+      for (ClassMacroApplicationData classApplicationData
+          in data.classData.values) {
         for (ApplicationData applicationData
             in classApplicationData.memberApplications.values) {
           executionResults.addAll(
@@ -701,6 +849,18 @@
               libraryBuilder.origin, classApplicationData.classApplications!));
         }
       }
+      for (ExtensionTypeMacroApplicationData extensionTypeApplicationData
+          in data.extensionTypeData.values) {
+        for (ApplicationData applicationData
+            in extensionTypeApplicationData.memberApplications.values) {
+          executionResults.addAll(
+              await _applyTypeMacros(libraryBuilder.origin, applicationData));
+        }
+        if (extensionTypeApplicationData.extensionTypeApplications != null) {
+          executionResults.addAll(await _applyTypeMacros(libraryBuilder.origin,
+              extensionTypeApplicationData.extensionTypeApplications!));
+        }
+      }
       if (executionResults.isNotEmpty) {
         Map<macro.OmittedTypeAnnotation, String> omittedTypes = {};
         List<macro.Span> spans = [];
@@ -813,6 +973,8 @@
 
   Future<void> applyDeclarationsMacros(
       List<SourceClassBuilder> sortedSourceClassBuilders,
+      List<SourceExtensionTypeDeclarationBuilder>
+          sortedSourceExtensionTypeBuilders,
       Future<void> Function(SourceLibraryBuilder) onAugmentationLibrary) async {
     // TODO(johnniwinther): Maintain a pending list instead of running through
     // all annotations to find the once have to be applied now.
@@ -838,19 +1000,52 @@
 
     // Apply macros to classes first, in class hierarchy order.
     for (SourceClassBuilder classBuilder in sortedSourceClassBuilders) {
-      await applyClassMacros(classBuilder);
-      // TODO(johnniwinther): Avoid accessing augmentations from the outside.
-      List<SourceClassBuilder>? augmentationClassBuilders =
-          classBuilder.augmentationsForTesting;
-      if (augmentationClassBuilders != null) {
-        for (SourceClassBuilder augmentationClassBuilder
-            in augmentationClassBuilders) {
-          await applyClassMacros(augmentationClassBuilder);
-        }
+      Iterator<SourceClassBuilder> declarationIterator =
+          classBuilder.declarationIterator;
+      while (declarationIterator.moveNext()) {
+        await applyClassMacros(declarationIterator.current);
       }
     }
 
-    // Apply macros to library members second.
+    // TODO(johnniwinther): Maintain a pending list instead of running through
+    // all annotations to find the once have to be applied now.
+    Future<void> applyExtensionTypeMacros(
+        SourceExtensionTypeDeclarationBuilder
+            extensionTypeDeclarationBuilder) async {
+      SourceLibraryBuilder libraryBuilder =
+          extensionTypeDeclarationBuilder.libraryBuilder;
+      LibraryMacroApplicationData? libraryApplicationData =
+          _libraryData[libraryBuilder];
+      if (libraryApplicationData == null) return;
+
+      ExtensionTypeMacroApplicationData? extensionTypeApplicationData =
+          libraryApplicationData
+              .extensionTypeData[extensionTypeDeclarationBuilder];
+      if (extensionTypeApplicationData == null) return;
+      for (ApplicationData applicationData
+          in extensionTypeApplicationData.memberApplications.values) {
+        await _applyDeclarationsMacros(
+            libraryBuilder.origin, applicationData, onAugmentationLibrary);
+      }
+      if (extensionTypeApplicationData.extensionTypeApplications != null) {
+        await _applyDeclarationsMacros(
+            libraryBuilder.origin,
+            extensionTypeApplicationData.extensionTypeApplications!,
+            onAugmentationLibrary);
+      }
+    }
+
+    // Apply macros to extension types second, in class hierarchy order.
+    for (SourceExtensionTypeDeclarationBuilder extensionTypeDeclarationBuilder
+        in sortedSourceExtensionTypeBuilders) {
+      Iterator<SourceExtensionTypeDeclarationBuilder> declarationIterator =
+          extensionTypeDeclarationBuilder.declarationIterator;
+      while (declarationIterator.moveNext()) {
+        await applyExtensionTypeMacros(declarationIterator.current);
+      }
+    }
+
+    // Apply macros to library members third.
     for (MapEntry<SourceLibraryBuilder, LibraryMacroApplicationData> entry
         in _libraryData.entries) {
       SourceLibraryBuilder libraryBuilder = entry.key;
@@ -925,9 +1120,8 @@
         executionResults.addAll(await _applyDefinitionMacros(
             libraryBuilder.origin, applicationData));
       }
-      for (MapEntry<ClassBuilder, ClassMacroApplicationData> entry
-          in data.classData.entries) {
-        ClassMacroApplicationData classApplicationData = entry.value;
+      for (ClassMacroApplicationData classApplicationData
+          in data.classData.values) {
         for (ApplicationData applicationData
             in classApplicationData.memberApplications.values) {
           executionResults.addAll(await _applyDefinitionMacros(
@@ -938,6 +1132,19 @@
               libraryBuilder.origin, classApplicationData.classApplications!));
         }
       }
+      for (ExtensionTypeMacroApplicationData extensionTypeApplicationData
+          in data.extensionTypeData.values) {
+        for (ApplicationData applicationData
+            in extensionTypeApplicationData.memberApplications.values) {
+          executionResults.addAll(await _applyDefinitionMacros(
+              libraryBuilder.origin, applicationData));
+        }
+        if (extensionTypeApplicationData.extensionTypeApplications != null) {
+          executionResults.addAll(await _applyDefinitionMacros(
+              libraryBuilder.origin,
+              extensionTypeApplicationData.extensionTypeApplications!));
+        }
+      }
       if (executionResults.isNotEmpty) {
         List<macro.Span> spans = [];
         String result = _macroExecutor.buildAugmentationLibrary(
@@ -1072,6 +1279,8 @@
     return macro.DeclarationKind.enumType;
   } else if (declaration is macro.MixinDeclaration) {
     return macro.DeclarationKind.mixinType;
+  } else if (declaration is macro.ExtensionTypeDeclaration) {
+    return macro.DeclarationKind.extensionType;
   }
   throw new UnsupportedError(
       "Unexpected declaration ${declaration} (${declaration.runtimeType})");
@@ -1151,6 +1360,25 @@
   String get textForTesting => _classBuilder.name;
 }
 
+class ExtensionTypeApplicationData extends DeclarationApplicationData {
+  final SourceExtensionTypeDeclarationBuilder _extensionTypeDeclarationBuilder;
+
+  ExtensionTypeApplicationData(super.macroIntrospection, super.libraryBuilder,
+      this._extensionTypeDeclarationBuilder, super.macroApplications);
+
+  @override
+  macro.Declaration get declaration {
+    return _declaration ??= _macroIntrospection
+        .getExtensionTypeDeclaration(_extensionTypeDeclarationBuilder);
+  }
+
+  @override
+  Builder get builder => _extensionTypeDeclarationBuilder;
+
+  @override
+  String get textForTesting => _extensionTypeDeclarationBuilder.name;
+}
+
 class MemberApplicationData extends DeclarationApplicationData {
   final MemberBuilder _memberBuilder;
 
diff --git a/pkg/front_end/lib/src/fasta/source/class_declaration.dart b/pkg/front_end/lib/src/fasta/source/class_declaration.dart
index 42ba5f6..cfd979a 100644
--- a/pkg/front_end/lib/src/fasta/source/class_declaration.dart
+++ b/pkg/front_end/lib/src/fasta/source/class_declaration.dart
@@ -31,6 +31,60 @@
   bool get isMixinDeclaration;
 
   int resolveConstructors(SourceLibraryBuilder library);
+
+  /// [Iterator] for all members declared directly in this class, including
+  /// augmenting members.
+  ///
+  /// Duplicates are _not_ included.
+  ///
+  /// For instance:
+  ///
+  ///     class Class {
+  ///       // Declared, so it is included for this class but not for the
+  ///       // augmentation class below.
+  ///       method() {}
+  ///       // Declared, so it is included for this class but not for the
+  ///       // augmentation class below.
+  ///       method2() {}
+  ///       method2() {} // Duplicate, so it is *not* included.
+  ///     }
+  ///
+  ///     augment class Class {
+  ///       // Augmenting, so it is included for this augmentation class but
+  ///       // not for the origin class above.
+  ///       augment method() {}
+  ///       // Declared, so it is included for this augmentation class but not
+  ///       // for the origin class above.
+  ///       extra() {}
+  ///     }
+  ///
+  Iterator<T> localMemberIterator<T extends Builder>();
+
+  /// [Iterator] for all constructors declared directly in this class, including
+  /// augmenting constructors.
+  ///
+  /// For instance:
+  ///
+  ///     class Class {
+  ///       // Declared, so it is included for this class but not for the
+  ///       // augmentation class below.
+  ///       Class();
+  ///       // Declared, so it is included for this class but not for the
+  ///       // augmentation class below.
+  ///       Class.named();
+  ///       Class.named(); // Duplicate, so it is *not* included.
+  ///     }
+  ///
+  ///     augment class Class {
+  ///       // Augmenting, so it is included for this augmentation class but
+  ///       // not for the origin class above.
+  ///       augment Class();
+  ///       // Declared, so it is included for this augmentation class but not
+  ///       // for the origin class above.
+  ///       Class.extra();
+  ///     }
+  ///
+  Iterator<T> localConstructorIterator<T extends MemberBuilder>();
 }
 
 mixin ClassDeclarationMixin implements ClassDeclaration {
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index 757c927..c5f967d 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -21,6 +21,7 @@
         updateBoundNullabilities;
 import 'package:kernel/type_environment.dart';
 
+import '../builder/augmentation_iterator.dart';
 import '../builder/builder.dart';
 import '../builder/constructor_reference_builder.dart';
 import '../builder/declaration_builders.dart';
@@ -370,60 +371,12 @@
         .forEach(build);
   }
 
-  /// [Iterator] for all members declared directly in this class, including
-  /// augmenting members.
-  ///
-  /// Duplicates are _not_ included.
-  ///
-  /// For instance:
-  ///
-  ///     class Class {
-  ///       // Declared, so it is included for this class but not for the
-  ///       // augmentation class below.
-  ///       method() {}
-  ///       // Declared, so it is included for this class but not for the
-  ///       // augmentation class below.
-  ///       method2() {}
-  ///       method2() {} // Duplicate, so it is *not* included.
-  ///     }
-  ///
-  ///     augment class Class {
-  ///       // Augmenting, so it is included for this augmentation class but
-  ///       // not for the origin class above.
-  ///       augment method() {}
-  ///       // Declared, so it is included for this augmentation class but not
-  ///       // for the origin class above.
-  ///       extra() {}
-  ///     }
-  ///
+  @override
   Iterator<T> localMemberIterator<T extends Builder>() =>
       new ClassDeclarationMemberIterator<SourceClassBuilder, T>.local(this,
           includeDuplicates: false);
 
-  /// [Iterator] for all constructors declared directly in this class, including
-  /// augmenting constructors.
-  ///
-  /// For instance:
-  ///
-  ///     class Class {
-  ///       // Declared, so it is included for this class but not for the
-  ///       // augmentation class below.
-  ///       Class();
-  ///       // Declared, so it is included for this class but not for the
-  ///       // augmentation class below.
-  ///       Class.named();
-  ///       Class.named(); // Duplicate, so it is *not* included.
-  ///     }
-  ///
-  ///     augment class Class {
-  ///       // Augmenting, so it is included for this augmentation class but
-  ///       // not for the origin class above.
-  ///       augment Class();
-  ///       // Declared, so it is included for this augmentation class but not
-  ///       // for the origin class above.
-  ///       Class.extra();
-  ///     }
-  ///
+  @override
   Iterator<T> localConstructorIterator<T extends MemberBuilder>() =>
       new ClassDeclarationConstructorIterator<SourceClassBuilder, T>.local(this,
           includeDuplicates: false);
@@ -1954,6 +1907,12 @@
       }
     }
   }
+
+  /// Returns an iterator the origin class and all augmentations in application
+  /// order.
+  Iterator<SourceClassBuilder> get declarationIterator =>
+      new AugmentationIterator<SourceClassBuilder>(
+          origin, origin._augmentations);
 }
 
 /// Returns `true` if override problems should be overlooked.
diff --git a/pkg/front_end/lib/src/fasta/source/source_extension_type_declaration_builder.dart b/pkg/front_end/lib/src/fasta/source/source_extension_type_declaration_builder.dart
index fd547e6..627311b 100644
--- a/pkg/front_end/lib/src/fasta/source/source_extension_type_declaration_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_extension_type_declaration_builder.dart
@@ -9,6 +9,7 @@
 import 'package:kernel/type_algebra.dart';
 import 'package:kernel/type_environment.dart';
 
+import '../builder/augmentation_iterator.dart';
 import '../builder/builder.dart';
 import '../builder/constructor_reference_builder.dart';
 import '../builder/declaration_builders.dart';
@@ -779,6 +780,25 @@
     }
     return result;
   }
+
+  @override
+  Iterator<T> localMemberIterator<T extends Builder>() =>
+      new ClassDeclarationMemberIterator<SourceExtensionTypeDeclarationBuilder,
+          T>.local(this, includeDuplicates: false);
+
+  @override
+  Iterator<T> localConstructorIterator<T extends MemberBuilder>() =>
+      new ClassDeclarationConstructorIterator<
+          SourceExtensionTypeDeclarationBuilder,
+          T>.local(this, includeDuplicates: false);
+
+  /// Returns an iterator the origin extension type declaration and all
+  /// augmentations in application order.
+  Iterator<SourceExtensionTypeDeclarationBuilder> get declarationIterator =>
+      new AugmentationIterator<SourceExtensionTypeDeclarationBuilder>(
+          // TODO(johnniwinther): Support augmentations.
+          origin,
+          null);
 }
 
 class _SourceExtensionTypeDeclarationBuilderAugmentationAccess
diff --git a/pkg/front_end/test/coverage_suite.dart b/pkg/front_end/test/coverage_suite.dart
index fc4038a..f36da0c 100644
--- a/pkg/front_end/test/coverage_suite.dart
+++ b/pkg/front_end/test/coverage_suite.dart
@@ -229,7 +229,7 @@
   "package:front_end/src/fasta/source/source_extension_builder.dart":
       61.261261261261254,
   "package:front_end/src/fasta/source/source_extension_type_declaration_builder.dart":
-      85.34136546184739,
+      84.0,
   "package:front_end/src/fasta/source/source_factory_builder.dart":
       92.22222222222223,
   "package:front_end/src/fasta/source/source_field_builder.dart":
diff --git a/pkg/front_end/test/macros/application/data/tests/targets.dart b/pkg/front_end/test/macros/application/data/tests/targets.dart
index f5efb5b..af8dedd 100644
--- a/pkg/front_end/test/macros/application/data/tests/targets.dart
+++ b/pkg/front_end/test/macros/application/data/tests/targets.dart
@@ -22,6 +22,7 @@
  Enum.a:VariableTypesMacro.new()
  Enum:ClassTypesMacro.new()
  Mixin:MixinTypesMacro.new()
+ ExtensionType:ExtensionTypeTypesMacro.new()
 Declarations Order:
  Class.field:FieldDeclarationsMacro.new()
  Class.field:VariableDeclarationsMacro.new()
@@ -34,6 +35,7 @@
  Enum.a:VariableDeclarationsMacro.new()
  Enum:ClassDeclarationsMacro.new()
  Mixin:MixinDeclarationsMacro.new()
+ ExtensionType:ExtensionTypeDeclarationsMacro.new()
  org-dartlang-test:///a/b/c/main.dart:LibraryDeclarationsMacro.new()
  function:FunctionDeclarationsMacro.new()
  variable:VariableDeclarationsMacro.new()
@@ -50,7 +52,8 @@
  Enum.a:FieldDefinitionMacro.new()
  Enum.a:VariableDefinitionMacro.new()
  Enum:ClassDefinitionMacro.new()
- Mixin:MixinDefinitionMacro.new()*/
+ Mixin:MixinDefinitionMacro.new()
+ ExtensionType:ExtensionTypeDefinitionMacro.new()*/
 
 @LibraryTypesMacro() // Ok
 @LibraryDeclarationsMacro() // Ok
diff --git a/pkg/front_end/test/macros/application/data/tests/targets.dart.expect b/pkg/front_end/test/macros/application/data/tests/targets.dart.expect
index 9b5e1e9..f708358 100644
--- a/pkg/front_end/test/macros/application/data/tests/targets.dart.expect
+++ b/pkg/front_end/test/macros/application/data/tests/targets.dart.expect
@@ -1166,6 +1166,154 @@
 // @LibraryTypesMacro() // Error
 //  ^
 //
+// org-dartlang-test:///a/b/c/main.dart:507:2: Error: The macro can only be applied to fields, functions, methods or variables.
+// @VariableAndFunctionTypesMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:506:2: Error: The macro can only be applied to fields or methods.
+// @FieldAndMethodTypesMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:505:2: Error: The macro can only be applied to typedefs.
+// @TypeAliasDeclarationsMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:504:2: Error: The macro can only be applied to typedefs.
+// @TypeAliasTypesMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:500:2: Error: The macro can only be applied to extensions.
+// @ExtensionDefinitionMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:499:2: Error: The macro can only be applied to extensions.
+// @ExtensionDeclarationsMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:498:2: Error: The macro can only be applied to extensions.
+// @ExtensionTypesMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:497:2: Error: The macro can only be applied to mixin declarations.
+// @MixinDefinitionMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:496:2: Error: The macro can only be applied to mixin declarations.
+// @MixinDeclarationsMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:495:2: Error: The macro can only be applied to mixin declarations.
+// @MixinTypesMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:494:2: Error: The macro can only be applied to constructors.
+// @ConstructorDefinitionMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:493:2: Error: The macro can only be applied to constructors.
+// @ConstructorDeclarationsMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:492:2: Error: The macro can only be applied to constructors.
+// @ConstructorTypesMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:491:2: Error: The macro can only be applied to methods.
+// @MethodDefinitionMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:490:2: Error: The macro can only be applied to methods.
+// @MethodDeclarationsMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:489:2: Error: The macro can only be applied to methods.
+// @MethodTypesMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:488:2: Error: The macro can only be applied to fields.
+// @FieldDefinitionMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:487:2: Error: The macro can only be applied to fields.
+// @FieldDeclarationsMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:486:2: Error: The macro can only be applied to fields.
+// @FieldTypesMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:485:2: Error: The macro can only be applied to enum values.
+// @EnumValueDefinitionMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:484:2: Error: The macro can only be applied to enum values.
+// @EnumValueDeclarationsMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:483:2: Error: The macro can only be applied to enum values.
+// @EnumValueTypesMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:482:2: Error: The macro can only be applied to enums.
+// @EnumDefinitionMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:481:2: Error: The macro can only be applied to enums.
+// @EnumDeclarationsMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:480:2: Error: The macro can only be applied to enums.
+// @EnumTypesMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:479:2: Error: The macro can only be applied to classes.
+// @ClassDefinitionMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:478:2: Error: The macro can only be applied to classes.
+// @ClassDeclarationsMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:477:2: Error: The macro can only be applied to classes.
+// @ClassTypesMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:476:2: Error: The macro can only be applied to fields or variables.
+// @VariableDefinitionMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:475:2: Error: The macro can only be applied to fields or variables.
+// @VariableDeclarationsMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:474:2: Error: The macro can only be applied to fields or variables.
+// @VariableTypesMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:473:2: Error: The macro can only be applied to functions or methods.
+// @FunctionDefinitionMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:472:2: Error: The macro can only be applied to functions or methods.
+// @FunctionDeclarationsMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:471:2: Error: The macro can only be applied to functions or methods.
+// @FunctionTypesMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:470:2: Error: The macro can only be applied to libraries.
+// @LibraryDefinitionMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:469:2: Error: The macro can only be applied to libraries.
+// @LibraryDeclarationsMacro() // Error
+//  ^
+//
+// org-dartlang-test:///a/b/c/main.dart:468:2: Error: The macro can only be applied to libraries.
+// @LibraryTypesMacro() // Error
+//  ^
+//
 // org-dartlang-test:///a/b/c/main.dart:256:2: Error: The macro can only be applied to fields or methods.
 // @FieldAndMethodTypesMacro() // Error
 //  ^
diff --git a/pkg/front_end/test/macros/macro_api_test.dart b/pkg/front_end/test/macros/macro_api_test.dart
index a1dc02e..b1d756b8 100644
--- a/pkg/front_end/test/macros/macro_api_test.dart
+++ b/pkg/front_end/test/macros/macro_api_test.dart
@@ -4,6 +4,7 @@
 
 import 'dart:io' show Platform;
 
+import 'package:front_end/src/api_prototype/terminal_color_support.dart';
 import 'package:macros/src/executor/multi_executor.dart';
 import 'package:expect/expect.dart';
 import 'package:front_end/src/api_prototype/experimental_flags.dart';
@@ -24,7 +25,9 @@
         '../../../_fe_analyzer_shared/test/macros/api/package_config.json');
     options.macroExecutor ??= new MultiMacroExecutor();
     options.macroSerializer = macroSerializer;
-
+    options.onDiagnostic = (DiagnosticMessage message) {
+      printDiagnosticMessage(message, print);
+    };
     InternalCompilerResult result = await kernelForProgramInternal(
         Platform.script.resolve(
             '../../../_fe_analyzer_shared/test/macros/api/api_test_data.dart'),