implement the remaining definition phase macros, as well as all declaration phase macros
Change-Id: I8ad1625d102cfbdafed020a7a1b88220e4e6a6bc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/229000
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Auto-Submit: Jake Macdonald <jakemac@google.com>
Commit-Queue: Jake Macdonald <jakemac@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/api/builders.dart b/pkg/_fe_analyzer_shared/lib/src/macros/api/builders.dart
index 2bfd7e8..868e62f 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/api/builders.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/api/builders.dart
@@ -87,11 +87,6 @@
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.
///
@@ -117,23 +112,25 @@
/// Retrieve a [VariableDefinitionBuilder] for a field by [name].
///
/// Throws an [ArgumentError] if there is no field by that name.
- VariableDefinitionBuilder buildField(String name);
+ Future<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);
+ Future<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);
+ Future<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].
+ /// Augments an existing constructor body with [body] and [initializers].
+ ///
+ /// The [initializers] should not contain trailing or preceding commas.
///
/// TODO: Link the library augmentations proposal to describe the semantics.
void augment({FunctionBodyCode? body, List<Code>? initializers});
@@ -151,6 +148,9 @@
abstract class VariableDefinitionBuilder implements DefinitionBuilder {
/// Augments the field.
///
+ /// For [getter] and [setter] the full function declaration should be
+ /// provided, minus the `augment` keyword (which will be implicitly added).
+ ///
/// TODO: Link the library augmentations proposal to describe the semantics.
void augment({
DeclarationCode? getter,
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/api/introspection.dart b/pkg/_fe_analyzer_shared/lib/src/macros/api/introspection.dart
index 10ccafa..fae7630 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/api/introspection.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/api/introspection.dart
@@ -69,6 +69,9 @@
///
/// See subtypes [ClassDeclaration] and [TypeAliasDeclaration].
abstract class TypeDeclaration implements Declaration {
+ // TODO: Change this to a [StaticType]? https://github.com/dart-lang/language/issues/2072
+ TypeAnnotation get type;
+
/// The type parameters defined for this type declaration.
Iterable<TypeParameterDeclaration> get typeParameters;
@@ -144,7 +147,7 @@
/// Method introspection information.
abstract class MethodDeclaration implements FunctionDeclaration {
/// The class that defines this method.
- TypeAnnotation get definingClass;
+ NamedTypeAnnotation get definingClass;
}
/// Constructor introspection information.
@@ -155,23 +158,27 @@
/// 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.
+ /// Whether this field has an `external` modifier.
bool get isExternal;
+ /// Whether this field has a `final` modifier.
+ bool get isFinal;
+
+ /// Whether this field has a `late` modifier.
+ bool get isLate;
+
/// The type of this field.
TypeAnnotation get type;
- /// A [Code] object representing the initializer for this field, if present.
- Code? get initializer;
+ /// A [ExpressionCode] object representing the initializer for this field, if
+ /// present.
+ ExpressionCode? get initializer;
}
/// Field introspection information ..
abstract class FieldDeclaration implements VariableDeclaration {
/// The class that defines this method.
- TypeAnnotation get definingClass;
+ NamedTypeAnnotation get definingClass;
}
/// Parameter introspection information.
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/api/macros.dart b/pkg/_fe_analyzer_shared/lib/src/macros/api/macros.dart
index 7685589a..5ab073a 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/api/macros.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/api/macros.dart
@@ -50,7 +50,7 @@
/// 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(
+ FutureOr<void> buildDefinitionForVariable(
VariableDeclaration variable, VariableDefinitionBuilder builder);
}
@@ -65,7 +65,7 @@
/// contribute new non-type declarations to the program.
abstract class ClassDeclarationsMacro implements Macro {
FutureOr<void> buildDeclarationsForClass(
- ClassDeclaration clazz, ClassDeclarationBuilder builder);
+ ClassDeclaration clazz, ClassMemberDeclarationBuilder builder);
}
/// The interface for [Macro]s that can be applied to any class, and wants to
@@ -85,13 +85,13 @@
/// 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(
+ FutureOr<void> buildDeclarationsForField(
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 {
+abstract class FieldDefinitionMacro implements Macro {
FutureOr<void> buildDefinitionForField(
FieldDeclaration field, VariableDefinitionBuilder builder);
}
@@ -105,7 +105,7 @@
/// 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 {
+abstract class MethodDeclarationsMacro implements Macro {
FutureOr<void> buildDeclarationsForMethod(
MethodDeclaration method, ClassMemberDeclarationBuilder builder);
}
@@ -121,19 +121,20 @@
/// to contribute new type declarations to the program.
abstract class ConstructorTypesMacro implements Macro {
FutureOr<void> buildTypesForConstructor(
- ConstructorDeclaration method, TypeBuilder builder);
+ ConstructorDeclaration constructor, 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 {
+abstract class ConstructorDeclarationsMacro implements Macro {
FutureOr<void> buildDeclarationsForConstructor(
- ConstructorDeclaration method, ClassMemberDeclarationBuilder builder);
+ ConstructorDeclaration constructor,
+ 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);
+ ConstructorDeclaration constructor, ConstructorDefinitionBuilder builder);
}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart b/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
index 4d2f6a1..1c50b6a 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
@@ -37,6 +37,7 @@
import 'dart:async';
import 'dart:isolate';
+import 'package:_fe_analyzer_shared/src/macros/executor_shared/execute_macro.dart';
import 'package:_fe_analyzer_shared/src/macros/executor_shared/introspection_impls.dart';
import 'package:_fe_analyzer_shared/src/macros/executor_shared/remote_instance.dart';
import 'package:_fe_analyzer_shared/src/macros/executor_shared/response_impls.dart';
@@ -70,6 +71,10 @@
var request = new InstantiateMacroRequest.deserialize(deserializer, zoneId);
(await _instantiateMacro(request)).serialize(serializer);
break;
+ case MessageType.executeDeclarationsPhaseRequest:
+ var request = new ExecuteDeclarationsPhaseRequest.deserialize(deserializer, zoneId);
+ (await _executeDeclarationsPhase(request, sendRequest)).serialize(serializer);
+ break;
case MessageType.executeDefinitionsPhaseRequest:
var request = new ExecuteDefinitionsPhaseRequest.deserialize(deserializer, zoneId);
(await _executeDefinitionsPhase(request, sendRequest)).serialize(serializer);
@@ -130,6 +135,41 @@
}
}
+Future<SerializableResponse> _executeDeclarationsPhase(
+ ExecuteDeclarationsPhaseRequest request,
+ Future<Response> Function(Request request) sendRequest) async {
+ try {
+ Macro? instance = _macroInstances[request.macro];
+ if (instance == null) {
+ throw new StateError('Unrecognized macro instance \${request.macro}\\n'
+ 'Known instances: \$_macroInstances)');
+ }
+ var classIntrospector = ClientClassIntrospector(
+ sendRequest,
+ remoteInstance: request.classIntrospector,
+ serializationZoneId: request.serializationZoneId);
+ var typeResolver = ClientTypeResolver(
+ sendRequest,
+ remoteInstance: request.typeResolver,
+ serializationZoneId: request.serializationZoneId);
+
+ var result = await executeDeclarationsMacro(
+ instance, request.declaration, classIntrospector, typeResolver);
+ return new SerializableResponse(
+ responseType: MessageType.macroExecutionResult,
+ response: result,
+ requestId: request.id,
+ serializationZoneId: request.serializationZoneId);
+ } catch (e, s) {
+ return new SerializableResponse(
+ responseType: MessageType.error,
+ error: e.toString(),
+ stackTrace: s.toString(),
+ requestId: request.id,
+ serializationZoneId: request.serializationZoneId);
+ }
+}
+
Future<SerializableResponse> _executeDefinitionsPhase(
ExecuteDefinitionsPhaseRequest request,
Future<Response> Function(Request request) sendRequest) async {
@@ -152,54 +192,14 @@
remoteInstance: request.classIntrospector,
serializationZoneId: request.serializationZoneId);
- Declaration declaration = request.declaration;
- if (instance is FunctionDefinitionMacro &&
- declaration is FunctionDeclarationImpl) {
- FunctionDefinitionBuilderImpl builder = new FunctionDefinitionBuilderImpl(
- declaration,
- typeResolver,
- typeDeclarationResolver,
- classIntrospector);
- await instance.buildDefinitionForFunction(declaration, builder);
- return new SerializableResponse(
- responseType: MessageType.macroExecutionResult,
- response: builder.result,
- requestId: request.id,
- serializationZoneId: request.serializationZoneId);
- } else if (instance is MethodDefinitionMacro
- && declaration is MethodDeclarationImpl) {
- FunctionDefinitionBuilderImpl builder = new FunctionDefinitionBuilderImpl(
- declaration,
- typeResolver,
- typeDeclarationResolver,
- classIntrospector);
- await instance.buildDefinitionForMethod(declaration, builder);
- var result = builder.result;
- // Wrap augmentations up as a part of the class
- if (result.augmentations.isNotEmpty) {
- result = MacroExecutionResultImpl(
- augmentations: [
- DeclarationCode.fromParts([
- 'augment class ',
- declaration.definingClass,
- ' {\\n',
- ...result.augmentations,
- '\\n}',
- ]),
- ],
- imports: result.imports,
- );
- }
- return new SerializableResponse(
- responseType: MessageType.macroExecutionResult,
- response: result,
- requestId: request.id,
- serializationZoneId: request.serializationZoneId);
- } else {
- throw new UnsupportedError(
- 'Unsupported macro type, only Method and Function Definition '
- 'Macros are supported currently');
- }
+ var result = await executeDefinitionMacro(
+ instance, request.declaration, classIntrospector, typeResolver,
+ typeDeclarationResolver);
+ return new SerializableResponse(
+ responseType: MessageType.macroExecutionResult,
+ response: result,
+ requestId: request.id,
+ serializationZoneId: request.serializationZoneId);
} catch (e, s) {
return new SerializableResponse(
responseType: MessageType.error,
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/builder_impls.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/builder_impls.dart
new file mode 100644
index 0000000..59a6376
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/builder_impls.dart
@@ -0,0 +1,398 @@
+// 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 '../executor.dart';
+import '../api.dart';
+import 'response_impls.dart';
+
+class TypeBuilderBase {
+ /// The final result, will be built up over `augment` calls.
+ final List<DeclarationCode> _augmentations;
+
+ /// Creates and returns a [MacroExecutionResult] out of the [_augmentations]
+ /// created by this builder.
+ MacroExecutionResult get result => new MacroExecutionResultImpl(
+ augmentations: _augmentations,
+ // TODO: Implement `imports`, or possibly drop it?
+ imports: [],
+ );
+
+ TypeBuilderBase({List<DeclarationCode>? parentAugmentations})
+ : _augmentations = parentAugmentations ?? [];
+}
+
+/// Base class for all [DeclarationBuilder]s.
+class DeclarationBuilderBase extends TypeBuilderBase
+ implements ClassIntrospector, TypeResolver {
+ final ClassIntrospector classIntrospector;
+ final TypeResolver typeResolver;
+
+ DeclarationBuilderBase(this.classIntrospector, this.typeResolver,
+ {List<DeclarationCode>? parentAugmentations})
+ : super(parentAugmentations: parentAugmentations);
+
+ @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<ClassDeclaration?> superclassOf(ClassDeclaration clazz) =>
+ classIntrospector.superclassOf(clazz);
+
+ @override
+ Future<StaticType> resolve(TypeAnnotation typeAnnotation) =>
+ typeResolver.resolve(typeAnnotation);
+}
+
+class DeclarationBuilderImpl extends DeclarationBuilderBase
+ implements DeclarationBuilder {
+ DeclarationBuilderImpl(
+ ClassIntrospector classIntrospector, TypeResolver typeResolver,
+ {List<DeclarationCode>? parentAugmentations})
+ : super(classIntrospector, typeResolver,
+ parentAugmentations: parentAugmentations);
+
+ @override
+ void declareInLibrary(DeclarationCode declaration) {
+ _augmentations.add(declaration);
+ }
+}
+
+class ClassMemberDeclarationBuilderImpl extends DeclarationBuilderImpl
+ implements ClassMemberDeclarationBuilder {
+ final TypeAnnotation definingClass;
+
+ ClassMemberDeclarationBuilderImpl(this.definingClass,
+ ClassIntrospector classIntrospector, TypeResolver typeResolver,
+ {List<DeclarationCode>? parentAugmentations})
+ : super(classIntrospector, typeResolver,
+ parentAugmentations: parentAugmentations);
+
+ @override
+ void declareInClass(DeclarationCode declaration) {
+ _augmentations.add(_buildClassAugmentation(definingClass, [declaration]));
+ }
+}
+
+/// Base class for all [DefinitionBuilder]s.
+class DefinitionBuilderBase extends DeclarationBuilderBase
+ implements TypeDeclarationResolver {
+ final TypeDeclarationResolver typeDeclarationResolver;
+
+ DefinitionBuilderBase(ClassIntrospector classIntrospector,
+ TypeResolver typeResolver, this.typeDeclarationResolver,
+ {List<DeclarationCode>? parentAugmentations})
+ : super(classIntrospector, typeResolver,
+ parentAugmentations: parentAugmentations);
+
+ @override
+ Future<TypeDeclaration> declarationOf(NamedStaticType annotation) =>
+ typeDeclarationResolver.declarationOf(annotation);
+}
+
+class ClassDefinitionBuilderImpl extends DefinitionBuilderBase
+ implements ClassDefinitionBuilder {
+ /// The declaration this is a builder for.
+ final ClassDeclaration declaration;
+
+ ClassDefinitionBuilderImpl(
+ this.declaration,
+ ClassIntrospector classIntrospector,
+ TypeResolver typeResolver,
+ TypeDeclarationResolver typeDeclarationResolver,
+ {List<DeclarationCode>? parentAugmentations})
+ : super(classIntrospector, typeResolver, typeDeclarationResolver,
+ parentAugmentations: parentAugmentations);
+
+ @override
+ Future<ConstructorDefinitionBuilder> buildConstructor(String name) async {
+ ConstructorDeclaration constructor =
+ (await classIntrospector.constructorsOf(declaration))
+ .firstWhere((constructor) => constructor.name == name);
+ return new ConstructorDefinitionBuilderImpl(
+ constructor, classIntrospector, typeResolver, typeDeclarationResolver,
+ parentAugmentations: _augmentations);
+ }
+
+ @override
+ Future<VariableDefinitionBuilder> buildField(String name) async {
+ FieldDeclaration field = (await classIntrospector.fieldsOf(declaration))
+ .firstWhere((field) => field.name == name);
+ return new FieldDefinitionBuilderImpl(
+ field, classIntrospector, typeResolver, typeDeclarationResolver,
+ parentAugmentations: _augmentations);
+ }
+
+ @override
+ Future<FunctionDefinitionBuilder> buildMethod(String name) async {
+ MethodDeclaration method = (await classIntrospector.methodsOf(declaration))
+ .firstWhere((method) => method.name == name);
+ return new MethodDefinitionBuilderImpl(
+ method, classIntrospector, typeResolver, typeDeclarationResolver,
+ parentAugmentations: _augmentations);
+ }
+}
+
+/// Implementation of [FunctionDefinitionBuilder].
+class FunctionDefinitionBuilderImpl extends DefinitionBuilderBase
+ implements FunctionDefinitionBuilder {
+ final FunctionDeclaration declaration;
+
+ FunctionDefinitionBuilderImpl(
+ this.declaration,
+ ClassIntrospector classIntrospector,
+ TypeResolver typeResolver,
+ TypeDeclarationResolver typeDeclarationResolver,
+ {List<DeclarationCode>? parentAugmentations})
+ : super(classIntrospector, typeResolver, typeDeclarationResolver,
+ parentAugmentations: parentAugmentations);
+
+ @override
+ void augment(FunctionBodyCode body) {
+ _augmentations.add(_buildFunctionAugmentation(body, declaration));
+ }
+}
+
+/// Implementation of [MethodDefinitionBuilderImpl].
+class MethodDefinitionBuilderImpl extends FunctionDefinitionBuilderImpl {
+ @override
+ final MethodDeclaration declaration;
+
+ MethodDefinitionBuilderImpl(
+ this.declaration,
+ ClassIntrospector classIntrospector,
+ TypeResolver typeResolver,
+ TypeDeclarationResolver typeDeclarationResolver,
+ {List<DeclarationCode>? parentAugmentations})
+ : super(declaration, classIntrospector, typeResolver,
+ typeDeclarationResolver,
+ parentAugmentations: parentAugmentations);
+
+ @override
+ void augment(FunctionBodyCode body) {
+ _augmentations.add(_buildClassAugmentation(
+ declaration.definingClass,
+ [_buildFunctionAugmentation(body, declaration)],
+ ));
+ }
+}
+
+class ConstructorDefinitionBuilderImpl extends DefinitionBuilderBase
+ implements ConstructorDefinitionBuilder {
+ final ConstructorDeclaration declaration;
+
+ ConstructorDefinitionBuilderImpl(
+ this.declaration,
+ ClassIntrospector classIntrospector,
+ TypeResolver typeResolver,
+ TypeDeclarationResolver typeDeclarationResolver,
+ {List<DeclarationCode>? parentAugmentations})
+ : super(classIntrospector, typeResolver, typeDeclarationResolver,
+ parentAugmentations: parentAugmentations);
+
+ @override
+ void augment({FunctionBodyCode? body, List<Code>? initializers}) {
+ body ??= new FunctionBodyCode.fromString('''{
+ augment super();
+ }''');
+ _augmentations.add(_buildClassAugmentation(declaration.definingClass, [
+ _buildFunctionAugmentation(body, declaration, initializers: initializers)
+ ]));
+ }
+}
+
+class VariableDefinitionBuilderImpl extends DefinitionBuilderBase
+ implements VariableDefinitionBuilder {
+ final VariableDeclaration declaration;
+
+ VariableDefinitionBuilderImpl(
+ this.declaration,
+ ClassIntrospector classIntrospector,
+ TypeResolver typeResolver,
+ TypeDeclarationResolver typeDeclarationResolver,
+ {List<DeclarationCode>? parentAugmentations})
+ : super(classIntrospector, typeResolver, typeDeclarationResolver,
+ parentAugmentations: parentAugmentations);
+
+ @override
+ void augment(
+ {DeclarationCode? getter,
+ DeclarationCode? setter,
+ ExpressionCode? initializer}) {
+ _augmentations.addAll(_buildVariableAugmentations(declaration,
+ getter: getter, setter: setter, initializer: initializer));
+ }
+}
+
+class FieldDefinitionBuilderImpl extends DefinitionBuilderBase
+ implements VariableDefinitionBuilder {
+ final FieldDeclaration declaration;
+
+ FieldDefinitionBuilderImpl(
+ this.declaration,
+ ClassIntrospector classIntrospector,
+ TypeResolver typeResolver,
+ TypeDeclarationResolver typeDeclarationResolver,
+ {List<DeclarationCode>? parentAugmentations})
+ : super(classIntrospector, typeResolver, typeDeclarationResolver,
+ parentAugmentations: parentAugmentations);
+
+ @override
+ void augment(
+ {DeclarationCode? getter,
+ DeclarationCode? setter,
+ ExpressionCode? initializer}) {
+ _augmentations.add(_buildClassAugmentation(
+ declaration.definingClass,
+ _buildVariableAugmentations(declaration,
+ getter: getter, setter: setter, initializer: initializer)));
+ }
+}
+
+/// Creates an augmentation of [clazz] with member [augmentations].
+DeclarationCode _buildClassAugmentation(
+ TypeAnnotation clazz, List<DeclarationCode> augmentations) =>
+ new DeclarationCode.fromParts([
+ 'augment class ',
+ clazz,
+ ' {\n',
+ ...augmentations.joinAsCode('\n'),
+ '\n}',
+ ]);
+
+/// Builds all the possible augmentations for a variable.
+List<DeclarationCode> _buildVariableAugmentations(
+ VariableDeclaration declaration,
+ {DeclarationCode? getter,
+ DeclarationCode? setter,
+ ExpressionCode? initializer}) {
+ List<DeclarationCode> augmentations = [];
+ if (getter != null) {
+ augmentations.add(new DeclarationCode.fromParts([
+ 'augment ',
+ getter,
+ ]));
+ }
+ if (setter != null) {
+ augmentations.add(new DeclarationCode.fromParts([
+ 'augment ',
+ setter,
+ ]));
+ }
+ if (initializer != null) {
+ augmentations.add(new DeclarationCode.fromParts([
+ 'augment ',
+ if (declaration.isFinal) 'final ',
+ declaration.type,
+ ' ',
+ declaration.name,
+ ' = ',
+ initializer,
+ ';',
+ ]));
+ }
+
+ return augmentations;
+}
+
+/// Builds the code to augment a function, method, or constructor with a new
+/// body.
+///
+/// The [initializers] parameter can only be used if [declaration] is a
+/// constructor.
+DeclarationCode _buildFunctionAugmentation(
+ FunctionBodyCode body, FunctionDeclaration declaration,
+ {List<Code>? initializers}) {
+ assert(initializers == null || declaration is ConstructorDeclaration);
+
+ return new DeclarationCode.fromParts([
+ 'augment ',
+ if (declaration is ConstructorDeclaration) ...[
+ declaration.definingClass.name,
+ if (declaration.name.isNotEmpty) '.',
+ ] else ...[
+ 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!,
+ ],
+ ]),
+ ', ',
+ ],
+ '}',
+ ],
+ ') ',
+ if (initializers != null && initializers.isNotEmpty) ...[
+ ' : ',
+ initializers.first,
+ for (Code initializer in initializers.skip(1)) ...[
+ ',\n',
+ initializer,
+ ],
+ ],
+ body,
+ ]);
+}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/execute_macro.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/execute_macro.dart
new file mode 100644
index 0000000..f94470d
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/execute_macro.dart
@@ -0,0 +1,120 @@
+// Copyright (c) 2022, 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 'package:_fe_analyzer_shared/src/macros/executor.dart';
+import 'package:_fe_analyzer_shared/src/macros/executor_shared/builder_impls.dart';
+import 'package:_fe_analyzer_shared/src/macros/api.dart';
+
+/// Runs [macro] in the declaration phase and returns a [MacroExecutionResult].
+Future<MacroExecutionResult> executeDeclarationsMacro(
+ Macro macro,
+ Declaration declaration,
+ ClassIntrospector classIntrospector,
+ TypeResolver typeResolver) async {
+ if (declaration is FunctionDeclaration) {
+ if (macro is ConstructorDeclarationsMacro &&
+ declaration is ConstructorDeclaration) {
+ ClassMemberDeclarationBuilderImpl builder =
+ new ClassMemberDeclarationBuilderImpl(
+ declaration.definingClass, classIntrospector, typeResolver);
+ await macro.buildDeclarationsForConstructor(declaration, builder);
+ return builder.result;
+ } else if (macro is MethodDeclarationsMacro &&
+ declaration is MethodDeclaration) {
+ ClassMemberDeclarationBuilderImpl builder =
+ new ClassMemberDeclarationBuilderImpl(
+ declaration.definingClass, classIntrospector, typeResolver);
+ await macro.buildDeclarationsForMethod(declaration, builder);
+ return builder.result;
+ } else if (macro is FunctionDeclarationsMacro) {
+ DeclarationBuilderImpl builder =
+ new DeclarationBuilderImpl(classIntrospector, typeResolver);
+ await macro.buildDeclarationsForFunction(declaration, builder);
+ return builder.result;
+ }
+ } else if (declaration is VariableDeclaration) {
+ if (macro is FieldDeclarationsMacro && declaration is FieldDeclaration) {
+ ClassMemberDeclarationBuilderImpl builder =
+ new ClassMemberDeclarationBuilderImpl(
+ declaration.definingClass, classIntrospector, typeResolver);
+ await macro.buildDeclarationsForField(declaration, builder);
+ return builder.result;
+ } else if (macro is VariableDeclarationsMacro) {
+ DeclarationBuilderImpl builder =
+ new DeclarationBuilderImpl(classIntrospector, typeResolver);
+ await macro.buildDeclarationsForVariable(declaration, builder);
+ return builder.result;
+ }
+ } else if (macro is ClassDeclarationsMacro &&
+ declaration is ClassDeclaration) {
+ ClassMemberDeclarationBuilderImpl builder =
+ new ClassMemberDeclarationBuilderImpl(
+ declaration.type, classIntrospector, typeResolver);
+ await macro.buildDeclarationsForClass(declaration, builder);
+ return builder.result;
+ }
+ throw new UnsupportedError('Unsupported macro type or invalid declaration:\n'
+ 'macro: $macro\ndeclaration: $declaration');
+}
+
+/// Runs [macro] in the definition phase and returns a [MacroExecutionResult].
+Future<MacroExecutionResult> executeDefinitionMacro(
+ Macro macro,
+ Declaration declaration,
+ ClassIntrospector classIntrospector,
+ TypeResolver typeResolver,
+ TypeDeclarationResolver typeDeclarationResolver) async {
+ if (declaration is FunctionDeclaration) {
+ if (macro is ConstructorDefinitionMacro &&
+ declaration is ConstructorDeclaration) {
+ ConstructorDefinitionBuilderImpl builder =
+ new ConstructorDefinitionBuilderImpl(declaration, classIntrospector,
+ typeResolver, typeDeclarationResolver);
+ await macro.buildDefinitionForConstructor(declaration, builder);
+ return builder.result;
+ } else if (macro is MethodDefinitionMacro &&
+ declaration is MethodDeclaration) {
+ MethodDefinitionBuilderImpl builder = new MethodDefinitionBuilderImpl(
+ declaration,
+ classIntrospector,
+ typeResolver,
+ typeDeclarationResolver);
+ await macro.buildDefinitionForMethod(declaration, builder);
+ return builder.result;
+ } else if (macro is FunctionDefinitionMacro) {
+ FunctionDefinitionBuilderImpl builder = new FunctionDefinitionBuilderImpl(
+ declaration,
+ classIntrospector,
+ typeResolver,
+ typeDeclarationResolver);
+ await macro.buildDefinitionForFunction(declaration, builder);
+ return builder.result;
+ }
+ } else if (declaration is VariableDeclaration) {
+ if (macro is FieldDefinitionMacro && declaration is FieldDeclaration) {
+ FieldDefinitionBuilderImpl builder = new FieldDefinitionBuilderImpl(
+ declaration,
+ classIntrospector,
+ typeResolver,
+ typeDeclarationResolver);
+ await macro.buildDefinitionForField(declaration, builder);
+ return builder.result;
+ } else if (macro is VariableDefinitionMacro) {
+ VariableDefinitionBuilderImpl builder = new VariableDefinitionBuilderImpl(
+ declaration,
+ classIntrospector,
+ typeResolver,
+ typeDeclarationResolver);
+ await macro.buildDefinitionForVariable(declaration, builder);
+ return builder.result;
+ }
+ } else if (macro is ClassDefinitionMacro && declaration is ClassDeclaration) {
+ ClassDefinitionBuilderImpl builder = new ClassDefinitionBuilderImpl(
+ declaration, classIntrospector, typeResolver, typeDeclarationResolver);
+ await macro.buildDefinitionForClass(declaration, builder);
+ return builder.result;
+ }
+ throw new UnsupportedError('Unsupported macro type or invalid declaration:\n'
+ 'macro: $macro\ndeclaration: $declaration');
+}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/introspection_impls.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/introspection_impls.dart
index a3f6fb4..9bdd740 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/introspection_impls.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/introspection_impls.dart
@@ -334,7 +334,7 @@
class MethodDeclarationImpl extends FunctionDeclarationImpl
implements MethodDeclaration {
@override
- final TypeAnnotationImpl definingClass;
+ final NamedTypeAnnotationImpl definingClass;
@override
RemoteInstanceKind get kind => RemoteInstanceKind.methodDeclaration;
@@ -401,7 +401,7 @@
required TypeAnnotationImpl returnType,
required List<TypeParameterDeclarationImpl> typeParameters,
// Method fields
- required TypeAnnotationImpl definingClass,
+ required NamedTypeAnnotationImpl definingClass,
// Constructor fields
required this.isFactory,
}) : super(
@@ -433,15 +433,18 @@
class VariableDeclarationImpl extends DeclarationImpl
implements VariableDeclaration {
@override
- final Code? initializer;
-
- @override
- final bool isAbstract;
+ final ExpressionCode? initializer;
@override
final bool isExternal;
@override
+ final bool isFinal;
+
+ @override
+ final bool isLate;
+
+ @override
final TypeAnnotationImpl type;
@override
@@ -451,8 +454,9 @@
required int id,
required String name,
required this.initializer,
- required this.isAbstract,
required this.isExternal,
+ required this.isFinal,
+ required this.isLate,
required this.type,
}) : super(id: id, name: name);
@@ -466,8 +470,9 @@
initializer.serializeNullable(serializer);
serializer
- ..addBool(isAbstract)
- ..addBool(isExternal);
+ ..addBool(isExternal)
+ ..addBool(isFinal)
+ ..addBool(isLate);
type.serialize(serializer);
}
}
@@ -475,16 +480,17 @@
class FieldDeclarationImpl extends VariableDeclarationImpl
implements FieldDeclaration {
@override
- final TypeAnnotationImpl definingClass;
+ final NamedTypeAnnotationImpl definingClass;
FieldDeclarationImpl({
// Declaration fields
required int id,
required String name,
// Variable fields
- required Code? initializer,
- required bool isAbstract,
+ required ExpressionCode? initializer,
required bool isExternal,
+ required bool isFinal,
+ required bool isLate,
required TypeAnnotationImpl type,
// Field fields
required this.definingClass,
@@ -492,8 +498,9 @@
id: id,
name: name,
initializer: initializer,
- isAbstract: isAbstract,
isExternal: isExternal,
+ isFinal: isFinal,
+ isLate: isLate,
type: type);
@override
@@ -513,11 +520,15 @@
abstract class TypeDeclarationImpl extends DeclarationImpl
implements TypeDeclaration {
@override
+ final TypeAnnotationImpl type;
+
+ @override
final List<TypeParameterDeclarationImpl> typeParameters;
TypeDeclarationImpl({
required int id,
required String name,
+ required this.type,
required this.typeParameters,
}) : super(id: id, name: name);
@@ -535,6 +546,7 @@
return;
}
+ type.serialize(serializer);
serializer..startList();
for (TypeParameterDeclarationImpl param in typeParameters) {
param.serialize(serializer);
@@ -568,6 +580,7 @@
required int id,
required String name,
// TypeDeclaration fields
+ required TypeAnnotationImpl type,
required List<TypeParameterDeclarationImpl> typeParameters,
// ClassDeclaration fields
required this.interfaces,
@@ -575,7 +588,7 @@
required this.isExternal,
required this.mixins,
required this.superclass,
- }) : super(id: id, name: name, typeParameters: typeParameters);
+ }) : super(id: id, name: name, type: type, typeParameters: typeParameters);
@override
void serialize(Serializer serializer) {
@@ -604,21 +617,22 @@
class TypeAliasDeclarationImpl extends TypeDeclarationImpl
implements TypeAliasDeclaration {
- @override
- RemoteInstanceKind get kind => RemoteInstanceKind.typeAliasDeclaration;
+ /// The type being aliased.
+ final TypeAnnotationImpl aliasedType;
@override
- final TypeAnnotationImpl type;
+ RemoteInstanceKind get kind => RemoteInstanceKind.typeAliasDeclaration;
TypeAliasDeclarationImpl({
// Declaration fields
required int id,
required String name,
// TypeDeclaration fields
+ required TypeAnnotationImpl type,
required List<TypeParameterDeclarationImpl> typeParameters,
// TypeAlias fields
- required this.type,
- }) : super(id: id, name: name, typeParameters: typeParameters);
+ required this.aliasedType,
+ }) : super(id: id, name: name, type: type, typeParameters: typeParameters);
@override
void serialize(Serializer serializer) {
@@ -628,6 +642,6 @@
return;
}
- type.serialize(serializer);
+ aliasedType.serialize(serializer);
}
}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/protocol.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/protocol.dart
index f16daf9..3eae69c 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/protocol.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/protocol.dart
@@ -239,6 +239,41 @@
/// A request to execute a macro on a particular declaration in the definition
/// phase.
+class ExecuteDeclarationsPhaseRequest extends Request {
+ final MacroInstanceIdentifier macro;
+ final DeclarationImpl declaration;
+
+ final RemoteInstanceImpl typeResolver;
+ final RemoteInstanceImpl classIntrospector;
+
+ ExecuteDeclarationsPhaseRequest(
+ this.macro, this.declaration, this.typeResolver, this.classIntrospector,
+ {required int serializationZoneId})
+ : super(serializationZoneId: serializationZoneId);
+
+ /// When deserializing we have already consumed the message type, so we don't
+ /// consume it again.
+ ExecuteDeclarationsPhaseRequest.deserialize(
+ Deserializer deserializer, int serializationZoneId)
+ : macro = new MacroInstanceIdentifierImpl.deserialize(deserializer),
+ declaration = RemoteInstance.deserialize(deserializer),
+ typeResolver = RemoteInstance.deserialize(deserializer),
+ classIntrospector = RemoteInstance.deserialize(deserializer),
+ super.deserialize(deserializer, serializationZoneId);
+
+ void serialize(Serializer serializer) {
+ serializer.addNum(MessageType.executeDeclarationsPhaseRequest.index);
+ macro.serialize(serializer);
+ declaration.serialize(serializer);
+ typeResolver.serialize(serializer);
+ classIntrospector.serialize(serializer);
+
+ super.serialize(serializer);
+ }
+}
+
+/// A request to execute a macro on a particular declaration in the definition
+/// phase.
class ExecuteDefinitionsPhaseRequest extends Request {
final MacroInstanceIdentifier macro;
final DeclarationImpl declaration;
@@ -627,6 +662,7 @@
mixinsOfRequest,
superclassOfRequest,
error,
+ executeDeclarationsPhaseRequest,
executeDefinitionsPhaseRequest,
instantiateMacroRequest,
isExactlyTypeRequest,
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/response_impls.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/response_impls.dart
index 77556ad..f829357 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/response_impls.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/response_impls.dart
@@ -2,13 +2,8 @@
// 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/executor_shared/remote_instance.dart';
-
import '../executor.dart';
import '../api.dart';
-import 'introspection_impls.dart';
import 'serialization.dart';
import 'serialization_extensions.dart';
@@ -55,10 +50,9 @@
final List<DeclarationCode> imports;
MacroExecutionResultImpl({
- List<DeclarationCode>? augmentations,
- List<DeclarationCode>? imports,
- }) : augmentations = augmentations ?? [],
- imports = imports ?? [];
+ required this.augmentations,
+ required this.imports,
+ });
factory MacroExecutionResultImpl.deserialize(Deserializer deserializer) {
deserializer.moveNext();
@@ -97,128 +91,3 @@
serializer.endList();
}
}
-
-/// Implementation of [FunctionDefinitionBuilder].
-class FunctionDefinitionBuilderImpl implements FunctionDefinitionBuilder {
- final TypeResolver typeResolver;
- final TypeDeclarationResolver typeDeclarationResolver;
- final ClassIntrospector classIntrospector;
-
- /// The declaration this is a builder for.
- final FunctionDeclarationImpl declaration;
-
- /// The final result, will be built up over `augment` calls.
- final MacroExecutionResultImpl result;
-
- FunctionDefinitionBuilderImpl(this.declaration, this.typeResolver,
- this.typeDeclarationResolver, this.classIntrospector)
- : result = new MacroExecutionResultImpl();
-
- FunctionDefinitionBuilderImpl.deserialize(Deserializer deserializer,
- this.typeResolver, this.typeDeclarationResolver, this.classIntrospector)
- : declaration = RemoteInstance.deserialize(deserializer),
- result = new MacroExecutionResultImpl.deserialize(deserializer);
-
- void serialize(Serializer serializer) {
- // Note that the `typeResolver`, `typeDeclarationResolver`, and
- // `classIntrospector` are not serialized. These have custom implementations
- // on the client/server side.
- declaration.serialize(serializer);
- result.serialize(serializer);
- }
-
- @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/executor_shared/serialization_extensions.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization_extensions.dart
index b7df0be..33464d7 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization_extensions.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization_extensions.dart
@@ -152,8 +152,9 @@
id: id,
name: expectString(),
initializer: (this..moveNext()).expectNullableCode(),
- isAbstract: (this..moveNext()).expectBool(),
isExternal: (this..moveNext()).expectBool(),
+ isFinal: (this..moveNext()).expectBool(),
+ isLate: (this..moveNext()).expectBool(),
type: RemoteInstance.deserialize(this),
);
@@ -161,8 +162,9 @@
id: id,
name: expectString(),
initializer: (this..moveNext()).expectNullableCode(),
- isAbstract: (this..moveNext()).expectBool(),
isExternal: (this..moveNext()).expectBool(),
+ isFinal: (this..moveNext()).expectBool(),
+ isLate: (this..moveNext()).expectBool(),
type: RemoteInstance.deserialize(this),
definingClass: RemoteInstance.deserialize(this),
);
@@ -170,6 +172,7 @@
ClassDeclaration _expectClassDeclaration(int id) => new ClassDeclarationImpl(
id: id,
name: expectString(),
+ type: RemoteInstance.deserialize(this),
typeParameters: (this..moveNext())._expectRemoteInstanceList(),
interfaces: (this..moveNext())._expectRemoteInstanceList(),
isAbstract: (this..moveNext()).expectBool(),
@@ -183,8 +186,9 @@
new TypeAliasDeclarationImpl(
id: id,
name: expectString(),
- typeParameters: (this..moveNext())._expectRemoteInstanceList(),
type: RemoteInstance.deserialize(this),
+ typeParameters: (this..moveNext())._expectRemoteInstanceList(),
+ aliasedType: RemoteInstance.deserialize(this),
);
T expectCode<T extends Code>() {
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
index 91b1125..e1e12fe 100644
--- 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
@@ -6,6 +6,7 @@
import 'dart:isolate';
import 'dart:mirrors';
+import '../executor_shared/builder_impls.dart';
import '../executor_shared/introspection_impls.dart';
import '../executor_shared/response_impls.dart';
import '../executor_shared/protocol.dart';
@@ -97,9 +98,9 @@
declaration is FunctionDeclarationImpl) {
FunctionDefinitionBuilderImpl builder = new FunctionDefinitionBuilderImpl(
declaration,
+ request.classIntrospector.instance as ClassIntrospector,
request.typeResolver.instance as TypeResolver,
- request.typeDeclarationResolver.instance as TypeDeclarationResolver,
- request.classIntrospector.instance as ClassIntrospector);
+ request.typeDeclarationResolver.instance as TypeDeclarationResolver);
await instance.buildDefinitionForFunction(declaration, builder);
return new Response(
response: builder.result,
@@ -109,9 +110,9 @@
declaration is MethodDeclarationImpl) {
FunctionDefinitionBuilderImpl builder = new FunctionDefinitionBuilderImpl(
declaration,
+ request.classIntrospector.instance as ClassIntrospector,
request.typeResolver.instance as TypeResolver,
- request.typeDeclarationResolver.instance as TypeDeclarationResolver,
- request.classIntrospector.instance as ClassIntrospector);
+ request.typeDeclarationResolver.instance as TypeDeclarationResolver);
await instance.buildDefinitionForMethod(declaration, builder);
return new SerializableResponse(
responseType: MessageType.macroExecutionResult,
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/isolated_executor/isolated_executor.dart b/pkg/_fe_analyzer_shared/lib/src/macros/isolated_executor/isolated_executor.dart
index 57f0ec8..9194c7f 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/isolated_executor/isolated_executor.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/isolated_executor/isolated_executor.dart
@@ -377,13 +377,22 @@
@override
Future<MacroExecutionResult> executeDeclarationsPhase(
- MacroInstanceIdentifier macro,
- DeclarationImpl declaration,
- TypeResolver typeResolver,
- ClassIntrospector classIntrospector) {
- // TODO: implement executeDeclarationsPhase
- throw new UnimplementedError();
- }
+ MacroInstanceIdentifier macro,
+ DeclarationImpl declaration,
+ TypeResolver typeResolver,
+ ClassIntrospector classIntrospector) =>
+ _sendRequest((zoneId) => new ExecuteDeclarationsPhaseRequest(
+ macro,
+ declaration,
+ new RemoteInstanceImpl(
+ instance: typeResolver,
+ id: RemoteInstance.uniqueId,
+ kind: RemoteInstanceKind.typeResolver),
+ new RemoteInstanceImpl(
+ instance: classIntrospector,
+ id: RemoteInstance.uniqueId,
+ kind: RemoteInstanceKind.classIntrospector),
+ serializationZoneId: zoneId));
@override
Future<MacroExecutionResult> executeDefinitionsPhase(
diff --git a/pkg/_fe_analyzer_shared/test/macros/executor_shared/serialization_test.dart b/pkg/_fe_analyzer_shared/test/macros/executor_shared/serialization_test.dart
index 6a3807b..b9efa16 100644
--- a/pkg/_fe_analyzer_shared/test/macros/executor_shared/serialization_test.dart
+++ b/pkg/_fe_analyzer_shared/test/macros/executor_shared/serialization_test.dart
@@ -207,9 +207,10 @@
var bar = VariableDeclarationImpl(
id: RemoteInstance.uniqueId,
name: 'bar',
- isAbstract: false,
isExternal: true,
- initializer: Code.fromString('Bar()'),
+ isFinal: false,
+ isLate: true,
+ initializer: ExpressionCode.fromString('Bar()'),
type: barType,
);
expectSerializationEquality(bar);
@@ -219,8 +220,9 @@
var bar = FieldDeclarationImpl(
id: RemoteInstance.uniqueId,
name: 'bar',
- isAbstract: false,
isExternal: false,
+ isFinal: true,
+ isLate: false,
initializer: null,
type: barType,
definingClass: fooType,
@@ -250,6 +252,7 @@
isExternal: false,
mixins: [serializableType],
superclass: objectType,
+ type: fooType,
typeParameters: [zapTypeParam],
);
expectSerializationEquality(fooClass);
@@ -262,9 +265,14 @@
type: NamedTypeAnnotationImpl(
id: RemoteInstance.uniqueId,
isNullable: false,
+ name: 'FooOfBar',
+ typeArguments: []),
+ typeParameters: [zapTypeParam],
+ aliasedType: NamedTypeAnnotationImpl(
+ id: RemoteInstance.uniqueId,
+ isNullable: false,
name: 'Foo',
typeArguments: [barType]),
- typeParameters: [zapTypeParam],
);
expectSerializationEquality(typeAlias);
});
diff --git a/pkg/_fe_analyzer_shared/test/macros/isolated_executor/isolated_executor_test.dart b/pkg/_fe_analyzer_shared/test/macros/isolated_executor/isolated_executor_test.dart
index 7c242a4..81aa97f 100644
--- a/pkg/_fe_analyzer_shared/test/macros/isolated_executor/isolated_executor_test.dart
+++ b/pkg/_fe_analyzer_shared/test/macros/isolated_executor/isolated_executor_test.dart
@@ -18,31 +18,23 @@
void main() {
late MacroExecutor executor;
- late Directory tmpDir;
+ late File kernelOutputFile;
+ final macroName = 'SimpleMacro';
+ late MacroInstanceIdentifier instanceId;
+ late Uri macroUri;
late File simpleMacroFile;
+ late Directory tmpDir;
- setUpAll(() {
+ setUpAll(() async {
// We support running from either the root of the SDK or the package root.
simpleMacroFile = File(
'pkg/_fe_analyzer_shared/test/macros/isolated_executor/simple_macro.dart');
if (!simpleMacroFile.existsSync()) {
simpleMacroFile = File('test/macros/isolated_executor/simple_macro.dart');
}
- });
-
- setUp(() async {
executor = await isolatedExecutor.start();
tmpDir = Directory.systemTemp.createTempSync('isolated_executor_test');
- });
-
- tearDown(() {
- if (tmpDir.existsSync()) tmpDir.deleteSync(recursive: true);
- executor.close();
- });
-
- test('can load and run macros', () async {
- var macroUri = simpleMacroFile.absolute.uri;
- var macroName = 'SimpleMacro';
+ macroUri = simpleMacroFile.absolute.uri;
var bootstrapContent = bootstrapMacroIsolate({
macroUri.toString(): {
@@ -51,22 +43,22 @@
});
var bootstrapFile = File(tmpDir.uri.resolve('main.dart').toFilePath())
..writeAsStringSync(bootstrapContent);
- var kernelOutputFile =
- File(tmpDir.uri.resolve('main.dart.dill').toFilePath());
- var result = await Process.run(Platform.resolvedExecutable, [
+ kernelOutputFile = File(tmpDir.uri.resolve('main.dart.dill').toFilePath());
+ var buildSnapshotResult = await Process.run(Platform.resolvedExecutable, [
'--snapshot=${kernelOutputFile.uri.toFilePath()}',
'--snapshot-kind=kernel',
'--packages=${(await Isolate.packageConfig)!}',
bootstrapFile.uri.toFilePath(),
]);
- expect(result.exitCode, 0,
- reason: 'stdout: ${result.stdout}\nstderr: ${result.stderr}');
+ expect(buildSnapshotResult.exitCode, 0,
+ reason: 'stdout: ${buildSnapshotResult.stdout}\n'
+ 'stderr: ${buildSnapshotResult.stderr}');
var clazzId = await executor.loadMacro(macroUri, macroName,
precompiledKernelUri: kernelOutputFile.uri);
expect(clazzId, isNotNull, reason: 'Can load a macro.');
- var instanceId =
+ instanceId =
await executor.instantiateMacro(clazzId, '', Arguments([], {}));
expect(instanceId, isNotNull,
reason: 'Can create an instance with no arguments.');
@@ -80,7 +72,14 @@
clazzId, 'named', Arguments([], {'x': 1, 'y': 2}));
expect(instanceId, isNotNull,
reason: 'Can create an instance with named arguments.');
+ });
+ tearDownAll(() {
+ if (tmpDir.existsSync()) tmpDir.deleteSync(recursive: true);
+ executor.close();
+ });
+
+ group('run macros', () {
var stringType = NamedTypeAnnotationImpl(
id: RemoteInstance.uniqueId,
name: 'String',
@@ -111,6 +110,7 @@
var myClass = ClassDeclarationImpl(
id: RemoteInstance.uniqueId,
name: myClassType.name,
+ type: myClassType,
typeParameters: [],
interfaces: [myInterfaceType],
isAbstract: false,
@@ -134,13 +134,15 @@
id: RemoteInstance.uniqueId,
name: 'myField',
initializer: null,
- isAbstract: false,
isExternal: false,
+ isFinal: false,
+ isLate: false,
type: stringType,
definingClass: myClassType);
var myInterface = ClassDeclarationImpl(
id: RemoteInstance.uniqueId,
name: myInterfaceType.name,
+ type: myInterfaceType,
typeParameters: [],
interfaces: [],
isAbstract: false,
@@ -162,6 +164,7 @@
var myMixin = ClassDeclarationImpl(
id: RemoteInstance.uniqueId,
name: myMixinType.name,
+ type: myMixinType,
typeParameters: [],
interfaces: [],
isAbstract: false,
@@ -171,6 +174,7 @@
var mySuperclass = ClassDeclarationImpl(
id: RemoteInstance.uniqueId,
name: mySuperclassType.name,
+ type: mySuperclassType,
typeParameters: [],
interfaces: [],
isAbstract: false,
@@ -181,61 +185,189 @@
var myClassStaticType = TestNamedStaticType(
'package:my_package/my_package.dart', myClassType.name, []);
- var definitionResult = await executor.executeDefinitionsPhase(
- instanceId,
- MethodDeclarationImpl(
- id: RemoteInstance.uniqueId,
- definingClass: myClassType,
- isAbstract: false,
- isExternal: false,
- isGetter: false,
- isSetter: false,
- name: 'foo',
- namedParameters: [],
- positionalParameters: [],
- returnType: stringType,
- typeParameters: [],
- ),
- TestTypeResolver({
- stringType: TestNamedStaticType('dart:core', stringType.name, []),
- myClassType: myClassStaticType,
- }),
- TestClassIntrospector(
- constructors: {
- myClass: [myConstructor],
- },
- fields: {
- myClass: [myField],
- },
- interfaces: {
- myClass: [myInterface],
- },
- methods: {
- myClass: [myMethod],
- },
- mixins: {
- myClass: [myMixin],
- },
- superclass: {
- myClass: mySuperclass,
- },
- ),
- TestTypeDeclarationResolver({myClassStaticType: myClass}));
- expect(definitionResult.augmentations, hasLength(1));
- expect(definitionResult.augmentations.first.debugString().toString(),
- equalsIgnoringWhitespace('''
- augment class MyClass {
- augment String foo() {
- print('x: 1, y: 2');
- print('parentClass: MyClass');
- print('superClass: MySuperclass');
- print('interface: MyInterface');
- print('mixin: MyMixin');
- print('field: myField');
- print('method: myMethod');
- print('constructor: myConstructor');
- return augment super();
- }
- }'''));
+ var testTypeResolver = TestTypeResolver({
+ stringType: TestNamedStaticType('dart:core', stringType.name, []),
+ myClassType: myClassStaticType,
+ });
+ var testClassIntrospector = TestClassIntrospector(
+ constructors: {
+ myClass: [myConstructor],
+ },
+ fields: {
+ myClass: [myField],
+ },
+ interfaces: {
+ myClass: [myInterface],
+ },
+ methods: {
+ myClass: [myMethod],
+ },
+ mixins: {
+ myClass: [myMixin],
+ },
+ superclass: {
+ myClass: mySuperclass,
+ },
+ );
+ var testTypeDeclarationResolver =
+ TestTypeDeclarationResolver({myClassStaticType: myClass});
+
+ group('in the declaration phase', () {
+ test('on methods', () async {
+ var result = await executor.executeDeclarationsPhase(
+ instanceId, myMethod, testTypeResolver, testClassIntrospector);
+ expect(
+ result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace(
+ 'String delegateMemberMyMethod() => myMethod();'));
+ });
+
+ test('on constructors', () async {
+ var result = await executor.executeDeclarationsPhase(
+ instanceId, myConstructor, testTypeResolver, testClassIntrospector);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('''
+ augment class MyClass {
+ factory MyClass.myConstructorDelegate() => MyClass.myConstructor();
+ }'''));
+ });
+
+ test('on fields', () async {
+ var result = await executor.executeDeclarationsPhase(
+ instanceId, myField, testTypeResolver, testClassIntrospector);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('''
+ augment class MyClass {
+ String get delegateMyField => myField;
+ }'''));
+ });
+
+ test('on classes', () async {
+ var result = await executor.executeDeclarationsPhase(
+ instanceId, myClass, testTypeResolver, testClassIntrospector);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('''
+ augment class MyClass {
+ static const List<String> fieldNames = ['myField',];
+ }'''));
+ });
+ });
+
+ group('in the definition phase', () {
+ test('on methods', () async {
+ var definitionResult = await executor.executeDefinitionsPhase(
+ instanceId,
+ myMethod,
+ testTypeResolver,
+ testClassIntrospector,
+ testTypeDeclarationResolver);
+ expect(definitionResult.augmentations, hasLength(2));
+ var augmentationStrings = definitionResult.augmentations
+ .map((a) => a.debugString().toString())
+ .toList();
+ expect(augmentationStrings, unorderedEquals(methodDefinitionMatchers));
+ });
+
+ test('on constructors', () async {
+ var definitionResult = await executor.executeDefinitionsPhase(
+ instanceId,
+ myConstructor,
+ testTypeResolver,
+ testClassIntrospector,
+ testTypeDeclarationResolver);
+ expect(definitionResult.augmentations, hasLength(1));
+ expect(definitionResult.augmentations.first.debugString().toString(),
+ constructorDefinitionMatcher);
+ });
+
+ test('on fields', () async {
+ var definitionResult = await executor.executeDefinitionsPhase(
+ instanceId,
+ myField,
+ testTypeResolver,
+ testClassIntrospector,
+ testTypeDeclarationResolver);
+ expect(definitionResult.augmentations, hasLength(1));
+ expect(definitionResult.augmentations.first.debugString().toString(),
+ fieldDefinitionMatcher);
+ });
+
+ test('on classes', () async {
+ var definitionResult = await executor.executeDefinitionsPhase(
+ instanceId,
+ myClass,
+ testTypeResolver,
+ testClassIntrospector,
+ testTypeDeclarationResolver);
+ var augmentationStrings = definitionResult.augmentations
+ .map((a) => a.debugString().toString())
+ .toList();
+ expect(
+ augmentationStrings,
+ unorderedEquals([
+ ...methodDefinitionMatchers,
+ constructorDefinitionMatcher,
+ fieldDefinitionMatcher
+ ]));
+ });
+ });
});
}
+
+final constructorDefinitionMatcher = equalsIgnoringWhitespace('''
+augment class MyClass {
+ augment MyClass.myConstructor() {
+ print('definingClass: MyClass');
+ print('isFactory: false');
+ print('isAbstract: false');
+ print('isExternal: false');
+ print('isGetter: false');
+ print('isSetter: false');
+ print('returnType: MyClass');
+ return augment super();
+ }
+}''');
+
+final fieldDefinitionMatcher = equalsIgnoringWhitespace('''
+augment class MyClass {
+ augment String get myField {
+ print('parentClass: MyClass');
+ print('isExternal: false');
+ print('isFinal: false');
+ print('isLate: false');
+ return augment super;
+ }
+ augment set (String value) {
+ augment super(value);
+ }
+}''');
+
+final methodDefinitionMatchers = [
+ equalsIgnoringWhitespace('''
+ augment class MyClass {
+ augment String myMethod() {
+ print('definingClass: MyClass');
+ print('isAbstract: false');
+ print('isExternal: false');
+ print('isGetter: false');
+ print('isSetter: false');
+ print('returnType: String');
+ return augment super();
+ }
+ }
+ '''),
+ equalsIgnoringWhitespace('''
+ augment class MyClass {
+ augment String myMethod() {
+ print('x: 1, y: 2');
+ print('parentClass: MyClass');
+ print('superClass: MySuperclass');
+ print('interface: MyInterface');
+ print('mixin: MyMixin');
+ print('field: myField');
+ print('method: myMethod');
+ print('constructor: myConstructor');
+ return augment super();
+ }
+ }'''),
+];
diff --git a/pkg/_fe_analyzer_shared/test/macros/isolated_executor/simple_macro.dart b/pkg/_fe_analyzer_shared/test/macros/isolated_executor/simple_macro.dart
index 84ddb7a..b5681aa 100644
--- a/pkg/_fe_analyzer_shared/test/macros/isolated_executor/simple_macro.dart
+++ b/pkg/_fe_analyzer_shared/test/macros/isolated_executor/simple_macro.dart
@@ -6,9 +6,26 @@
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 MethodDefinitionMacro {
+/// A very simple macro that augments any declaration it is given, usually
+/// adding print statements and inlining values from the declaration object
+/// for comparision with expected values in tests.
+///
+/// When applied to [MethodDeclaration]s there is some extra work that happens
+/// to validate the introspection APIs work as expected.
+class SimpleMacro
+ implements
+ ClassDeclarationsMacro,
+ ClassDefinitionMacro,
+ ConstructorDeclarationsMacro,
+ ConstructorDefinitionMacro,
+ FieldDeclarationsMacro,
+ FieldDefinitionMacro,
+ FunctionDeclarationsMacro,
+ FunctionDefinitionMacro,
+ MethodDeclarationsMacro,
+ MethodDefinitionMacro,
+ VariableDeclarationsMacro,
+ VariableDefinitionMacro {
final int? x;
final int? y;
@@ -17,14 +34,132 @@
SimpleMacro.named({this.x, this.y});
@override
- FutureOr<void> buildDefinitionForMethod(
- MethodDeclaration method, FunctionDefinitionBuilder builder) async {
- if (method.namedParameters
- .followedBy(method.positionalParameters)
- .isNotEmpty) {
- throw ArgumentError(
- 'This macro can only be run on functions with no arguments!');
+ FutureOr<void> buildDeclarationsForClass(
+ ClassDeclaration clazz, ClassMemberDeclarationBuilder builder) async {
+ var fields = await builder.fieldsOf(clazz);
+ builder.declareInClass(DeclarationCode.fromParts([
+ 'static const List<String> fieldNames = [',
+ for (var field in fields) "'${field.name}',",
+ '];',
+ ]));
+ }
+
+ @override
+ FutureOr<void> buildDeclarationsForConstructor(
+ ConstructorDeclaration constructor,
+ ClassMemberDeclarationBuilder builder) {
+ if (constructor.positionalParameters.isNotEmpty ||
+ constructor.namedParameters.isNotEmpty) {
+ throw new UnsupportedError(
+ 'Can only run on constructors with no parameters!');
}
+ builder.declareInClass(
+ DeclarationCode.fromString('factory ${constructor.definingClass.name}'
+ '.${constructor.name}Delegate() => '
+ '${constructor.definingClass.name}.${constructor.name}();'));
+ }
+
+ @override
+ FutureOr<void> buildDeclarationsForFunction(
+ FunctionDeclaration function, DeclarationBuilder builder) {
+ if (function.positionalParameters.isNotEmpty ||
+ function.namedParameters.isNotEmpty) {
+ throw new UnsupportedError(
+ 'Can only run on functions with no parameters!');
+ }
+ builder.declareInLibrary(DeclarationCode.fromParts([
+ function.returnType,
+ ' delegate${function.name.capitalize()}() => ${function.name}();',
+ ]));
+ }
+
+ @override
+ FutureOr<void> buildDeclarationsForMethod(
+ MethodDeclaration method, ClassMemberDeclarationBuilder builder) {
+ if (method.positionalParameters.isNotEmpty ||
+ method.namedParameters.isNotEmpty) {
+ throw new UnsupportedError('Can only run on method with no parameters!');
+ }
+ builder.declareInLibrary(DeclarationCode.fromParts([
+ method.returnType,
+ ' delegateMember${method.name.capitalize()}() => ${method.name}();',
+ ]));
+ }
+
+ @override
+ FutureOr<void> buildDeclarationsForVariable(
+ VariableDeclaration variable, DeclarationBuilder builder) {
+ builder.declareInLibrary(DeclarationCode.fromParts([
+ variable.type,
+ ' get delegate${variable.name.capitalize()} => ${variable.name};',
+ ]));
+ }
+
+ @override
+ FutureOr<void> buildDeclarationsForField(
+ FieldDeclaration field, ClassMemberDeclarationBuilder builder) {
+ builder.declareInClass(DeclarationCode.fromParts([
+ field.type,
+ ' get delegate${field.name.capitalize()} => ${field.name};',
+ ]));
+ }
+
+ @override
+ Future<void> buildDefinitionForClass(
+ ClassDeclaration clazz, ClassDefinitionBuilder builder) async {
+ // Apply ourself to all our members
+ var fields = (await builder.fieldsOf(clazz));
+ for (var field in fields) {
+ await buildDefinitionForField(
+ field, await builder.buildField(field.name));
+ }
+ var methods = (await builder.methodsOf(clazz));
+ for (var method in methods) {
+ await buildDefinitionForMethod(
+ method, await builder.buildMethod(method.name));
+ }
+ var constructors = (await builder.constructorsOf(clazz));
+ for (var constructor in constructors) {
+ await buildDefinitionForConstructor(
+ constructor, await builder.buildConstructor(constructor.name));
+ }
+ }
+
+ @override
+ Future<void> buildDefinitionForConstructor(ConstructorDeclaration constructor,
+ ConstructorDefinitionBuilder builder) async {
+ var clazz = await builder.declarationOf(
+ await builder.resolve(constructor.definingClass) as NamedStaticType)
+ as ClassDeclaration;
+ var fields = (await builder.fieldsOf(clazz));
+
+ builder.augment(
+ body: _buildFunctionAugmentation(constructor),
+ initializers: [
+ for (var field in fields)
+ // TODO: Compare against actual `int` type.
+ if (field.isFinal &&
+ (field.type as NamedTypeAnnotation).name == 'int')
+ Code.fromString('${field.name} = ${x!}'),
+ ],
+ );
+ }
+
+ @override
+ Future<void> buildDefinitionForField(
+ FieldDeclaration field, VariableDefinitionBuilder builder) async =>
+ buildDefinitionForVariable(field, builder);
+
+ @override
+ Future<void> buildDefinitionForFunction(
+ FunctionDeclaration function, FunctionDefinitionBuilder builder) async {
+ builder.augment(_buildFunctionAugmentation(function));
+ }
+
+ @override
+ Future<void> buildDefinitionForMethod(
+ MethodDeclaration method, FunctionDefinitionBuilder builder) async {
+ await buildDefinitionForFunction(method, builder);
// Test the type resolver and static type interfaces
var staticReturnType = await builder.resolve(method.returnType);
@@ -48,6 +183,9 @@
// Test the type declaration resolver
var parentClass =
await builder.declarationOf(classType) as ClassDeclaration;
+ // Should be able to find ourself in the methods of the parent class.
+ (await builder.methodsOf(parentClass))
+ .singleWhere((m) => m.name == method.name);
// Test the class introspector
var superClass = (await builder.superclassOf(parentClass))!;
@@ -74,4 +212,71 @@
}''',
]));
}
+
+ @override
+ Future<void> buildDefinitionForVariable(
+ VariableDeclaration variable, VariableDefinitionBuilder builder) async {
+ var definingClass =
+ variable is FieldDeclaration ? variable.definingClass.name : '';
+ builder.augment(
+ getter: DeclarationCode.fromParts([
+ variable.type,
+ ' get ',
+ variable.name,
+ ''' {
+ print('parentClass: $definingClass');
+ print('isExternal: ${variable.isExternal}');
+ print('isFinal: ${variable.isFinal}');
+ print('isLate: ${variable.isLate}');
+ return augment super;
+ }''',
+ ]),
+ setter: DeclarationCode.fromParts(
+ ['set (', variable.type, ' value) { augment super(value); }']),
+ initializer: variable.initializer,
+ );
+ }
+}
+
+FunctionBodyCode _buildFunctionAugmentation(FunctionDeclaration function) =>
+ FunctionBodyCode.fromParts([
+ '{\n',
+ if (function is MethodDeclaration)
+ "print('definingClass: ${function.definingClass.name}');\n",
+ if (function is ConstructorDeclaration)
+ "print('isFactory: ${function.isFactory}');\n",
+ '''
+ print('isAbstract: ${function.isAbstract}');
+ print('isExternal: ${function.isExternal}');
+ print('isGetter: ${function.isGetter}');
+ print('isSetter: ${function.isSetter}');
+ print('returnType: ''',
+ function.returnType,
+ "');\n",
+ for (var param in function.positionalParameters) ...[
+ "print('positionalParam: ",
+ param.type,
+ ' ${param.name}',
+ if (param.defaultValue != null) ...[' = ', param.defaultValue!],
+ "');\n",
+ ],
+ for (var param in function.namedParameters) ...[
+ "print('namedParam: ",
+ param.type,
+ ' ${param.name}',
+ if (param.defaultValue != null) ...[' = ', param.defaultValue!],
+ "');\n",
+ ],
+ for (var param in function.typeParameters) ...[
+ "print('typeParam: ${param.name} ",
+ if (param.bounds != null) param.bounds!,
+ "');\n",
+ ],
+ '''
+ return augment super();
+ }''',
+ ]);
+
+extension _ on String {
+ String capitalize() => '${this[0].toUpperCase()}${this.substring(1)}';
}