Move macro apis to _fe_analyzer_shared from the language repo.
I could do a separate package if you think that would be better, but putting it here I think makes things simpler.
Change-Id: I4e62bc18dcd9d3bb84a7aceb8f4e2821c84d1361
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/224280
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/api.dart b/pkg/_fe_analyzer_shared/lib/src/macros/api.dart
new file mode 100644
index 0000000..5d5c262
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/api.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2021, 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.
+
+import 'dart:async';
+
+part 'api/builders.dart';
+part 'api/code.dart';
+part 'api/introspection.dart';
+part 'api/macros.dart';
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/api/builders.dart b/pkg/_fe_analyzer_shared/lib/src/macros/api/builders.dart
new file mode 100644
index 0000000..74bf73c
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/api/builders.dart
@@ -0,0 +1,159 @@
+// Copyright (c) 2021, 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.
+
+part of '../api.dart';
+
+/// The base interface used to add declarations to the program as well
+/// as augment existing ones.
+abstract class Builder {}
+
+/// The api used by [Macro]s to contribute new type declarations to the
+/// current library, and get [TypeAnnotation]s from runtime [Type] objects.
+abstract class TypeBuilder implements Builder {
+ /// Adds a new type declaration to the surrounding library.
+ void declareType(DeclarationCode typeDeclaration);
+}
+
+/// The interface to resolve a [TypeAnnotation] to a [StaticType].
+///
+/// The [StaticType]s can be compared against other [StaticType]s to see how
+/// they relate to each other.
+///
+/// This api is only available to the declaration and definition phases of
+/// macro expansion.
+abstract class TypeResolver {
+ /// Resolves [typeAnnotation] to a [StaticType].
+ ///
+ /// Throws an error if the type annotation cannot be resolved. This should
+ /// only happen in the case of incomplete or invalid programs, but macros
+ /// may be asked to run in this state during the development cycle. It is
+ /// helpful for users if macros provide a best effort implementation in that
+ /// case or handle the error in a useful way.
+ Future<StaticType> resolve(TypeAnnotation typeAnnotation);
+}
+
+/// The api used to introspect on a [ClassDeclaration].
+///
+/// Available in the declaration and definition phases, but limited in the
+/// declaration phase to immediately annotated [ClassDeclaration]s. This is
+/// done by limiting the access to the [TypeDeclarationResolver] to the
+/// definition phase.
+abstract class ClassIntrospector {
+ /// The fields available for [clazz].
+ ///
+ /// This may be incomplete if in the declaration phase and additional macros
+ /// are going to run on this class.
+ Future<List<FieldDeclaration>> fieldsOf(ClassDeclaration clazz);
+
+ /// The methods available so far for the current class.
+ ///
+ /// This may be incomplete if additional declaration macros are running on
+ /// this class.
+ Future<List<MethodDeclaration>> methodsOf(ClassDeclaration clazz);
+
+ /// The constructors available so far for the current class.
+ ///
+ /// This may be incomplete if additional declaration macros are running on
+ /// this class.
+ Future<List<ConstructorDeclaration>> constructorsOf(ClassDeclaration clazz);
+
+ /// The class that is directly extended via an `extends` clause.
+ Future<ClassDeclaration?> superclassOf(ClassDeclaration clazz);
+
+ /// All of the classes that are mixed in with `with` clauses.
+ Future<List<ClassDeclaration>> mixinsOf(ClassDeclaration clazz);
+
+ /// All of the classes that are implemented with an `implements` clause.
+ Future<List<ClassDeclaration>> interfacesOf(ClassDeclaration clazz);
+}
+
+/// The api used by [Macro]s to contribute new (non-type)
+/// declarations to the current library.
+///
+/// Can also be used to do subtype checks on types.
+abstract class DeclarationBuilder
+ implements Builder, TypeResolver, ClassIntrospector {
+ /// Adds a new regular declaration to the surrounding library.
+ ///
+ /// Note that type declarations are not supported.
+ void declareInLibrary(DeclarationCode declaration);
+}
+
+/// The api used by [Macro]s to contribute new members to a class.
+abstract class ClassMemberDeclarationBuilder implements DeclarationBuilder {
+ /// Adds a new declaration to the surrounding class.
+ void declareInClass(DeclarationCode declaration);
+}
+
+/// The api used by [Macro]s to reflect on the currently available
+/// members, superclass, and mixins for a given [ClassDeclaration]
+abstract class ClassDeclarationBuilder
+ implements ClassMemberDeclarationBuilder, ClassIntrospector {}
+
+/// The interface used by [Macro]s to resolve any [NamedStaticType] to its
+/// declaration.
+///
+/// Only available in the definition phase of macro expansion.
+abstract class TypeDeclarationResolver {
+ /// Resolves a [NamedStaticType] to its [TypeDeclaration].
+ Future<TypeDeclaration> declarationOf(NamedStaticType annotation);
+}
+
+/// The base class for builders in the definition phase. These can convert
+/// any [TypeAnnotation] into its corresponding [TypeDeclaration], and also
+/// reflect more deeply on those.
+abstract class DefinitionBuilder
+ implements
+ Builder,
+ TypeResolver,
+ ClassIntrospector,
+ TypeDeclarationResolver {}
+
+/// The apis used by [Macro]s that run on classes, to fill in the definitions
+/// of any external declarations within that class.
+abstract class ClassDefinitionBuilder implements DefinitionBuilder {
+ /// Retrieve a [VariableDefinitionBuilder] for a field by [name].
+ ///
+ /// Throws an [ArgumentError] if there is no field by that name.
+ VariableDefinitionBuilder buildField(String name);
+
+ /// Retrieve a [FunctionDefinitionBuilder] for a method by [name].
+ ///
+ /// Throws an [ArgumentError] if there is no method by that name.
+ FunctionDefinitionBuilder buildMethod(String name);
+
+ /// Retrieve a [ConstructorDefinitionBuilder] for a constructor by [name].
+ ///
+ /// Throws an [ArgumentError] if there is no constructor by that name.
+ ConstructorDefinitionBuilder buildConstructor(String name);
+}
+
+/// The apis used by [Macro]s to define the body of a constructor
+/// or wrap the body of an existing constructor with additional statements.
+abstract class ConstructorDefinitionBuilder implements DefinitionBuilder {
+ /// Augments an existing constructor body with [body].
+ ///
+ /// TODO: Link the library augmentations proposal to describe the semantics.
+ void augment({FunctionBodyCode? body, List<Code>? initializers});
+}
+
+/// The apis used by [Macro]s to augment functions or methods.
+abstract class FunctionDefinitionBuilder implements DefinitionBuilder {
+ /// Augments the function.
+ ///
+ /// TODO: Link the library augmentations proposal to describe the semantics.
+ void augment(FunctionBodyCode body);
+}
+
+/// The api used by [Macro]s to augment a top level variable or instance field.
+abstract class VariableDefinitionBuilder implements DefinitionBuilder {
+ /// Augments the field.
+ ///
+ /// TODO: Link the library augmentations proposal to describe the semantics.
+ void augment({
+ DeclarationCode? getter,
+ DeclarationCode? setter,
+ ExpressionCode? initializer,
+ });
+}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/api/code.dart b/pkg/_fe_analyzer_shared/lib/src/macros/api/code.dart
new file mode 100644
index 0000000..89f169f
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/api/code.dart
@@ -0,0 +1,104 @@
+// Copyright (c) 2021, 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.
+
+part of '../api.dart';
+
+/// The base class representing an arbitrary chunk of Dart code, which may or
+/// may not be syntactically or semantically valid yet.
+class Code {
+ /// All the chunks of [Code] or raw [String]s that comprise this [Code]
+ /// object.
+ final List<Object> parts;
+
+ Code.fromString(String code) : parts = [code];
+
+ Code.fromParts(this.parts);
+}
+
+/// A piece of code representing a syntactically valid declaration.
+class DeclarationCode extends Code {
+ DeclarationCode.fromString(String code) : super.fromString(code);
+
+ DeclarationCode.fromParts(List<Object> parts) : super.fromParts(parts);
+}
+
+/// A piece of code representing a syntactically valid element.
+///
+/// Should not include any trailing commas,
+class ElementCode extends Code {
+ ElementCode.fromString(String code) : super.fromString(code);
+
+ ElementCode.fromParts(List<Object> parts) : super.fromParts(parts);
+}
+
+/// A piece of code representing a syntactically valid expression.
+class ExpressionCode extends Code {
+ ExpressionCode.fromString(String code) : super.fromString(code);
+
+ ExpressionCode.fromParts(List<Object> parts) : super.fromParts(parts);
+}
+
+/// A piece of code representing a syntactically valid function body.
+///
+/// This includes any and all code after the parameter list of a function,
+/// including modifiers like `async`.
+///
+/// Both arrow and block function bodies are allowed.
+class FunctionBodyCode extends Code {
+ FunctionBodyCode.fromString(String code) : super.fromString(code);
+
+ FunctionBodyCode.fromParts(List<Object> parts) : super.fromParts(parts);
+}
+
+/// A piece of code representing a syntactically valid identifier.
+class IdentifierCode extends Code {
+ IdentifierCode.fromString(String code) : super.fromString(code);
+
+ IdentifierCode.fromParts(List<Object> parts) : super.fromParts(parts);
+}
+
+/// A piece of code identifying a named argument.
+///
+/// This should not include any trailing commas.
+class NamedArgumentCode extends Code {
+ NamedArgumentCode.fromString(String code) : super.fromString(code);
+
+ NamedArgumentCode.fromParts(List<Object> parts) : super.fromParts(parts);
+}
+
+/// A piece of code identifying a syntactically valid function parameter.
+///
+/// This should not include any trailing commas, but may include modifiers
+/// such as `required`, and default values.
+///
+/// There is no distinction here made between named and positional parameters,
+/// nor between optional or required parameters. It is the job of the user to
+/// construct and combine these together in a way that creates valid parameter
+/// lists.
+class ParameterCode extends Code {
+ ParameterCode.fromString(String code) : super.fromString(code);
+
+ ParameterCode.fromParts(List<Object> parts) : super.fromParts(parts);
+}
+
+/// A piece of code representing a syntactically valid statement.
+///
+/// Should always end with a semicolon.
+class StatementCode extends Code {
+ StatementCode.fromString(String code) : super.fromString(code);
+
+ StatementCode.fromParts(List<Object> parts) : super.fromParts(parts);
+}
+
+extension Join<T extends Code> on List<T> {
+ /// Joins all the items in [this] with [separator], and returns
+ /// a new list.
+ List<Code> joinAsCode(String separator) => [
+ for (int i = 0; i < length - 1; i++) ...[
+ this[i],
+ new Code.fromString(separator),
+ ],
+ last,
+ ];
+}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/api/introspection.dart b/pkg/_fe_analyzer_shared/lib/src/macros/api/introspection.dart
new file mode 100644
index 0000000..e892296
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/api/introspection.dart
@@ -0,0 +1,192 @@
+// Copyright (c) 2021, 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.
+
+part of '../api.dart';
+
+/// The base class for an unresolved reference to a type.
+///
+/// See the subtypes [FunctionTypeAnnotation] and [NamedTypeAnnotation].
+abstract class TypeAnnotation {
+ /// Whether or not the type annotation is explicitly nullable (contains a
+ /// trailing `?`)
+ bool get isNullable;
+
+ /// A [Code] object representation of this type annotation.
+ Code get code;
+}
+
+/// The base class for function type declarations.
+abstract class FunctionTypeAnnotation implements TypeAnnotation {
+ /// The return type of this function.
+ TypeAnnotation get returnType;
+
+ /// The positional parameters for this function.
+ Iterable<ParameterDeclaration> get positionalParameters;
+
+ /// The named parameters for this function.
+ Iterable<ParameterDeclaration> get namedParameters;
+
+ /// The type parameters for this function.
+ Iterable<TypeParameterDeclaration> get typeParameters;
+}
+
+/// An unresolved reference to a type.
+///
+/// These can be resolved to a [TypeDeclaration] using the `builder` classes
+/// depending on the phase a macro is running in.
+abstract class NamedTypeAnnotation implements TypeAnnotation {
+ /// The name of the type as it exists in the type annotation.
+ String get name;
+
+ /// The type arguments, if applicable.
+ Iterable<TypeAnnotation> get typeArguments;
+}
+
+/// The interface representing a resolved type.
+///
+/// Resolved types understand exactly what type they represent, and can be
+/// compared to other static types.
+abstract class StaticType {
+ /// Returns true if this is a subtype of [other].
+ Future<bool> isSubtypeOf(StaticType other);
+
+ /// Returns true if this is an identical type to [other].
+ Future<bool> isExactly(StaticType other);
+}
+
+/// A subtype of [StaticType] representing types that can be resolved by name
+/// to a concrete declaration.
+abstract class NamedStaticType implements StaticType {
+ String get name;
+}
+
+/// The base class for all declarations.
+abstract class Declaration {
+ /// The name of this declaration.
+ String get name;
+}
+
+/// A declaration that defines a new type in the program.
+abstract class TypeDeclaration implements Declaration {
+ /// The type parameters defined for this type declaration.
+ Iterable<TypeParameterDeclaration> get typeParameters;
+
+ /// Create a static type representing this type with [typeArguments].
+ ///
+ /// If [isNullable] is `true`, then this type will behave as if it has a
+ /// trailing `?`.
+ ///
+ /// Throws an exception if the type could not be instantiated, typically due
+ /// to one of the type arguments not matching the bounds of the corresponding
+ /// type parameter.
+ Future<StaticType> instantiate(
+ {required List<StaticType> typeArguments, required bool isNullable});
+}
+
+/// Class (and enum) introspection information.
+///
+/// Information about fields, methods, and constructors must be retrieved from
+/// the `builder` objects.
+abstract class ClassDeclaration implements TypeDeclaration {
+ /// Whether this class has an `abstract` modifier.
+ bool get isAbstract;
+
+ /// Whether this class has an `external` modifier.
+ bool get isExternal;
+
+ /// The `extends` type annotation, if present.
+ TypeAnnotation? get superclass;
+
+ /// All the `implements` type annotations.
+ Iterable<TypeAnnotation> get interfaces;
+
+ /// All the `with` type annotations.
+ Iterable<TypeAnnotation> get mixins;
+
+ /// All the type arguments, if applicable.
+ Iterable<TypeParameterDeclaration> get typeParameters;
+}
+
+/// Function introspection information.
+abstract class FunctionDeclaration implements Declaration {
+ /// Whether this function has an `abstract` modifier.
+ bool get isAbstract;
+
+ /// Whether this function has an `external` modifier.
+ bool get isExternal;
+
+ /// Whether this function is actually a getter.
+ bool get isGetter;
+
+ /// Whether this function is actually a setter.
+ bool get isSetter;
+
+ /// The return type of this function.
+ TypeAnnotation get returnType;
+
+ /// The positional parameters for this function.
+ Iterable<ParameterDeclaration> get positionalParameters;
+
+ /// The named parameters for this function.
+ Iterable<ParameterDeclaration> get namedParameters;
+
+ /// The type parameters for this function.
+ Iterable<TypeParameterDeclaration> get typeParameters;
+}
+
+/// Method introspection information.
+abstract class MethodDeclaration implements FunctionDeclaration {
+ /// The class that defines this method.
+ TypeAnnotation get definingClass;
+}
+
+/// Constructor introspection information.
+abstract class ConstructorDeclaration implements MethodDeclaration {
+ /// Whether or not this is a factory constructor.
+ bool get isFactory;
+}
+
+/// Variable introspection information.
+abstract class VariableDeclaration implements Declaration {
+ /// Whether this function has an `abstract` modifier.
+ bool get isAbstract;
+
+ /// Whether this function has an `external` modifier.
+ bool get isExternal;
+
+ /// The type of this field.
+ TypeAnnotation get type;
+
+ /// A [Code] object representing the initializer for this field, if present.
+ Code? get initializer;
+}
+
+/// Field introspection information ..
+abstract class FieldDeclaration implements VariableDeclaration {
+ /// The class that defines this method.
+ TypeAnnotation get definingClass;
+}
+
+/// Parameter introspection information.
+abstract class ParameterDeclaration implements Declaration {
+ /// The type of this parameter.
+ TypeAnnotation get type;
+
+ /// Whether or not this is a named parameter.
+ bool get isNamed;
+
+ /// Whether or not this parameter is either a non-optional positional
+ /// parameter or an optional parameter with the `required` keyword.
+ bool get isRequired;
+
+ /// A [Code] object representing the default value for this parameter, if
+ /// present. Can be used to copy default values to other parameters.
+ Code? get defaultValue;
+}
+
+/// Type parameter introspection information.
+abstract class TypeParameterDeclaration implements Declaration {
+ /// The bounds for this type parameter, if it has any.
+ TypeAnnotation? get bounds;
+}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/api/macros.dart b/pkg/_fe_analyzer_shared/lib/src/macros/api/macros.dart
new file mode 100644
index 0000000..7685589a
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/api/macros.dart
@@ -0,0 +1,139 @@
+// Copyright (c) 2021, 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.
+
+part of '../api.dart';
+
+/// The marker interface for all types of macros.
+abstract class Macro {}
+
+/// The interface for [Macro]s that can be applied to any top level function,
+/// instance method, or static method, and wants to contribute new type
+/// declarations to the program.
+abstract class FunctionTypesMacro implements Macro {
+ FutureOr<void> buildTypesForFunction(
+ FunctionDeclaration function, TypeBuilder builder);
+}
+
+/// The interface for [Macro]s that can be applied to any top level function,
+/// instance method, or static method, and wants to contribute new non-type
+/// declarations to the program.
+abstract class FunctionDeclarationsMacro implements Macro {
+ FutureOr<void> buildDeclarationsForFunction(
+ FunctionDeclaration function, DeclarationBuilder builder);
+}
+
+/// The interface for [Macro]s that can be applied to any top level function,
+/// instance method, or static method, and wants to augment the function
+/// definition.
+abstract class FunctionDefinitionMacro implements Macro {
+ FutureOr<void> buildDefinitionForFunction(
+ FunctionDeclaration function, FunctionDefinitionBuilder builder);
+}
+
+/// The interface for [Macro]s that can be applied to any top level variable or
+/// instance field, and wants to contribute new type declarations to the
+/// program.
+abstract class VariableTypesMacro implements Macro {
+ FutureOr<void> buildTypesForVariable(
+ VariableDeclaration variable, TypeBuilder builder);
+}
+
+/// The interface for [Macro]s that can be applied to any top level variable or
+/// instance field and wants to contribute new non-type declarations to the
+/// program.
+abstract class VariableDeclarationsMacro implements Macro {
+ FutureOr<void> buildDeclarationsForVariable(
+ VariableDeclaration variable, DeclarationBuilder builder);
+}
+
+/// The interface for [Macro]s that can be applied to any top level variable
+/// or instance field, and wants to augment the variable definition.
+abstract class VariableDefinitionMacro implements Macro {
+ FutureOr<void> buildDefinitionForFunction(
+ VariableDeclaration variable, VariableDefinitionBuilder builder);
+}
+
+/// The interface for [Macro]s that can be applied to any class, and wants to
+/// contribute new type declarations to the program.
+abstract class ClassTypesMacro implements Macro {
+ FutureOr<void> buildTypesForClass(
+ ClassDeclaration clazz, TypeBuilder builder);
+}
+
+/// The interface for [Macro]s that can be applied to any class, and wants to
+/// contribute new non-type declarations to the program.
+abstract class ClassDeclarationsMacro implements Macro {
+ FutureOr<void> buildDeclarationsForClass(
+ ClassDeclaration clazz, ClassDeclarationBuilder builder);
+}
+
+/// The interface for [Macro]s that can be applied to any class, and wants to
+/// augment the definitions of members on the class.
+abstract class ClassDefinitionMacro implements Macro {
+ FutureOr<void> buildDefinitionForClass(
+ ClassDeclaration clazz, ClassDefinitionBuilder builder);
+}
+
+/// The interface for [Macro]s that can be applied to any field, and wants to
+/// contribute new type declarations to the program.
+abstract class FieldTypesMacro implements Macro {
+ FutureOr<void> buildTypesForField(
+ FieldDeclaration field, TypeBuilder builder);
+}
+
+/// The interface for [Macro]s that can be applied to any field, and wants to
+/// contribute new type declarations to the program.
+abstract class FieldDeclarationsMacro implements Macro {
+ FutureOr<void> buildTypesForField(
+ FieldDeclaration field, ClassMemberDeclarationBuilder builder);
+}
+
+/// The interface for [Macro]s that can be applied to any field, and wants to
+/// augment the field definition.
+abstract class FieldDefinitionsMacro implements Macro {
+ FutureOr<void> buildDefinitionForField(
+ FieldDeclaration field, VariableDefinitionBuilder builder);
+}
+
+/// The interface for [Macro]s that can be applied to any method, and wants to
+/// contribute new type declarations to the program.
+abstract class MethodTypesMacro implements Macro {
+ FutureOr<void> buildTypesForMethod(
+ MethodDeclaration method, TypeBuilder builder);
+}
+
+/// The interface for [Macro]s that can be applied to any method, and wants to
+/// contribute new non-type declarations to the program.
+abstract class MethodDeclarationDeclarationsMacro implements Macro {
+ FutureOr<void> buildDeclarationsForMethod(
+ MethodDeclaration method, ClassMemberDeclarationBuilder builder);
+}
+
+/// The interface for [Macro]s that can be applied to any method, and wants to
+/// augment the function definition.
+abstract class MethodDefinitionMacro implements Macro {
+ FutureOr<void> buildDefinitionForMethod(
+ MethodDeclaration method, FunctionDefinitionBuilder builder);
+}
+
+/// The interface for [Macro]s that can be applied to any constructor, and wants
+/// to contribute new type declarations to the program.
+abstract class ConstructorTypesMacro implements Macro {
+ FutureOr<void> buildTypesForConstructor(
+ ConstructorDeclaration method, TypeBuilder builder);
+}
+
+/// The interface for [Macro]s that can be applied to any constructors, and
+/// wants to contribute new non-type declarations to the program.
+abstract class ConstructorDeclarationDeclarationsMacro implements Macro {
+ FutureOr<void> buildDeclarationsForConstructor(
+ ConstructorDeclaration method, ClassMemberDeclarationBuilder builder);
+}
+
+/// The interface for [Macro]s that can be applied to any constructor, and wants
+/// to augment the function definition.
+abstract class ConstructorDefinitionMacro implements Macro {
+ FutureOr<void> buildDefinitionForConstructor(
+ ConstructorDeclaration method, ConstructorDefinitionBuilder builder);
+}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart
new file mode 100644
index 0000000..0d4e878
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart
@@ -0,0 +1,115 @@
+// Copyright (c) 2021, 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.
+
+import 'api.dart';
+
+/// The interface used by Dart language implementations, in order to load
+/// and execute macros, as well as produce library augmentations from those
+/// macro applications.
+///
+/// This class more clearly defines the role of a Dart language implementation
+/// during macro discovery and expansion, and unifies how augmentation libraries
+/// are produced.
+abstract class MacroExecutor {
+ /// Invoked when an implementation discovers a new macro definition in a
+ /// [library] with [name], and prepares this executor to run the macro.
+ ///
+ /// May be invoked more than once for the same macro, which will cause the
+ /// macro to be re-loaded. Previous [MacroClassIdentifier]s and
+ /// [MacroInstanceIdentifier]s given for this macro will be invalid after
+ /// that point and should be discarded.
+ ///
+ /// Throws an exception if the macro fails to load.
+ Future<MacroClassIdentifier> loadMacro(Uri library, String name);
+
+ /// Creates an instance of [macroClass] in the executor, and returns an
+ /// identifier for that instance.
+ ///
+ /// Throws an exception if an instance is not created.
+ Future<MacroInstanceIdentifier> instantiateMacro(
+ MacroClassIdentifier macroClass, String constructor, Arguments arguments);
+
+ /// Runs the type phase for [macro] on a given [declaration].
+ ///
+ /// Throws an exception if there is an error executing the macro.
+ Future<MacroExecutionResult> executeTypesPhase(
+ MacroInstanceIdentifier macro, Declaration declaration);
+
+ /// Runs the declarations phase for [macro] on a given [declaration].
+ ///
+ /// Throws an exception if there is an error executing the macro.
+ Future<MacroExecutionResult> executeDeclarationsPhase(
+ MacroInstanceIdentifier macro,
+ Declaration declaration,
+ TypeResolver typeResolver,
+ ClassIntrospector classIntrospector);
+
+ /// Runs the definitions phase for [macro] on a given [declaration].
+ ///
+ /// Throws an exception if there is an error executing the macro.
+ Future<MacroExecutionResult> executeDefinitionsPhase(
+ MacroInstanceIdentifier macro,
+ Declaration declaration,
+ TypeResolver typeResolver,
+ ClassIntrospector classIntrospector,
+ TypeDeclarationResolver typeDeclarationResolver);
+
+ /// Combines multiple [MacroExecutionResult]s into a single library
+ /// augmentation file, and returns a [String] representing that file.
+ Future<String> buildAugmentationLibrary(
+ Iterable<MacroExecutionResult> macroResults);
+
+ /// Tell the executor to shut down and clean up any resources it may have
+ /// allocated.
+ void close();
+}
+
+/// The arguments passed to a macro constructor.
+///
+/// All argument instances must be of type [Code] or a built-in value type that
+/// is serializable (num, bool, String, null, etc).
+class Arguments {
+ final List<Object?> positional;
+
+ final Map<String, Object?> named;
+
+ Arguments(this.positional, this.named);
+}
+
+/// An opaque identifier for a macro class, retrieved by
+/// [MacroExecutor.loadMacro].
+///
+/// Used to execute or reload this macro in the future.
+abstract class MacroClassIdentifier {}
+
+/// An opaque identifier for an instance of a macro class, retrieved by
+/// [MacroExecutor.instantiateMacro].
+///
+/// Used to execute or reload this macro in the future.
+abstract class MacroInstanceIdentifier {}
+
+/// A summary of the results of running a macro in a given phase.
+///
+/// All modifications are expressed in terms of library augmentation
+/// declarations.
+abstract class MacroExecutionResult {
+ /// Any library imports that should be added to support the code used in
+ /// the augmentations.
+ Iterable<DeclarationCode> get imports;
+
+ /// Any augmentations that should be applied as a result of executing a macro.
+ Iterable<DeclarationCode> get augmentations;
+}
+
+/// Each of the different macro execution phases.
+enum Phase {
+ /// Only new types are added in this phase.
+ types,
+
+ /// New non-type declarations are added in this phase.
+ declarations,
+
+ /// This phase allows augmenting existing declarations.
+ definitions,
+}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/isolate_mirrors_executor/isolate_mirrors_executor.dart b/pkg/_fe_analyzer_shared/lib/src/macros/isolate_mirrors_executor/isolate_mirrors_executor.dart
new file mode 100644
index 0000000..d6476af
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/isolate_mirrors_executor/isolate_mirrors_executor.dart
@@ -0,0 +1,137 @@
+// Copyright (c) 2021, 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.
+
+import 'dart:async';
+import 'dart:isolate';
+import 'dart:mirrors';
+
+import 'isolate_mirrors_impl.dart';
+import 'protocol.dart';
+import '../executor.dart';
+import '../api.dart';
+
+/// A [MacroExecutor] implementation which relies on [IsolateMirror.loadUri]
+/// in order to load macros libraries.
+///
+/// All actual work happens in a separate [Isolate], and this class serves as
+/// a bridge between that isolate and the language frontends.
+class IsolateMirrorMacroExecutor implements MacroExecutor {
+ /// The actual isolate doing macro loading and execution.
+ final Isolate _macroIsolate;
+
+ /// The channel used to send requests to the [_macroIsolate].
+ final SendPort _sendPort;
+
+ /// The stream of responses from the [_macroIsolate].
+ final Stream<GenericResponse> _responseStream;
+
+ /// A map of response completers by request id.
+ final _responseCompleters = <int, Completer<GenericResponse>>{};
+
+ /// A function that should be invoked when shutting down this executor
+ /// to perform any necessary cleanup.
+ final void Function() _onClose;
+
+ IsolateMirrorMacroExecutor._(
+ this._macroIsolate, this._sendPort, this._responseStream, this._onClose) {
+ _responseStream.listen((event) {
+ Completer<GenericResponse>? completer =
+ _responseCompleters.remove(event.requestId);
+ if (completer == null) {
+ throw new StateError(
+ 'Got a response for an unrecognized request id ${event.requestId}');
+ }
+ completer.complete(event);
+ });
+ }
+
+ /// Initialize an [IsolateMirrorMacroExecutor] and return it once ready.
+ ///
+ /// Spawns the macro isolate and sets up a communication channel.
+ static Future<MacroExecutor> start() async {
+ ReceivePort receivePort = new ReceivePort();
+ Completer<SendPort> sendPortCompleter = new Completer<SendPort>();
+ StreamController<GenericResponse> responseStreamController =
+ new StreamController<GenericResponse>(sync: true);
+ receivePort.listen((message) {
+ if (!sendPortCompleter.isCompleted) {
+ sendPortCompleter.complete(message as SendPort);
+ } else {
+ responseStreamController.add(message as GenericResponse);
+ }
+ }).onDone(responseStreamController.close);
+ Isolate macroIsolate = await Isolate.spawn(spawn, receivePort.sendPort);
+
+ return new IsolateMirrorMacroExecutor._(
+ macroIsolate,
+ await sendPortCompleter.future,
+ responseStreamController.stream,
+ receivePort.close);
+ }
+
+ @override
+ Future<String> buildAugmentationLibrary(
+ Iterable<MacroExecutionResult> macroResults) {
+ // TODO: implement buildAugmentationLibrary
+ throw new UnimplementedError();
+ }
+
+ @override
+ void close() {
+ _onClose();
+ _macroIsolate.kill();
+ }
+
+ @override
+ Future<MacroExecutionResult> executeDeclarationsPhase(
+ MacroInstanceIdentifier macro,
+ Declaration declaration,
+ TypeResolver typeResolver,
+ ClassIntrospector classIntrospector) {
+ // TODO: implement executeDeclarationsPhase
+ throw new UnimplementedError();
+ }
+
+ @override
+ Future<MacroExecutionResult> executeDefinitionsPhase(
+ MacroInstanceIdentifier macro,
+ Declaration declaration,
+ TypeResolver typeResolver,
+ ClassIntrospector classIntrospector,
+ TypeDeclarationResolver typeDeclarationResolver) =>
+ _sendRequest(new ExecuteDefinitionsPhaseRequest(macro, declaration,
+ typeResolver, classIntrospector, typeDeclarationResolver));
+
+ @override
+ Future<MacroExecutionResult> executeTypesPhase(
+ MacroInstanceIdentifier macro, Declaration declaration) {
+ // TODO: implement executeTypesPhase
+ throw new UnimplementedError();
+ }
+
+ @override
+ Future<MacroInstanceIdentifier> instantiateMacro(
+ MacroClassIdentifier macroClass,
+ String constructor,
+ Arguments arguments) =>
+ _sendRequest(
+ new InstantiateMacroRequest(macroClass, constructor, arguments));
+
+ @override
+ Future<MacroClassIdentifier> loadMacro(Uri library, String name) =>
+ _sendRequest(new LoadMacroRequest(library, name));
+
+ /// Sends a request and returns the response, casting it to the expected
+ /// type.
+ Future<T> _sendRequest<T>(Request request) async {
+ _sendPort.send(request);
+ Completer<GenericResponse<T>> completer =
+ new Completer<GenericResponse<T>>();
+ _responseCompleters[request.id] = completer;
+ GenericResponse<T> response = await completer.future;
+ T? result = response.response;
+ if (result != null) return result;
+ throw response.error!;
+ }
+}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/isolate_mirrors_executor/isolate_mirrors_impl.dart b/pkg/_fe_analyzer_shared/lib/src/macros/isolate_mirrors_executor/isolate_mirrors_impl.dart
new file mode 100644
index 0000000..3cf24a5
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/isolate_mirrors_executor/isolate_mirrors_impl.dart
@@ -0,0 +1,255 @@
+// Copyright (c) 2021, 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.
+
+import 'dart:async';
+import 'dart:isolate';
+import 'dart:mirrors';
+
+import 'protocol.dart';
+import '../executor.dart';
+import '../api.dart';
+
+/// Spawns a new isolate for loading and executing macros.
+void spawn(SendPort sendPort) {
+ ReceivePort receivePort = new ReceivePort();
+ sendPort.send(receivePort.sendPort);
+ receivePort.listen((message) async {
+ if (message is LoadMacroRequest) {
+ GenericResponse<MacroClassIdentifier> response =
+ await _loadMacro(message);
+ sendPort.send(response);
+ } else if (message is InstantiateMacroRequest) {
+ GenericResponse<MacroInstanceIdentifier> response =
+ await _instantiateMacro(message);
+ sendPort.send(response);
+ } else if (message is ExecuteDefinitionsPhaseRequest) {
+ GenericResponse<MacroExecutionResult> response =
+ await _executeDefinitionsPhase(message);
+ sendPort.send(response);
+ } else {
+ throw new StateError('Unrecognized event type $message');
+ }
+ });
+}
+
+/// Maps macro identifiers to class mirrors.
+final _macroClasses = <_MacroClassIdentifier, ClassMirror>{};
+
+/// Handles [LoadMacroRequest]s.
+Future<GenericResponse<MacroClassIdentifier>> _loadMacro(
+ LoadMacroRequest request) async {
+ try {
+ _MacroClassIdentifier identifier =
+ new _MacroClassIdentifier(request.library, request.name);
+ if (_macroClasses.containsKey(identifier)) {
+ throw new UnsupportedError(
+ 'Reloading macros is not supported by this implementation');
+ }
+ LibraryMirror libMirror =
+ await currentMirrorSystem().isolate.loadUri(request.library);
+ ClassMirror macroClass =
+ libMirror.declarations[new Symbol(request.name)] as ClassMirror;
+ _macroClasses[identifier] = macroClass;
+ return new GenericResponse(response: identifier, requestId: request.id);
+ } catch (e) {
+ return new GenericResponse(error: e, requestId: request.id);
+ }
+}
+
+/// Maps macro instance identifiers to instances.
+final _macroInstances = <_MacroInstanceIdentifier, Macro>{};
+
+/// Handles [InstantiateMacroRequest]s.
+Future<GenericResponse<MacroInstanceIdentifier>> _instantiateMacro(
+ InstantiateMacroRequest request) async {
+ try {
+ ClassMirror? clazz = _macroClasses[request.macroClass];
+ if (clazz == null) {
+ throw new ArgumentError('Unrecognized macro class ${request.macroClass}');
+ }
+ Macro instance = clazz.newInstance(
+ new Symbol(request.constructorName), request.arguments.positional, {
+ for (MapEntry<String, Object?> entry in request.arguments.named.entries)
+ new Symbol(entry.key): entry.value,
+ }).reflectee as Macro;
+ _MacroInstanceIdentifier identifier = new _MacroInstanceIdentifier();
+ _macroInstances[identifier] = instance;
+ return new GenericResponse<MacroInstanceIdentifier>(
+ response: identifier, requestId: request.id);
+ } catch (e) {
+ return new GenericResponse(error: e, requestId: request.id);
+ }
+}
+
+Future<GenericResponse<MacroExecutionResult>> _executeDefinitionsPhase(
+ ExecuteDefinitionsPhaseRequest request) async {
+ try {
+ Macro? instance = _macroInstances[request.macro];
+ if (instance == null) {
+ throw new StateError('Unrecognized macro instance ${request.macro}\n'
+ 'Known instances: $_macroInstances)');
+ }
+ Declaration declaration = request.declaration;
+ if (instance is FunctionDefinitionMacro &&
+ declaration is FunctionDeclaration) {
+ _FunctionDefinitionBuilder builder = new _FunctionDefinitionBuilder(
+ declaration,
+ request.typeResolver,
+ request.typeDeclarationResolver,
+ request.classIntrospector);
+ await instance.buildDefinitionForFunction(declaration, builder);
+ return new GenericResponse(
+ response: builder.result, requestId: request.id);
+ } else {
+ throw new UnsupportedError(
+ ('Only FunctionDefinitionMacros are supported currently'));
+ }
+ } catch (e) {
+ return new GenericResponse(error: e, requestId: request.id);
+ }
+}
+
+/// Our implementation of [MacroClassIdentifier].
+class _MacroClassIdentifier implements MacroClassIdentifier {
+ final String id;
+
+ _MacroClassIdentifier(Uri library, String name) : id = '$library#$name';
+
+ operator ==(other) => other is _MacroClassIdentifier && id == other.id;
+
+ int get hashCode => id.hashCode;
+}
+
+/// Our implementation of [MacroInstanceIdentifier].
+class _MacroInstanceIdentifier implements MacroInstanceIdentifier {
+ static int _next = 0;
+
+ final int id;
+
+ _MacroInstanceIdentifier() : id = _next++;
+
+ operator ==(other) => other is _MacroInstanceIdentifier && id == other.id;
+
+ int get hashCode => id;
+}
+
+/// Our implementation of [MacroExecutionResult].
+class _MacroExecutionResult implements MacroExecutionResult {
+ @override
+ final List<DeclarationCode> augmentations = <DeclarationCode>[];
+
+ @override
+ final List<DeclarationCode> imports = <DeclarationCode>[];
+}
+
+/// Custom implementation of [FunctionDefinitionBuilder].
+class _FunctionDefinitionBuilder implements FunctionDefinitionBuilder {
+ final TypeResolver typeResolver;
+ final TypeDeclarationResolver typeDeclarationResolver;
+ final ClassIntrospector classIntrospector;
+
+ /// The declaration this is a builder for.
+ final FunctionDeclaration declaration;
+
+ /// The final result, will be built up over `augment` calls.
+ final _MacroExecutionResult result = new _MacroExecutionResult();
+
+ _FunctionDefinitionBuilder(this.declaration, this.typeResolver,
+ this.typeDeclarationResolver, this.classIntrospector);
+
+ @override
+ void augment(FunctionBodyCode body) {
+ result.augmentations.add(new DeclarationCode.fromParts([
+ 'augment ',
+ declaration.returnType.code,
+ ' ',
+ declaration.name,
+ if (declaration.typeParameters.isNotEmpty) ...[
+ '<',
+ for (TypeParameterDeclaration typeParam
+ in declaration.typeParameters) ...[
+ typeParam.name,
+ if (typeParam.bounds != null) ...['extends ', typeParam.bounds!.code],
+ if (typeParam != declaration.typeParameters.last) ', ',
+ ],
+ '>',
+ ],
+ '(',
+ for (ParameterDeclaration positionalRequired
+ in declaration.positionalParameters.where((p) => p.isRequired)) ...[
+ new ParameterCode.fromParts([
+ positionalRequired.type.code,
+ ' ',
+ positionalRequired.name,
+ ]),
+ ', '
+ ],
+ if (declaration.positionalParameters.any((p) => !p.isRequired)) ...[
+ '[',
+ for (ParameterDeclaration positionalOptional in declaration
+ .positionalParameters
+ .where((p) => !p.isRequired)) ...[
+ new ParameterCode.fromParts([
+ positionalOptional.type.code,
+ ' ',
+ positionalOptional.name,
+ ]),
+ ', ',
+ ],
+ ']',
+ ],
+ if (declaration.namedParameters.isNotEmpty) ...[
+ '{',
+ for (ParameterDeclaration named in declaration.namedParameters) ...[
+ new ParameterCode.fromParts([
+ if (named.isRequired) 'required ',
+ named.type.code,
+ ' ',
+ named.name,
+ if (named.defaultValue != null) ...[
+ ' = ',
+ named.defaultValue!,
+ ],
+ ]),
+ ', ',
+ ],
+ '}',
+ ],
+ ') ',
+ body,
+ ]));
+ }
+
+ @override
+ Future<List<ConstructorDeclaration>> constructorsOf(ClassDeclaration clazz) =>
+ classIntrospector.constructorsOf(clazz);
+
+ @override
+ Future<List<FieldDeclaration>> fieldsOf(ClassDeclaration clazz) =>
+ classIntrospector.fieldsOf(clazz);
+
+ @override
+ Future<List<ClassDeclaration>> interfacesOf(ClassDeclaration clazz) =>
+ classIntrospector.interfacesOf(clazz);
+
+ @override
+ Future<List<MethodDeclaration>> methodsOf(ClassDeclaration clazz) =>
+ classIntrospector.methodsOf(clazz);
+
+ @override
+ Future<List<ClassDeclaration>> mixinsOf(ClassDeclaration clazz) =>
+ classIntrospector.mixinsOf(clazz);
+
+ @override
+ Future<TypeDeclaration> declarationOf(NamedStaticType annotation) =>
+ typeDeclarationResolver.declarationOf(annotation);
+
+ @override
+ Future<ClassDeclaration?> superclassOf(ClassDeclaration clazz) =>
+ classIntrospector.superclassOf(clazz);
+
+ @override
+ Future<StaticType> resolve(TypeAnnotation typeAnnotation) =>
+ typeResolver.resolve(typeAnnotation);
+}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/isolate_mirrors_executor/protocol.dart b/pkg/_fe_analyzer_shared/lib/src/macros/isolate_mirrors_executor/protocol.dart
new file mode 100644
index 0000000..96a2724
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/isolate_mirrors_executor/protocol.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2021, 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.
+
+/// Defines the objects used for communication between the macro executor and
+/// the isolate doing the work of macro loading and execution.
+library protocol;
+
+import '../executor.dart';
+import '../api.dart';
+
+/// Base class all requests extend, provides a unique id for each request.
+class Request {
+ final int id;
+
+ Request() : id = _next++;
+
+ static int _next = 0;
+}
+
+/// A generic response object that is either an instance of [T] or an error.
+class GenericResponse<T> {
+ final T? response;
+ final Object? error;
+ final int requestId;
+
+ GenericResponse({this.response, this.error, required this.requestId})
+ : assert(response != null || error != null),
+ assert(response == null || error == null);
+}
+
+/// A request to load a macro in this isolate.
+class LoadMacroRequest extends Request {
+ final Uri library;
+ final String name;
+
+ LoadMacroRequest(this.library, this.name);
+}
+
+/// A request to instantiate a macro instance.
+class InstantiateMacroRequest extends Request {
+ final MacroClassIdentifier macroClass;
+ final String constructorName;
+ final Arguments arguments;
+
+ InstantiateMacroRequest(
+ this.macroClass, this.constructorName, this.arguments);
+}
+
+/// A request to execute a macro on a particular declaration in the definition
+/// phase.
+class ExecuteDefinitionsPhaseRequest extends Request {
+ final MacroInstanceIdentifier macro;
+ final Declaration declaration;
+ final TypeResolver typeResolver;
+ final ClassIntrospector classIntrospector;
+ final TypeDeclarationResolver typeDeclarationResolver;
+
+ ExecuteDefinitionsPhaseRequest(this.macro, this.declaration,
+ this.typeResolver, this.classIntrospector, this.typeDeclarationResolver);
+}
diff --git a/pkg/_fe_analyzer_shared/test/macros/isolate_mirror_executor/isolate_mirror_executor_test.dart b/pkg/_fe_analyzer_shared/test/macros/isolate_mirror_executor/isolate_mirror_executor_test.dart
new file mode 100644
index 0000000..48ca97b
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/macros/isolate_mirror_executor/isolate_mirror_executor_test.dart
@@ -0,0 +1,147 @@
+// Copyright (c) 2021, 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.
+
+import 'dart:io';
+
+import 'package:_fe_analyzer_shared/src/macros/api.dart';
+import 'package:_fe_analyzer_shared/src/macros/executor.dart';
+import 'package:_fe_analyzer_shared/src/macros/isolate_mirrors_executor/isolate_mirrors_executor.dart';
+
+import 'package:test/fake.dart';
+import 'package:test/test.dart';
+
+void main() {
+ late MacroExecutor executor;
+
+ setUp(() async {
+ executor = await IsolateMirrorMacroExecutor.start();
+ });
+
+ tearDown(() {
+ executor.close();
+ });
+
+ test('can load macros and create instances', () async {
+ var clazzId = await executor.loadMacro(
+ // Tests run from the root of the repo.
+ File('pkg/_fe_analyzer_shared/test/macros/isolate_mirror_executor/simple_macro.dart')
+ .absolute
+ .uri,
+ 'SimpleMacro');
+ expect(clazzId, isNotNull, reason: 'Can load a macro.');
+
+ var instanceId =
+ await executor.instantiateMacro(clazzId, '', Arguments([], {}));
+ expect(instanceId, isNotNull,
+ reason: 'Can create an instance with no arguments.');
+
+ instanceId =
+ await executor.instantiateMacro(clazzId, '', Arguments([1, 2], {}));
+ expect(instanceId, isNotNull,
+ reason: 'Can create an instance with positional arguments.');
+
+ instanceId = await executor.instantiateMacro(
+ clazzId, 'named', Arguments([], {'x': 1, 'y': 2}));
+ expect(instanceId, isNotNull,
+ reason: 'Can create an instance with named arguments.');
+
+ var definitionResult = await executor.executeDefinitionsPhase(
+ instanceId,
+ _FunctionDeclaration(
+ isAbstract: false,
+ isExternal: false,
+ isGetter: false,
+ isSetter: false,
+ name: 'foo',
+ namedParameters: [],
+ positionalParameters: [],
+ returnType:
+ _TypeAnnotation(Code.fromString('String'), isNullable: false),
+ typeParameters: [],
+ ),
+ _FakeTypeResolver(),
+ _FakeClassIntrospector(),
+ _FakeTypeDeclarationResolver());
+ expect(definitionResult.augmentations, hasLength(1));
+ expect(definitionResult.augmentations.first.debugString().toString(),
+ equalsIgnoringWhitespace('''
+ augment String foo() {
+ print('x: 1, y: 2');
+ return augment super();
+ }'''));
+ });
+}
+
+class _FakeClassIntrospector with Fake implements ClassIntrospector {}
+
+class _FakeTypeResolver with Fake implements TypeResolver {}
+
+class _FakeTypeDeclarationResolver
+ with Fake
+ implements TypeDeclarationResolver {}
+
+class _FunctionDeclaration implements FunctionDeclaration {
+ @override
+ final bool isAbstract;
+
+ @override
+ final bool isExternal;
+
+ @override
+ final bool isGetter;
+
+ @override
+ final bool isSetter;
+
+ @override
+ final String name;
+
+ @override
+ final Iterable<ParameterDeclaration> namedParameters;
+
+ @override
+ final Iterable<ParameterDeclaration> positionalParameters;
+
+ @override
+ final TypeAnnotation returnType;
+
+ @override
+ final Iterable<TypeParameterDeclaration> typeParameters;
+
+ _FunctionDeclaration({
+ required this.isAbstract,
+ required this.isExternal,
+ required this.isGetter,
+ required this.isSetter,
+ required this.name,
+ required this.namedParameters,
+ required this.positionalParameters,
+ required this.returnType,
+ required this.typeParameters,
+ });
+}
+
+class _TypeAnnotation implements TypeAnnotation {
+ @override
+ final Code code;
+
+ @override
+ final bool isNullable;
+
+ _TypeAnnotation(this.code, {required this.isNullable});
+}
+
+extension _ on Code {
+ StringBuffer debugString([StringBuffer? buffer]) {
+ buffer ??= StringBuffer();
+ for (var part in parts) {
+ if (part is Code) {
+ part.debugString(buffer);
+ } else {
+ buffer.write(part.toString());
+ }
+ }
+ return buffer;
+ }
+}
diff --git a/pkg/_fe_analyzer_shared/test/macros/isolate_mirror_executor/simple_macro.dart b/pkg/_fe_analyzer_shared/test/macros/isolate_mirror_executor/simple_macro.dart
new file mode 100644
index 0000000..b95da0b
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/macros/isolate_mirror_executor/simple_macro.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2021, 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.
+
+import 'dart:async';
+
+import 'package:_fe_analyzer_shared/src/macros/api.dart';
+
+/// A very simple macro that annotates functions (or getters) with no arguments
+/// and adds a print statement to the top of them.
+class SimpleMacro implements FunctionDefinitionMacro {
+ final int? x;
+ final int? y;
+
+ SimpleMacro([this.x, this.y]);
+
+ SimpleMacro.named({this.x, this.y});
+
+ @override
+ FutureOr<void> buildDefinitionForFunction(
+ FunctionDeclaration method, FunctionDefinitionBuilder builder) {
+ if (method.namedParameters
+ .followedBy(method.positionalParameters)
+ .isNotEmpty) {
+ throw ArgumentError(
+ 'This macro can only be run on functions with no arguments!');
+ }
+ builder.augment(FunctionBodyCode.fromString('''{
+ print('x: $x, y: $y');
+ return augment super();
+ }'''));
+ }
+}
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index a132ce2..81e6368 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -47,6 +47,7 @@
anyone
ap
api
+apis
app
apparently
applicable
@@ -73,6 +74,11 @@
atom
atoms
attributes
+augment
+augmentation
+augmentations
+augmenting
+augments
auto
automagically
auxiliary
@@ -140,6 +146,7 @@
breadcrumbs
brevity
brianwilkerson
+bridge
bs
bsd
bslash
@@ -225,15 +232,18 @@
combinator
combine2
combiner
+communication
compared
compares
compilations
+completers
completes
complicating
component's
comprehensive
compressed
compression
+comprise
concat
concatenate
concerned
@@ -252,6 +262,7 @@
containers
continuations
contra
+contribute
convention
coordinated
coordinating
@@ -310,6 +321,7 @@
deeply
def
defaulting
+definitions
degrades
degree
del
@@ -353,6 +365,7 @@
disallow
disambiguating
disambiguator
+discovers
disjoint
dispatched
distribute
@@ -420,6 +433,7 @@
estimate
eval
execute
+executor
exhausted
existence
existentially
@@ -643,10 +657,14 @@
interval
intervals
intl
+introspect
+introspection
+introspector
ints
invariants
io
is64
+isolate
isolated
issuecomment
issuing
@@ -661,6 +679,7 @@
java
jenkins
jensj
+job
johnniwinther
js
json
@@ -672,6 +691,7 @@
kallentu
kernel's
kernel2kernel
+kill
klass
kmillikin
kotlin
@@ -707,6 +727,7 @@
libs
lifted
lifter
+limiting
linearized
linebreak
linter
@@ -948,6 +969,7 @@
preexisting
premark
preorder
+prepares
preprocess
presented
presubmit
@@ -966,10 +988,12 @@
promo
proof
prop
+proposal
propose
proposed
proto
protobuf
+protocol
ps
pulled
pure
@@ -1048,6 +1072,7 @@
reexports
ref
reflect
+reflectee
reflective
reg
regis
@@ -1063,6 +1088,8 @@
relaxes
released
relink
+reload
+reloading
remapped
remedy
removal
@@ -1079,11 +1106,14 @@
repo
repositories
repurposed
+requests
requirement
res
residue
resource
respond
+response
+responses
restoring
restriction
resumed
@@ -1131,11 +1161,13 @@
separators
sequencing
sequential
+serializable
serializables
serializer
serializers
serve
server
+serves
service
session
setable
@@ -1154,6 +1186,8 @@
shr
shrinking
shru
+shut
+shutting
si
sibling
siblings
@@ -1186,6 +1220,8 @@
sourcemap
spaced
sparse
+spawn
+spawns
spec
spec'ed
specialization
@@ -1384,6 +1420,7 @@
unifiable
unification
unifier
+unifies
unify
uninstantiable
uninstantiated
@@ -1456,6 +1493,7 @@
w
waiting
wanting
+wants
waste
wasted
watch