From 4984280d7c9ac5f9e5d72d0995afa037dfea378d Mon Sep 17 00:00:00 2001 From: Jake Macdonald Date: Tue, 15 Oct 2024 16:40:26 +0000 Subject: [PATCH 1/7] pass the target model to the macro --- pkgs/_macro_client/lib/src/execute_macro.dart | 23 ++- pkgs/_test_macros/lib/declare_x_macro.dart | 6 +- pkgs/_test_macros/lib/json_codable.dart | 21 +- pkgs/_test_macros/lib/query_class.dart | 8 +- pkgs/dart_model/lib/src/dart_model.dart | 14 +- pkgs/dart_model/test/model_test.dart | 12 +- pkgs/macro/lib/macro.dart | 181 ++++++++++++++---- 7 files changed, 181 insertions(+), 84 deletions(-) diff --git a/pkgs/_macro_client/lib/src/execute_macro.dart b/pkgs/_macro_client/lib/src/execute_macro.dart index 46cff3c8..1a9267c4 100644 --- a/pkgs/_macro_client/lib/src/execute_macro.dart +++ b/pkgs/_macro_client/lib/src/execute_macro.dart @@ -14,11 +14,11 @@ Future executeTypesMacro( final target = request.target; // TODO: https://github.com/dart-lang/macros/issues/100. final queryResult = await host.query(Query(target: target)); - final properties = - queryResult.uris[target.uri]!.scopes[target.name]!.properties; - switch ((properties, macro)) { + final interface = queryResult.uris[target.uri]!.scopes[target.name]!; + + switch ((interface.properties, macro)) { case (Properties(isClass: true), ClassTypesMacro macro): - return await macro.buildTypesForClass(host, request); + return await macro.buildTypesForClass(interface, queryResult, host); case (_, LibraryTypesMacro()): case (_, ConstructorTypesMacro()): case (_, MethodTypesMacro()): @@ -44,12 +44,12 @@ Future executeDeclarationsMacro( final target = request.target; // TODO: https://github.com/dart-lang/macros/issues/100. final queryResult = await host.query(Query(target: target)); - final properties = - queryResult.uris[target.uri]!.scopes[target.name]!.properties; + final interface = queryResult.uris[target.uri]!.scopes[target.name]!; - switch ((properties, macro)) { + switch ((interface.properties, macro)) { case (Properties(isClass: true), ClassDeclarationsMacro macro): - return await macro.buildDeclarationsForClass(host, request); + return await macro.buildDeclarationsForClass( + interface, queryResult, host); case (_, LibraryDeclarationsMacro()): case (_, EnumDeclarationsMacro()): case (_, ExtensionDeclarationsMacro()): @@ -75,12 +75,11 @@ Future executeDefinitionsMacro( final target = request.target; // TODO: https://github.com/dart-lang/macros/issues/100. final queryResult = await host.query(Query(target: target)); - final properties = - queryResult.uris[target.uri]!.scopes[target.name]!.properties; + final interface = queryResult.uris[target.uri]!.scopes[target.name]!; - switch ((properties, macro)) { + switch ((interface.properties, macro)) { case (Properties(isClass: true), ClassDefinitionsMacro macro): - return await macro.buildDefinitionsForClass(host, request); + return await macro.buildDefinitionsForClass(interface, queryResult, host); case (_, LibraryDefinitionsMacro()): case (_, EnumDefinitionsMacro()): case (_, ExtensionDefinitionsMacro()): diff --git a/pkgs/_test_macros/lib/declare_x_macro.dart b/pkgs/_test_macros/lib/declare_x_macro.dart index c51d0573..926c03e6 100644 --- a/pkgs/_test_macros/lib/declare_x_macro.dart +++ b/pkgs/_test_macros/lib/declare_x_macro.dart @@ -23,11 +23,7 @@ class DeclareXImplementation implements ClassDeclarationsMacro { @override Future buildDeclarationsForClass( - Host host, AugmentRequest request) async { - // TODO(davidmorgan): make the host only run in the phases requested so - // that this is not needed. - if (request.phase != 2) return AugmentResponse(augmentations: []); - + Interface target, Model model, Host host) async { // TODO(davidmorgan): still need to pass through the augment target. return AugmentResponse( augmentations: [Augmentation(code: expandTemplate('int get x => 3;'))]); diff --git a/pkgs/_test_macros/lib/json_codable.dart b/pkgs/_test_macros/lib/json_codable.dart index bfb4adad..bbca2250 100644 --- a/pkgs/_test_macros/lib/json_codable.dart +++ b/pkgs/_test_macros/lib/json_codable.dart @@ -28,12 +28,12 @@ class JsonCodableImplementation @override Future buildDeclarationsForClass( - Host host, AugmentRequest request) async { - final target = request.target; + Interface target, Model model, Host host) async { + final qualifiedName = model.qualifiedNameOf(target.node)!; return AugmentResponse(augmentations: [ Augmentation(code: expandTemplate(''' // TODO(davidmorgan): see https://github.com/dart-lang/macros/issues/80. -// external ${target.name}.fromJson($_jsonMapType json); +// external ${qualifiedName.name}.fromJson($_jsonMapType json); // external $_jsonMapType toJson(); ''')) ]); @@ -41,17 +41,16 @@ class JsonCodableImplementation @override Future buildDefinitionsForClass( - Host host, AugmentRequest request) async { - final target = request.target; - final model = await host.query(Query(target: target)); - final clazz = model.uris[target.uri]!.scopes[target.name]!; - + Interface target, Model model, Host host) async { + final qualifiedName = model.qualifiedNameOf(target.node)!; // TODO(davidmorgan): put `extends` information directly in `Interface`. - final superclassName = MacroScope.current.typeSystem.supertypeOf(target); + final superclassName = + MacroScope.current.typeSystem.supertypeOf(qualifiedName); return AugmentResponse(augmentations: [ - await _generateFromJson(host, model, target, superclassName, clazz), - await _generateToJson(host, model, target, superclassName, clazz) + await _generateFromJson( + host, model, qualifiedName, superclassName, target), + await _generateToJson(host, model, qualifiedName, superclassName, target) ]); } diff --git a/pkgs/_test_macros/lib/query_class.dart b/pkgs/_test_macros/lib/query_class.dart index a34c7acf..701a0308 100644 --- a/pkgs/_test_macros/lib/query_class.dart +++ b/pkgs/_test_macros/lib/query_class.dart @@ -26,12 +26,12 @@ class QueryClassImplementation implements ClassDefinitionsMacro { @override Future buildDefinitionsForClass( - Host host, AugmentRequest request) async { - final model = await host.query(Query( - target: request.target, + Interface target, Model model, Host host) async { + final result = await host.query(Query( + target: model.qualifiedNameOf(target.node), )); return AugmentResponse(augmentations: [ - Augmentation(code: expandTemplate('// ${json.encode(model)}')) + Augmentation(code: expandTemplate('// ${json.encode(result)}')) ]); } } diff --git a/pkgs/dart_model/lib/src/dart_model.dart b/pkgs/dart_model/lib/src/dart_model.dart index cf4257b7..bf9135e4 100644 --- a/pkgs/dart_model/lib/src/dart_model.dart +++ b/pkgs/dart_model/lib/src/dart_model.dart @@ -14,18 +14,16 @@ extension QualifiedNameExtension on QualifiedName { } extension ModelExtension on Model { - /// Returns the path in the model to [member], or `null` if [member] is not - /// in this [Model]. + /// Returns the path in the model to [node], or `null` if + /// [node] is not in this [Model]. /// /// Comparison is by identity, not by value, so the exact instance must be in /// this [Model]. /// - /// TODO(davidmorgan): this works for any node, but it's not clear yet which - /// types of node we want this functionality exposed for. - /// TODO(davidmorgan): a list of path segments is probably more useful than - /// `String`. - QualifiedName? qualifiedNameOfMember(Member member) => - _qualifiedNameOf(member.node); + /// TODO: Should we create a base type called `Declaration` which is + /// implemented by the types which are valid to pass here? + QualifiedName? qualifiedNameOf(Map node) => + _qualifiedNameOf(node); /// Returns the [QualifiedName] in the model to [node], or `null` if [node] is not in this [Model]. QualifiedName? _qualifiedNameOf(Map node) { diff --git a/pkgs/dart_model/test/model_test.dart b/pkgs/dart_model/test/model_test.dart index 7ffbbf6f..1fc8209d 100644 --- a/pkgs/dart_model/test/model_test.dart +++ b/pkgs/dart_model/test/model_test.dart @@ -111,7 +111,7 @@ void main() { test('can give the path to Members in buffer backed maps', () { final member = model.uris['package:dart_model/dart_model.dart']! .scopes['JsonData']!.members['_root']!; - expect(model.qualifiedNameOfMember(member)!.asString, + expect(model.qualifiedNameOf(member.node)!.asString, 'package:dart_model/dart_model.dart#JsonData'); }); @@ -119,7 +119,7 @@ void main() { final copiedModel = Model.fromJson(_copyMap(model.node)); final member = copiedModel.uris['package:dart_model/dart_model.dart']! .scopes['JsonData']!.members['_root']!; - expect(copiedModel.qualifiedNameOfMember(member)!.asString, + expect(copiedModel.qualifiedNameOf(member.node)!.asString, 'package:dart_model/dart_model.dart#JsonData'); }); @@ -129,7 +129,7 @@ void main() { (copiedModel.node['uris'] as Map)['loop'] = copiedModel; final member = copiedModel.uris['package:dart_model/dart_model.dart']! .scopes['JsonData']!.members['_root']!; - expect(() => copiedModel.qualifiedNameOfMember(member), throwsStateError); + expect(() => copiedModel.qualifiedNameOf(member.node), throwsStateError); }); test('path to Members throws on reused node', () { @@ -139,7 +139,7 @@ void main() { copiedModel.uris['package:dart_model/dart_model.dart']!; final member = copiedModel.uris['package:dart_model/dart_model.dart']! .scopes['JsonData']!.members['_root']!; - expect(() => copiedModel.qualifiedNameOfMember(member), throwsStateError); + expect(() => copiedModel.qualifiedNameOf(member.node), throwsStateError); }); test('path to Member returns null for Member in wrong Map', () { @@ -151,8 +151,8 @@ void main() { .scopes['JsonData']! .members['_root']! .node)); - expect(copiedModel.qualifiedNameOfMember(member), null); - expect(model.qualifiedNameOfMember(copiedMember), null); + expect(copiedModel.qualifiedNameOf(member.node), null); + expect(model.qualifiedNameOf(copiedMember.node), null); }); }); diff --git a/pkgs/macro/lib/macro.dart b/pkgs/macro/lib/macro.dart index 40376967..4b4322e1 100644 --- a/pkgs/macro/lib/macro.dart +++ b/pkgs/macro/lib/macro.dart @@ -28,21 +28,30 @@ abstract interface class Macro { /// want to contribute new type declarations to the library. abstract interface class LibraryTypesMacro implements Macro { FutureOr buildTypesForLibrary( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to a library directive, and /// want to contribute new non-type declarations to the library. abstract interface class LibraryDeclarationsMacro implements Macro { FutureOr buildDeclarationsForLibrary( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to a library directive, and /// want to provide definitions for declarations in the library. abstract interface class LibraryDefinitionsMacro implements Macro { FutureOr buildDefinitionsForLibrary( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any top level function, @@ -50,7 +59,10 @@ abstract interface class LibraryDefinitionsMacro implements Macro { /// declarations to the program. abstract interface class FunctionTypesMacro implements Macro { FutureOr buildTypesForFunction( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any top level function, @@ -58,7 +70,10 @@ abstract interface class FunctionTypesMacro implements Macro { /// declarations to the program. abstract interface class FunctionDeclarationsMacro implements Macro { FutureOr buildDeclarationsForFunction( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any top level function, @@ -66,7 +81,10 @@ abstract interface class FunctionDeclarationsMacro implements Macro { /// definition. abstract interface class FunctionDefinitionsMacro implements Macro { FutureOr buildDefinitionsForFunction( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any top level variable or @@ -74,7 +92,10 @@ abstract interface class FunctionDefinitionsMacro implements Macro { /// program. abstract interface class VariableTypesMacro implements Macro { FutureOr buildTypesForVariable( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any top level variable or @@ -82,189 +103,261 @@ abstract interface class VariableTypesMacro implements Macro { /// program. abstract interface class VariableDeclarationsMacro implements Macro { FutureOr buildDeclarationsForVariable( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any top level variable /// or instance field, and want to augment the variable definition. abstract interface class VariableDefinitionsMacro implements Macro { FutureOr buildDefinitionsForVariable( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any class, and want to /// contribute new type declarations to the program. abstract interface class ClassTypesMacro implements Macro { FutureOr buildTypesForClass( - Host host, AugmentRequest request); + Interface target, Model model, Host host); } /// The interface for [Macro]s that can be applied to any class, and want to /// contribute new non-type declarations to the program. abstract interface class ClassDeclarationsMacro implements Macro { FutureOr buildDeclarationsForClass( - Host host, AugmentRequest request); + Interface target, Model model, Host host); } /// The interface for [Macro]s that can be applied to any class, and want to /// augment the definitions of the members of that class. abstract interface class ClassDefinitionsMacro implements Macro { FutureOr buildDefinitionsForClass( - Host host, AugmentRequest request); + Interface target, Model model, Host host); } /// The interface for [Macro]s that can be applied to any enum, and want to /// contribute new type declarations to the program. abstract interface class EnumTypesMacro implements Macro { FutureOr buildTypesForEnum( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any enum, and want to /// contribute new non-type declarations to the program. abstract interface class EnumDeclarationsMacro implements Macro { FutureOr buildDeclarationsForEnum( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any enum, and want to /// augment the definitions of members or values of that enum. abstract interface class EnumDefinitionsMacro implements Macro { FutureOr buildDefinitionsForEnum( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any enum, and want to /// contribute new type declarations to the program. abstract interface class EnumValueTypesMacro implements Macro { FutureOr buildTypesForEnumValue( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any enum, and want to /// contribute new non-type declarations to the program. abstract interface class EnumValueDeclarationsMacro implements Macro { FutureOr buildDeclarationsForEnumValue( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any enum, and want to /// augment the definitions of members or values of that enum. abstract interface class EnumValueDefinitionsMacro implements Macro { FutureOr buildDefinitionsForEnumValue( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any field, and want to /// contribute new type declarations to the program. abstract interface class FieldTypesMacro implements Macro { FutureOr buildTypesForField( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any field, and want to /// contribute new type declarations to the program. abstract interface class FieldDeclarationsMacro implements Macro { FutureOr buildDeclarationsForField( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any field, and want to /// augment the field definition. abstract interface class FieldDefinitionsMacro implements Macro { FutureOr buildDefinitionsForField( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any method, and want to /// contribute new type declarations to the program. abstract interface class MethodTypesMacro implements Macro { FutureOr buildTypesForMethod( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any method, and want to /// contribute new non-type declarations to the program. abstract interface class MethodDeclarationsMacro implements Macro { FutureOr buildDeclarationsForMethod( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any method, and want to /// augment the function definition. abstract interface class MethodDefinitionsMacro implements Macro { FutureOr buildDefinitionsForMethod( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any constructor, and want /// to contribute new type declarations to the program. abstract interface class ConstructorTypesMacro implements Macro { FutureOr buildTypesForConstructor( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any constructors, and /// want to contribute new non-type declarations to the program. abstract interface class ConstructorDeclarationsMacro implements Macro { FutureOr buildDeclarationsForConstructor( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any constructor, and want /// to augment the function definition. abstract interface class ConstructorDefinitionsMacro implements Macro { FutureOr buildDefinitionsForConstructor( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any mixin declaration, and /// want to contribute new type declarations to the program. abstract interface class MixinTypesMacro implements Macro { FutureOr buildTypesForMixin( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any mixin declaration, and /// want to contribute new non-type declarations to the program. abstract interface class MixinDeclarationsMacro implements Macro { FutureOr buildDeclarationsForMixin( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any mixin declaration, and /// want to augment the definitions of the members of that mixin. abstract interface class MixinDefinitionsMacro implements Macro { FutureOr buildDefinitionsForMixin( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any extension declaration, /// and want to contribute new type declarations to the program. abstract interface class ExtensionTypesMacro implements Macro { FutureOr buildTypesForExtension( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any extension declaration, /// and want to contribute new non-type declarations to the program. abstract interface class ExtensionDeclarationsMacro implements Macro { FutureOr buildDeclarationsForExtension( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any extension declaration, /// and want to augment the definitions of the members of that extension. abstract interface class ExtensionDefinitionsMacro implements Macro { FutureOr buildDefinitionsForExtension( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any extension type /// declaration, and want to contribute new type declarations to the program. abstract interface class ExtensionTypeTypesMacro implements Macro { FutureOr buildTypesForExtensionType( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any extension type @@ -272,7 +365,10 @@ abstract interface class ExtensionTypeTypesMacro implements Macro { /// program. abstract interface class ExtensionTypeDeclarationsMacro implements Macro { FutureOr buildDeclarationsForExtensionType( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any extension type @@ -280,14 +376,20 @@ abstract interface class ExtensionTypeDeclarationsMacro implements Macro { /// extension. abstract interface class ExtensionTypeDefinitionsMacro implements Macro { FutureOr buildDefinitionsForExtensionType( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any type alias /// declaration, and want to contribute new type declarations to the program. abstract interface class TypeAliasTypesMacro implements Macro { FutureOr buildTypesForTypeAlias( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } /// The interface for [Macro]s that can be applied to any type alias @@ -295,5 +397,8 @@ abstract interface class TypeAliasTypesMacro implements Macro { /// program. abstract interface class TypeAliasDeclarationsMacro implements Macro { FutureOr buildDeclarationsForTypeAlias( - Host host, AugmentRequest request); + // TODO: Fill in a real type once we have it + Object target, + Model model, + Host host); } From b9b677ebb2ceb221bbc28eb8188f7c2dc126a625 Mon Sep 17 00:00:00 2001 From: Jake Macdonald Date: Tue, 15 Oct 2024 18:15:41 +0000 Subject: [PATCH 2/7] add model to AugmentRequest, support passing it in implementations --- .../lib/macro_implementation.dart | 28 ++++++++-- .../_cfe_macros/lib/macro_implementation.dart | 28 ++++++++-- pkgs/_macro_client/lib/src/execute_macro.dart | 22 ++++---- .../_macro_client/test/macro_client_test.dart | 51 ++++++------------- pkgs/_macro_host/lib/macro_host.dart | 3 ++ pkgs/_macro_host/test/macro_host_test.dart | 29 ++++------- .../_macro_server/test/macro_server_test.dart | 18 ++++--- pkgs/dart_model/lib/src/dart_model.dart | 33 ++++++------ .../lib/src/macro_service.g.dart | 13 +++-- schemas/macro_service.schema.json | 4 ++ .../dart_model_generator/lib/definitions.dart | 9 +++- 11 files changed, 139 insertions(+), 99 deletions(-) diff --git a/pkgs/_analyzer_macros/lib/macro_implementation.dart b/pkgs/_analyzer_macros/lib/macro_implementation.dart index 09b48b08..07501187 100644 --- a/pkgs/_analyzer_macros/lib/macro_implementation.dart +++ b/pkgs/_analyzer_macros/lib/macro_implementation.dart @@ -81,6 +81,16 @@ class AnalyzerRunningMacro implements injected.RunningMacro { return AnalyzerRunningMacro._(impl, name, implementation); } + /// Queries for [target] and returns the [Model] representing the result. + /// + /// TODO: Make this a more limited query which doesn't fetch members. + Future _queryTarget(QualifiedName target) async => + (await _impl._host.hostService.handle(MacroRequest.queryRequest( + QueryRequest(query: Query(target: target)), + id: nextRequestId))) + .asQueryResponse + .model; + @override Future executeDeclarationsPhase( macros_api_v1.MacroTarget target, @@ -91,7 +101,11 @@ class AnalyzerRunningMacro implements injected.RunningMacro { return await AnalyzerMacroExecutionResult.dartModelToInjected( target, await _impl._host.augment( - name, AugmentRequest(phase: 2, target: target.qualifiedName))); + name, + AugmentRequest( + phase: 2, + target: target.qualifiedName, + model: await _queryTarget(target.qualifiedName)))); } @override @@ -104,7 +118,11 @@ class AnalyzerRunningMacro implements injected.RunningMacro { return await AnalyzerMacroExecutionResult.dartModelToInjected( target, await _impl._host.augment( - name, AugmentRequest(phase: 3, target: target.qualifiedName))); + name, + AugmentRequest( + phase: 3, + target: target.qualifiedName, + model: await _queryTarget(target.qualifiedName)))); } @override @@ -116,7 +134,11 @@ class AnalyzerRunningMacro implements injected.RunningMacro { return await AnalyzerMacroExecutionResult.dartModelToInjected( target, await _impl._host.augment( - name, AugmentRequest(phase: 1, target: target.qualifiedName))); + name, + AugmentRequest( + phase: 1, + target: target.qualifiedName, + model: await _queryTarget(target.qualifiedName)))); } } diff --git a/pkgs/_cfe_macros/lib/macro_implementation.dart b/pkgs/_cfe_macros/lib/macro_implementation.dart index 746e494b..7882c12b 100644 --- a/pkgs/_cfe_macros/lib/macro_implementation.dart +++ b/pkgs/_cfe_macros/lib/macro_implementation.dart @@ -81,6 +81,16 @@ class CfeRunningMacro implements injected.RunningMacro { return CfeRunningMacro._(impl, name, implementation); } + /// Queries for [target] and returns the [Model] representing the result. + /// + /// TODO: Make this a more limited query which doesn't fetch members. + Future _queryTarget(QualifiedName target) async => + (await _impl._host.hostService.handle(MacroRequest.queryRequest( + QueryRequest(query: Query(target: target)), + id: nextRequestId))) + .asQueryResponse + .model; + @override Future executeDeclarationsPhase( macros_api_v1.MacroTarget target, @@ -91,7 +101,11 @@ class CfeRunningMacro implements injected.RunningMacro { return await CfeMacroExecutionResult.dartModelToInjected( target, await _impl._host.augment( - name, AugmentRequest(phase: 2, target: target.qualifiedName))); + name, + AugmentRequest( + phase: 2, + target: target.qualifiedName, + model: await _queryTarget(target.qualifiedName)))); } @override @@ -104,7 +118,11 @@ class CfeRunningMacro implements injected.RunningMacro { return await CfeMacroExecutionResult.dartModelToInjected( target, await _impl._host.augment( - name, AugmentRequest(phase: 3, target: target.qualifiedName))); + name, + AugmentRequest( + phase: 3, + target: target.qualifiedName, + model: await _queryTarget(target.qualifiedName)))); } @override @@ -116,7 +134,11 @@ class CfeRunningMacro implements injected.RunningMacro { return await CfeMacroExecutionResult.dartModelToInjected( target, await _impl._host.augment( - name, AugmentRequest(phase: 1, target: target.qualifiedName))); + name, + AugmentRequest( + phase: 1, + target: target.qualifiedName, + model: await _queryTarget(target.qualifiedName)))); } } diff --git a/pkgs/_macro_client/lib/src/execute_macro.dart b/pkgs/_macro_client/lib/src/execute_macro.dart index 1a9267c4..7fbc6656 100644 --- a/pkgs/_macro_client/lib/src/execute_macro.dart +++ b/pkgs/_macro_client/lib/src/execute_macro.dart @@ -12,13 +12,12 @@ import 'package:macro_service/macro_service.dart'; Future executeTypesMacro( Macro macro, Host host, AugmentRequest request) async { final target = request.target; - // TODO: https://github.com/dart-lang/macros/issues/100. - final queryResult = await host.query(Query(target: target)); - final interface = queryResult.uris[target.uri]!.scopes[target.name]!; + final model = request.model; + final interface = model.uris[target.uri]!.scopes[target.name]!; switch ((interface.properties, macro)) { case (Properties(isClass: true), ClassTypesMacro macro): - return await macro.buildTypesForClass(interface, queryResult, host); + return await macro.buildTypesForClass(interface, model, host); case (_, LibraryTypesMacro()): case (_, ConstructorTypesMacro()): case (_, MethodTypesMacro()): @@ -42,14 +41,12 @@ Future executeTypesMacro( Future executeDeclarationsMacro( Macro macro, Host host, AugmentRequest request) async { final target = request.target; - // TODO: https://github.com/dart-lang/macros/issues/100. - final queryResult = await host.query(Query(target: target)); - final interface = queryResult.uris[target.uri]!.scopes[target.name]!; + final model = request.model; + final interface = model.uris[target.uri]!.scopes[target.name]!; switch ((interface.properties, macro)) { case (Properties(isClass: true), ClassDeclarationsMacro macro): - return await macro.buildDeclarationsForClass( - interface, queryResult, host); + return await macro.buildDeclarationsForClass(interface, model, host); case (_, LibraryDeclarationsMacro()): case (_, EnumDeclarationsMacro()): case (_, ExtensionDeclarationsMacro()): @@ -73,13 +70,12 @@ Future executeDeclarationsMacro( Future executeDefinitionsMacro( Macro macro, Host host, AugmentRequest request) async { final target = request.target; - // TODO: https://github.com/dart-lang/macros/issues/100. - final queryResult = await host.query(Query(target: target)); - final interface = queryResult.uris[target.uri]!.scopes[target.name]!; + final model = request.model; + final interface = model.uris[target.uri]!.scopes[target.name]!; switch ((interface.properties, macro)) { case (Properties(isClass: true), ClassDefinitionsMacro macro): - return await macro.buildDefinitionsForClass(interface, queryResult, host); + return await macro.buildDefinitionsForClass(interface, model, host); case (_, LibraryDefinitionsMacro()): case (_, EnumDefinitionsMacro()): case (_, ExtensionDefinitionsMacro()): diff --git a/pkgs/_macro_client/test/macro_client_test.dart b/pkgs/_macro_client/test/macro_client_test.dart index 54fde700..5838d8ad 100644 --- a/pkgs/_macro_client/test/macro_client_test.dart +++ b/pkgs/_macro_client/test/macro_client_test.dart @@ -14,7 +14,10 @@ import 'package:macro_service/macro_service.dart'; import 'package:test/test.dart'; void main() { - final target = QualifiedName.parse('package:a/a.dart#A'); + final fooTarget = QualifiedName(name: 'Foo', uri: 'package:foo/foo.dart'); + final fooModel = Scope.query.run(() => Model() + ..uris[fooTarget.uri] = (Library() + ..scopes['Foo'] = Interface(properties: Properties(isClass: true)))); for (final protocol in [ Protocol(encoding: ProtocolEncoding.json, version: ProtocolVersion.macros1), @@ -42,29 +45,6 @@ void main() { return result; } - void answerTargetQuery(MacroRequest targetQuery, Socket socket) { - expect( - targetQuery, - { - 'id': targetQuery.id, - 'type': 'QueryRequest', - 'value': { - 'query': {'target': target} - }, - }, - ); - Scope.query.run(() => protocol.send( - socket.add, - Response.queryResponse( - QueryResponse( - model: Model() - ..uris[target.uri] = (Library() - ..scopes[target.name] = Interface( - properties: (Properties(isClass: true))))), - requestId: targetQuery.id) - .node)); - } - test('connects to service', () async { final serverSocket = await ServerSocket.bind('localhost', 0); addTearDown(serverSocket.close); @@ -98,7 +78,8 @@ void main() { macroAnnotation: QualifiedName( uri: 'package:_test_macros/declare_x_macro.dart', name: 'DeclareX'), - AugmentRequest(phase: 2)) + AugmentRequest( + phase: 2, target: fooTarget, model: fooModel)) .node); final augmentResponse = await responses.next; @@ -145,9 +126,9 @@ void main() { macroAnnotation: QualifiedName( uri: 'package:_test_macros/declare_x_macro.dart', name: 'DeclareX'), - AugmentRequest(phase: 2, target: target)) + AugmentRequest( + phase: 2, target: fooTarget, model: fooModel)) .node); - answerTargetQuery(MacroRequest.fromJson(await responses.next), socket); final augmentResponse = await responses.next; expect(augmentResponse, { @@ -201,9 +182,8 @@ void main() { macroAnnotation: QualifiedName( uri: 'package:_test_macros/query_class.dart', name: 'QueryClass'), - AugmentRequest(phase: 3, target: target), + AugmentRequest(phase: 3, target: fooTarget, model: fooModel), ).node); - answerTargetQuery(MacroRequest.fromJson(await responses.next), socket); final queryRequest = await responses.next; final queryRequestId = MacroRequest.fromJson(queryRequest).id; @@ -213,15 +193,14 @@ void main() { 'id': queryRequestId, 'type': 'QueryRequest', 'value': { - 'query': {'target': target} + 'query': {'target': fooTarget} }, }, ); Scope.query.run(() => protocol.send( socket.add, - Response.queryResponse( - QueryResponse(model: Model()..uris[target.uri] = Library()), + Response.queryResponse(QueryResponse(model: fooModel), requestId: queryRequestId) .node)); @@ -237,7 +216,9 @@ void main() { 'code': [ { 'type': 'String', - 'value': '// {"uris":{"${target.uri}":{"scopes":{}}}}' + 'value': + '// {"uris":{"${fooTarget.uri}":{"scopes":{"Foo":' + '{"members":{},"properties":{"isClass":true}}}}}}' } ] } @@ -270,10 +251,8 @@ void main() { macroAnnotation: QualifiedName( uri: 'package:_test_macros/query_class.dart', name: 'QueryClass'), - AugmentRequest(phase: 3, target: target), + AugmentRequest(phase: 3, target: fooTarget, model: fooModel), ).node); - unawaited(responses.next.then((response) => - answerTargetQuery(MacroRequest.fromJson(response), socket))); } final queryRequest1 = await responses.next; diff --git a/pkgs/_macro_host/lib/macro_host.dart b/pkgs/_macro_host/lib/macro_host.dart index 7878a48c..2add1924 100644 --- a/pkgs/_macro_host/lib/macro_host.dart +++ b/pkgs/_macro_host/lib/macro_host.dart @@ -23,6 +23,9 @@ class MacroHost { final MacroBuilder macroBuilder = MacroBuilder(); final MacroRunner macroRunner = MacroRunner(); + /// We only want to expose the public interface and not the private impl. + HostService get hostService => _hostService; + MacroHost._(this.macroPackageConfig, this.macroServer, this._hostService); /// Starts a macro host with introspection queries handled by [queryService]. diff --git a/pkgs/_macro_host/test/macro_host_test.dart b/pkgs/_macro_host/test/macro_host_test.dart index c8c1da83..d453a777 100644 --- a/pkgs/_macro_host/test/macro_host_test.dart +++ b/pkgs/_macro_host/test/macro_host_test.dart @@ -10,6 +10,11 @@ import 'package:macro_service/macro_service.dart'; import 'package:test/test.dart'; void main() { + final fooTarget = QualifiedName(name: 'Foo', uri: 'package:foo/foo.dart'); + final fooModel = Scope.query.run(() => Model() + ..uris[fooTarget.uri] = (Library() + ..scopes['Foo'] = Interface(properties: Properties(isClass: true)))); + for (final protocol in [ Protocol(encoding: ProtocolEncoding.json, version: ProtocolVersion.macros1), Protocol( @@ -33,12 +38,8 @@ void main() { await host.queryMacroPhases(packageConfig, macroAnnotation), {2}); expect( - await host.augment( - macroAnnotation, - AugmentRequest( - phase: 2, - target: QualifiedName( - name: 'Foo', uri: 'package:foo/foo.dart'))), + await host.augment(macroAnnotation, + AugmentRequest(phase: 2, target: fooTarget, model: fooModel)), Scope.macro.run(() => AugmentResponse(augmentations: [ Augmentation(code: [Code.string('int get x => 3;')]) ]))); @@ -61,12 +62,8 @@ void main() { await host.queryMacroPhases(packageConfig, macroAnnotation), {3}); expect( - await host.augment( - macroAnnotation, - AugmentRequest( - phase: 3, - target: QualifiedName( - uri: 'package:foo/foo.dart', name: 'Foo'))), + await host.augment(macroAnnotation, + AugmentRequest(phase: 3, target: fooTarget, model: fooModel)), Scope.macro.run(() => AugmentResponse(augmentations: [ Augmentation(code: [ Code.string( @@ -92,12 +89,8 @@ void main() { queryService: queryService); for (final macroName in macroNames) { - await host.augment( - macroName, - AugmentRequest( - phase: 3, - target: - QualifiedName(uri: 'package:foo/foo.dart', name: 'Foo'))); + await host.augment(macroName, + AugmentRequest(phase: 3, target: fooTarget, model: fooModel)); } }); }); diff --git a/pkgs/_macro_server/test/macro_server_test.dart b/pkgs/_macro_server/test/macro_server_test.dart index 342cf7ef..96dfc01e 100644 --- a/pkgs/_macro_server/test/macro_server_test.dart +++ b/pkgs/_macro_server/test/macro_server_test.dart @@ -13,6 +13,11 @@ import 'package:macro_service/macro_service.dart'; import 'package:test/test.dart'; void main() { + final fooTarget = QualifiedName(name: 'Foo', uri: 'package:foo/foo.dart'); + final fooModel = Scope.query.run(() => Model() + ..uris[fooTarget.uri] = (Library() + ..scopes['Foo'] = Interface(properties: Properties(isClass: true)))); + for (final protocol in [ Protocol(encoding: ProtocolEncoding.json, version: ProtocolVersion.macros1), Protocol( @@ -37,7 +42,8 @@ void main() { final server = await MacroServer.serve(protocol: protocol, service: service); expect( - server.sendToMacro(HostRequest.augmentRequest(AugmentRequest(), + server.sendToMacro(HostRequest.augmentRequest( + AugmentRequest(phase: 1, target: fooTarget, model: fooModel), id: 1, macroAnnotation: QualifiedName( uri: 'package:_test_macros/test_macros.dart', @@ -58,7 +64,7 @@ void main() { macroAnnotation: QualifiedName( uri: 'package:_test_macros/declare_x_macro.dart', name: 'DeclareX'), - AugmentRequest(phase: 1), + AugmentRequest(phase: 1, target: fooTarget, model: fooModel), )); }); @@ -80,14 +86,14 @@ void main() { macroAnnotation: QualifiedName( uri: 'package:_test_macros/declare_x_macro.dart', name: 'DeclareX'), - AugmentRequest(phase: 1), + AugmentRequest(phase: 1, target: fooTarget, model: fooModel), )), server.sendToMacro(HostRequest.augmentRequest( id: 2, macroAnnotation: QualifiedName( uri: 'package:_test_macros/query_class.dart', name: 'QueryClass'), - AugmentRequest(phase: 1))) + AugmentRequest(phase: 1, target: fooTarget, model: fooModel))) ]); }); @@ -108,14 +114,14 @@ void main() { macroAnnotation: QualifiedName( uri: 'package:_test_macros/declare_x_macro.dart', name: 'DeclareX'), - AugmentRequest(phase: 1), + AugmentRequest(phase: 1, target: fooTarget, model: fooModel), )), server.sendToMacro(HostRequest.augmentRequest( id: 2, macroAnnotation: QualifiedName( uri: 'package:_test_macros/query_class.dart', name: 'QueryClass'), - AugmentRequest(phase: 1), + AugmentRequest(phase: 1, target: fooTarget, model: fooModel), )) ]); }); diff --git a/pkgs/dart_model/lib/src/dart_model.dart b/pkgs/dart_model/lib/src/dart_model.dart index bf9135e4..c5e7a990 100644 --- a/pkgs/dart_model/lib/src/dart_model.dart +++ b/pkgs/dart_model/lib/src/dart_model.dart @@ -25,23 +25,26 @@ extension ModelExtension on Model { QualifiedName? qualifiedNameOf(Map node) => _qualifiedNameOf(node); - /// Returns the [QualifiedName] in the model to [node], or `null` if [node] is not in this [Model]. + /// Returns the [QualifiedName] in the model to [node], or `null` if [node] + /// is not in this [Model]. QualifiedName? _qualifiedNameOf(Map node) { - final members = _getParent(node); - if (members == null) return null; - final interface = _getParent(members); - if (interface == null) return null; - final scopes = _getParent(interface); - if (scopes == null) return null; - final library = _getParent(scopes); - if (library == null) return null; - final libraries = _getParent(library); - if (libraries == null) return null; - - final uri = _keyOf(library, libraries); - final name = _keyOf(interface, scopes); + var parent = _getParent(node); + if (parent == null) return null; + final path = []; + path.add(_keyOf(node, parent)); + var previousParent = parent; + while ((parent = _getParent(previousParent)) != this.node) { + if (parent == null) return null; + path.insert(0, _keyOf(previousParent, parent)); + previousParent = parent; + } - return QualifiedName(uri: uri, name: name); + if (path case [String uri, 'scopes', String name]) { + return QualifiedName(uri: uri, name: name); + } + throw UnsupportedError( + 'Unsupported node type for `qualifiedNameOf`, only top level members ' + 'are supported for now. $path'); } /// Returns the key of [value] in [map]. diff --git a/pkgs/macro_service/lib/src/macro_service.g.dart b/pkgs/macro_service/lib/src/macro_service.g.dart index 7364aada..6816688a 100644 --- a/pkgs/macro_service/lib/src/macro_service.g.dart +++ b/pkgs/macro_service/lib/src/macro_service.g.dart @@ -14,11 +14,13 @@ import 'package:dart_model/src/scopes.dart'; extension type AugmentRequest.fromJson(Map node) implements Object { AugmentRequest({ - int? phase, - QualifiedName? target, + required int phase, + required QualifiedName target, + required Model model, }) : this.fromJson({ - if (phase != null) 'phase': phase, - if (target != null) 'target': target, + 'phase': phase, + 'target': target, + 'model': model, }); /// Which phase to run: 1, 2 or 3. @@ -26,6 +28,9 @@ extension type AugmentRequest.fromJson(Map node) /// The class to augment. TODO(davidmorgan): expand to more types of target. QualifiedName get target => node['target'] as QualifiedName; + + /// A pre-computed query result for the target. + Model get model => node['model'] as Model; } /// Macro's response to an [AugmentRequest]: the resulting augmentations. diff --git a/schemas/macro_service.schema.json b/schemas/macro_service.schema.json index fdc68b9a..1ee3da6e 100644 --- a/schemas/macro_service.schema.json +++ b/schemas/macro_service.schema.json @@ -23,6 +23,10 @@ "target": { "$comment": "The class to augment. TODO(davidmorgan): expand to more types of target.", "$ref": "file:dart_model.schema.json#/$defs/QualifiedName" + }, + "model": { + "$comment": "A pre-computed query result for the target.", + "$ref": "file:dart_model.schema.json#/$defs/Model" } } }, diff --git a/tool/dart_model_generator/lib/definitions.dart b/tool/dart_model_generator/lib/definitions.dart index fb0a4639..9d846368 100644 --- a/tool/dart_model_generator/lib/definitions.dart +++ b/tool/dart_model_generator/lib/definitions.dart @@ -349,11 +349,18 @@ static QualifiedName parse(String string) { description: 'A request to a macro to augment some code.', properties: [ Property('phase', - type: 'int', description: 'Which phase to run: 1, 2 or 3.'), + type: 'int', + required: true, + description: 'Which phase to run: 1, 2 or 3.'), Property('target', type: 'QualifiedName', + required: true, description: 'The class to augment. ' 'TODO(davidmorgan): expand to more types of target.'), + Property('model', + type: 'Model', + required: true, + description: 'A pre-computed query result for the target.'), ]), Definition.clazz('AugmentResponse', description: From c8ab828d674055877d255774b6992cf162a847ae Mon Sep 17 00:00:00 2001 From: Jake Macdonald Date: Tue, 15 Oct 2024 19:54:09 +0000 Subject: [PATCH 3/7] fix some tests --- pkgs/dart_model/lib/src/dart_model.dart | 2 +- pkgs/dart_model/test/model_test.dart | 23 ++++++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/pkgs/dart_model/lib/src/dart_model.dart b/pkgs/dart_model/lib/src/dart_model.dart index c5e7a990..75a43178 100644 --- a/pkgs/dart_model/lib/src/dart_model.dart +++ b/pkgs/dart_model/lib/src/dart_model.dart @@ -39,7 +39,7 @@ extension ModelExtension on Model { previousParent = parent; } - if (path case [String uri, 'scopes', String name]) { + if (path case [final uri, 'scopes', final name]) { return QualifiedName(uri: uri, name: name); } throw UnsupportedError( diff --git a/pkgs/dart_model/test/model_test.dart b/pkgs/dart_model/test/model_test.dart index 1fc8209d..22a8370b 100644 --- a/pkgs/dart_model/test/model_test.dart +++ b/pkgs/dart_model/test/model_test.dart @@ -108,10 +108,26 @@ void main() { 'JsonData']!['members']); }); + test('can give the path to Interfaces in buffer backed maps', () { + final interface = + model.uris['package:dart_model/dart_model.dart']!.scopes['JsonData']!; + expect(model.qualifiedNameOf(interface.node)!.asString, + 'package:dart_model/dart_model.dart#JsonData'); + }); + test('can give the path to Members in buffer backed maps', () { final member = model.uris['package:dart_model/dart_model.dart']! .scopes['JsonData']!.members['_root']!; - expect(model.qualifiedNameOf(member.node)!.asString, + expect(() => model.qualifiedNameOf(member.node)!.asString, + throwsUnsupportedError, + reason: 'Requires https://github.com/dart-lang/macros/pull/101'); + }); + + test('can give the path to Interfaces in SDK maps', () { + final copiedModel = Model.fromJson(_copyMap(model.node)); + final interface = copiedModel + .uris['package:dart_model/dart_model.dart']!.scopes['JsonData']!; + expect(copiedModel.qualifiedNameOf(interface.node)!.asString, 'package:dart_model/dart_model.dart#JsonData'); }); @@ -119,8 +135,9 @@ void main() { final copiedModel = Model.fromJson(_copyMap(model.node)); final member = copiedModel.uris['package:dart_model/dart_model.dart']! .scopes['JsonData']!.members['_root']!; - expect(copiedModel.qualifiedNameOf(member.node)!.asString, - 'package:dart_model/dart_model.dart#JsonData'); + expect(() => copiedModel.qualifiedNameOf(member.node)!.asString, + throwsUnsupportedError, + reason: 'Requires https://github.com/dart-lang/macros/pull/101'); }); test('path to Members throws on cycle', () { From 885c25423e06cfee0acfb014778c68db80daebaf Mon Sep 17 00:00:00 2001 From: Jake Macdonald Date: Fri, 18 Oct 2024 17:43:13 +0000 Subject: [PATCH 4/7] run initial query in the query scope, add the model to the type system --- .../lib/macro_implementation.dart | 11 ++--- .../_cfe_macros/lib/macro_implementation.dart | 11 ++--- pkgs/_macro_client/lib/macro_client.dart | 44 ++++++++++--------- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/pkgs/_analyzer_macros/lib/macro_implementation.dart b/pkgs/_analyzer_macros/lib/macro_implementation.dart index 07501187..e4fc739e 100644 --- a/pkgs/_analyzer_macros/lib/macro_implementation.dart +++ b/pkgs/_analyzer_macros/lib/macro_implementation.dart @@ -84,12 +84,13 @@ class AnalyzerRunningMacro implements injected.RunningMacro { /// Queries for [target] and returns the [Model] representing the result. /// /// TODO: Make this a more limited query which doesn't fetch members. - Future _queryTarget(QualifiedName target) async => - (await _impl._host.hostService.handle(MacroRequest.queryRequest( - QueryRequest(query: Query(target: target)), - id: nextRequestId))) + Future _queryTarget(QualifiedName target) => + Scope.query.run(() async => (await _impl._host.hostService.handle( + MacroRequest.queryRequest( + QueryRequest(query: Query(target: target)), + id: nextRequestId))) .asQueryResponse - .model; + .model); @override Future executeDeclarationsPhase( diff --git a/pkgs/_cfe_macros/lib/macro_implementation.dart b/pkgs/_cfe_macros/lib/macro_implementation.dart index 7882c12b..a4c86849 100644 --- a/pkgs/_cfe_macros/lib/macro_implementation.dart +++ b/pkgs/_cfe_macros/lib/macro_implementation.dart @@ -84,12 +84,13 @@ class CfeRunningMacro implements injected.RunningMacro { /// Queries for [target] and returns the [Model] representing the result. /// /// TODO: Make this a more limited query which doesn't fetch members. - Future _queryTarget(QualifiedName target) async => - (await _impl._host.hostService.handle(MacroRequest.queryRequest( - QueryRequest(query: Query(target: target)), - id: nextRequestId))) + Future _queryTarget(QualifiedName target) => + Scope.query.run(() async => (await _impl._host.hostService.handle( + MacroRequest.queryRequest( + QueryRequest(query: Query(target: target)), + id: nextRequestId))) .asQueryResponse - .model; + .model); @override Future executeDeclarationsPhase( diff --git a/pkgs/_macro_client/lib/macro_client.dart b/pkgs/_macro_client/lib/macro_client.dart index 39ecb573..58f96ba4 100644 --- a/pkgs/_macro_client/lib/macro_client.dart +++ b/pkgs/_macro_client/lib/macro_client.dart @@ -112,27 +112,29 @@ class MacroClient { '${hostRequest.macroAnnotation.asString}'))); } else { final augmentRequest = hostRequest.asAugmentRequest; - await Scope.macro - .runAsync(() async => _sendResponse(Response.augmentResponse( - switch (augmentRequest.phase) { - 1 => macro.description.runsInPhases.contains(1) - ? await executeTypesMacro( - macro, _host, augmentRequest) - : null, - 2 => macro.description.runsInPhases.contains(2) - ? await executeDeclarationsMacro( - macro, _host, augmentRequest) - : null, - 3 => macro.description.runsInPhases.contains(3) - ? await executeDefinitionsMacro( - macro, _host, augmentRequest) - : null, - _ => throw StateError( - 'Unexpected phase ${augmentRequest.phase}, ' - 'expected 1, 2, or 3.') - } ?? - AugmentResponse(augmentations: []), - requestId: hostRequest.id))); + await Scope.macro.runAsync(() async { + MacroScope.current.addModel(augmentRequest.model); + return _sendResponse(Response.augmentResponse( + switch (augmentRequest.phase) { + 1 => macro.description.runsInPhases.contains(1) + ? await executeTypesMacro( + macro, _host, augmentRequest) + : null, + 2 => macro.description.runsInPhases.contains(2) + ? await executeDeclarationsMacro( + macro, _host, augmentRequest) + : null, + 3 => macro.description.runsInPhases.contains(3) + ? await executeDefinitionsMacro( + macro, _host, augmentRequest) + : null, + _ => throw StateError( + 'Unexpected phase ${augmentRequest.phase}, ' + 'expected 1, 2, or 3.') + } ?? + AugmentResponse(augmentations: []), + requestId: hostRequest.id)); + }); } default: // Ignore unknown request. From 6a45e7c58b56d32b025b06a49fab61b904edf9cd Mon Sep 17 00:00:00 2001 From: Jake Macdonald Date: Fri, 18 Oct 2024 17:59:13 +0000 Subject: [PATCH 5/7] add some try/catch blocks to work around lack of query expressiveness --- pkgs/_analyzer_macros/lib/query_service.dart | 96 ++++++++++---------- pkgs/_cfe_macros/lib/query_service.dart | 9 +- 2 files changed, 57 insertions(+), 48 deletions(-) diff --git a/pkgs/_analyzer_macros/lib/query_service.dart b/pkgs/_analyzer_macros/lib/query_service.dart index b78ae3ad..af79a872 100644 --- a/pkgs/_analyzer_macros/lib/query_service.dart +++ b/pkgs/_analyzer_macros/lib/query_service.dart @@ -36,52 +36,56 @@ class AnalyzerQueryService implements QueryService { ..addInterfaceElement(clazz); final interface = Interface(properties: Properties(isClass: true)); - for (final constructor in clazz.constructors) { - interface.members[constructor.name] = Member( - requiredPositionalParameters: constructor - .requiredPositionalParameters(types.translator, types.context), - optionalPositionalParameters: constructor - .optionalPositionalParameters(types.translator, types.context), - namedParameters: - constructor.namedParameters(types.translator, types.context), - properties: Properties( - isAbstract: constructor.isAbstract, - isConstructor: true, - isGetter: false, - isField: false, - isMethod: false, - isStatic: false, - )); - } - for (final field in clazz.fields) { - interface.members[field.name] = Member( - properties: Properties( - isAbstract: field.isAbstract, - isConstructor: false, - isGetter: false, - isField: true, - isMethod: false, - isStatic: field.isStatic, - ), - returnType: types.addDartType(field.type)); - } - for (final method in clazz.methods) { - interface.members[method.name] = Member( - requiredPositionalParameters: method.requiredPositionalParameters( - types.translator, types.context), - optionalPositionalParameters: method.optionalPositionalParameters( - types.translator, types.context), - namedParameters: - method.namedParameters(types.translator, types.context), - properties: Properties( - isAbstract: method.isAbstract, - isConstructor: false, - isGetter: false, - isField: false, - isMethod: true, - isStatic: method.isStatic, - ), - returnType: types.addDartType(method.returnType)); + try { + for (final constructor in clazz.constructors) { + interface.members[constructor.name] = Member( + requiredPositionalParameters: constructor + .requiredPositionalParameters(types.translator, types.context), + optionalPositionalParameters: constructor + .optionalPositionalParameters(types.translator, types.context), + namedParameters: + constructor.namedParameters(types.translator, types.context), + properties: Properties( + isAbstract: constructor.isAbstract, + isConstructor: true, + isGetter: false, + isField: false, + isMethod: false, + isStatic: false, + )); + } + for (final field in clazz.fields) { + interface.members[field.name] = Member( + properties: Properties( + isAbstract: field.isAbstract, + isConstructor: false, + isGetter: false, + isField: true, + isMethod: false, + isStatic: field.isStatic, + ), + returnType: types.addDartType(field.type)); + } + for (final method in clazz.methods) { + interface.members[method.name] = Member( + requiredPositionalParameters: method.requiredPositionalParameters( + types.translator, types.context), + optionalPositionalParameters: method.optionalPositionalParameters( + types.translator, types.context), + namedParameters: + method.namedParameters(types.translator, types.context), + properties: Properties( + isAbstract: method.isAbstract, + isConstructor: false, + isGetter: false, + isField: false, + isMethod: true, + isStatic: method.isStatic, + ), + returnType: types.addDartType(method.returnType)); + } + } catch (_) { + // TODO: Fails in types phase, implement fine grained queries. } return Model(types: types.typeHierarchy) ..uris[uri] = (Library()..scopes[clazz.name] = interface); diff --git a/pkgs/_cfe_macros/lib/query_service.dart b/pkgs/_cfe_macros/lib/query_service.dart index 064041f1..f153200a 100644 --- a/pkgs/_cfe_macros/lib/query_service.dart +++ b/pkgs/_cfe_macros/lib/query_service.dart @@ -57,8 +57,13 @@ class CfeQueryService implements QueryService { isStatic: current.isStatic, )); } - - return Model(types: _buildTypeHierarchy({classBuilder.actualCls})) + TypeHierarchy? types; + try { + types = _buildTypeHierarchy({classBuilder.actualCls}); + } catch (_) { + // TODO: Fails in types phase, implement fine grained queries. + } + return Model(types: types) ..uris[uri] = (Library() .. // TODO(davidmorgan): return more than just fields. From a7bc967334de0b1773015c83d80160a791cdd873 Mon Sep 17 00:00:00 2001 From: Jake Macdonald Date: Mon, 21 Oct 2024 16:13:56 +0000 Subject: [PATCH 6/7] fix test expectations --- pkgs/_macro_client/test/macro_client_test.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkgs/_macro_client/test/macro_client_test.dart b/pkgs/_macro_client/test/macro_client_test.dart index ba8e2e8e..23e64923 100644 --- a/pkgs/_macro_client/test/macro_client_test.dart +++ b/pkgs/_macro_client/test/macro_client_test.dart @@ -140,7 +140,7 @@ void main() { 'interfaceAugmentations': {}, 'mixinAugmentations': {}, 'typeAugmentations': { - 'A': [ + 'Foo': [ { 'code': [ { @@ -222,7 +222,7 @@ void main() { 'interfaceAugmentations': {}, 'mixinAugmentations': {}, 'typeAugmentations': { - 'A': [ + 'Foo': [ { 'code': [ { @@ -302,7 +302,7 @@ void main() { 'interfaceAugmentations': {}, 'mixinAugmentations': {}, 'typeAugmentations': { - 'A': [ + 'Foo': [ { 'code': [ { @@ -329,7 +329,7 @@ void main() { 'interfaceAugmentations': {}, 'mixinAugmentations': {}, 'typeAugmentations': { - 'A': [ + 'Foo': [ { 'code': [ { From e9927253de635e5f8fc811093ade820a9b3d9218 Mon Sep 17 00:00:00 2001 From: Jake Macdonald Date: Mon, 21 Oct 2024 16:14:32 +0000 Subject: [PATCH 7/7] regenerate schema --- schemas/macro_service.schema.json | 61 ++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/schemas/macro_service.schema.json b/schemas/macro_service.schema.json index 1ee3da6e..5210275b 100644 --- a/schemas/macro_service.schema.json +++ b/schemas/macro_service.schema.json @@ -34,12 +34,69 @@ "type": "object", "description": "Macro's response to an [AugmentRequest]: the resulting augmentations.", "properties": { - "augmentations": { + "enumValueAugmentations": { + "type": "object", + "description": "Any augmentations to enum values that should be applied to an enum as a result of executing a macro, indexed by the name of the enum.", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "file:dart_model.schema.json#/$defs/Augmentation" + } + } + }, + "extendsTypeAugmentations": { + "type": "object", + "description": "Any extends clauses that should be added to types as a result of executing a macro, indexed by the name of the augmented type declaration.", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "file:dart_model.schema.json#/$defs/Augmentation" + } + } + }, + "interfaceAugmentations": { + "type": "object", + "description": "Any interfaces that should be added to types as a result of executing a macro, indexed by the name of the augmented type declaration.", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "file:dart_model.schema.json#/$defs/Augmentation" + } + } + }, + "libraryAugmentations": { "type": "array", - "description": "The augmentations.", + "description": "Any augmentations that should be applied to the library as a result of executing a macro.", "items": { "$ref": "file:dart_model.schema.json#/$defs/Augmentation" } + }, + "mixinAugmentations": { + "type": "object", + "description": "Any mixins that should be added to types as a result of executing a macro, indexed by the name of the augmented type declaration.", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "file:dart_model.schema.json#/$defs/Augmentation" + } + } + }, + "newTypeNames": { + "type": "array", + "description": "The names of any new types declared in [libraryAugmentations].", + "items": { + "type": "string" + } + }, + "typeAugmentations": { + "type": "object", + "description": "Any augmentations that should be applied to a class as a result of executing a macro, indexed by the name of the class.", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "file:dart_model.schema.json#/$defs/Augmentation" + } + } } } },