-
Notifications
You must be signed in to change notification settings - Fork 3.4k
[pigeon] Adds Dart implementation of ProxyApi #6043
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
6e385f1
abc026a
870cec3
0c69e1d
eb14522
155469f
3a45694
6350353
5cfcb3a
4ce1e21
22c3065
a14485e
360dd7a
ea9f7c3
33b2e07
6c79879
c8db9c8
b414381
00db939
54c7ac2
d05bebf
dfb7e45
8015a9a
2dac15d
36bbca1
afa62e8
1cd4d95
b08d017
fc3df6f
0caa963
1c61c51
cb2e654
12d9c7d
8abdb3f
1d2c549
c0aa558
1f0c6ce
7f1f70e
2b04aa5
94106ae
796d336
dcbd085
358b6d7
0138563
ea338c8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
|
||
import 'package:collection/collection.dart' show ListEquality; | ||
import 'package:meta/meta.dart'; | ||
import 'generator_tools.dart'; | ||
import 'pigeon_lib.dart'; | ||
|
||
typedef _ListEquals = bool Function(List<Object?>, List<Object?>); | ||
|
@@ -177,6 +178,46 @@ class AstProxyApi extends Api { | |
(ApiField field) => !field.isAttached, | ||
); | ||
|
||
/// A list of AstProxyApis where each `extends` the API that follows it. | ||
Iterable<AstProxyApi> get allSuperClasses => recursiveGetSuperClassApisChain( | ||
this, | ||
); | ||
|
||
/// All ProxyApis this API `implements` and all the interfaces those APIs | ||
/// `implements`. | ||
Iterable<AstProxyApi> get apisOfInterfaces => | ||
recursiveFindAllInterfaceApis(this); | ||
|
||
/// All methods inherited from interfaces and the interfaces of interfaces. | ||
Iterable<Method> flutterMethodsFromInterfaces() sync* { | ||
for (final AstProxyApi proxyApi in apisOfInterfaces) { | ||
yield* proxyApi.methods; | ||
} | ||
} | ||
|
||
/// A list of Flutter methods inherited from the ProxyApi that this ProxyApi | ||
/// `extends`. | ||
/// | ||
/// This also recursively checks the ProxyApi that the super class `extends` | ||
/// and so on. | ||
/// | ||
/// This also includes methods that super classes inherited from interfaces | ||
/// with `implements`. | ||
Iterable<Method> flutterMethodsFromSuperClasses() sync* { | ||
for (final AstProxyApi proxyApi in allSuperClasses.toList().reversed) { | ||
yield* proxyApi.flutterMethods; | ||
} | ||
if (superClass != null) { | ||
final Set<AstProxyApi> interfaceApisFromSuperClasses = | ||
recursiveFindAllInterfaceApis( | ||
superClass!.associatedProxyApi!, | ||
); | ||
for (final AstProxyApi proxyApi in interfaceApisFromSuperClasses) { | ||
yield* proxyApi.methods; | ||
} | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know if performance really matters here, but ideally these methods would only ever be ran once, and the data stored on the class. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since some of the fields of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't the code that associates the api's make copies? Maybe I'm looking in the wrong place. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unless I'm missing something, a new api is not created: https://github.com/flutter/packages/blob/main/packages/pigeon/lib/pigeon_lib.dart#L1297 and https://github.com/flutter/packages/blob/main/packages/pigeon/lib/pigeon_lib.dart#L1337. Only But even so, as long as the fields are mutable, it could cause a bug in the future if a contributor uses the method. I do think we should probably restructure the AST with immutable classes in the future. Mutable data classes can end up being a foot-gun. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a todo for this and tag me in it? |
||
|
||
@override | ||
String toString() { | ||
return '(ProxyApi name:$name methods:$methods field:$fields ' | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -455,9 +455,9 @@ final BinaryMessenger? ${_varNamePrefix}binaryMessenger; | |
Indent indent, { | ||
required String dartPackageName, | ||
}) { | ||
indent.writeln(proxyApiBaseClass); | ||
indent.format(proxyApiBaseClass); | ||
|
||
indent.writeln( | ||
indent.format( | ||
instanceManagerTemplate( | ||
allProxyApiNames: root.apis | ||
.whereType<AstProxyApi>() | ||
|
@@ -473,7 +473,7 @@ final BinaryMessenger? ${_varNamePrefix}binaryMessenger; | |
Indent indent, { | ||
required String dartPackageName, | ||
}) { | ||
indent.writeln( | ||
indent.format( | ||
instanceManagerApiTemplate( | ||
dartPackageName: dartPackageName, | ||
pigeonChannelCodecVarName: _pigeonChannelCodec, | ||
|
@@ -487,7 +487,7 @@ final BinaryMessenger? ${_varNamePrefix}binaryMessenger; | |
Root root, | ||
Indent indent, | ||
) { | ||
indent.writeln(proxyApiBaseCodec); | ||
indent.format(proxyApiBaseCodec); | ||
} | ||
|
||
@override | ||
|
@@ -500,48 +500,11 @@ final BinaryMessenger? ${_varNamePrefix}binaryMessenger; | |
}) { | ||
const String codecName = '_${classNamePrefix}ProxyApiBaseCodec'; | ||
|
||
// Each api has a private codec instance used by every host method, | ||
// Each API has a private codec instance used by every host method, | ||
// constructor, or non-static field. | ||
final String codecInstanceName = '${_varNamePrefix}codec${api.name}'; | ||
|
||
// A list of ProxyApis where each `extends` the API that follows it. | ||
final List<AstProxyApi> superClassApisChain = | ||
recursiveGetSuperClassApisChain( | ||
api, | ||
); | ||
|
||
// All ProxyApis this API `implements` and all the interfaces those APIs | ||
// `implements`. | ||
final Set<AstProxyApi> apisOfInterfaces = | ||
recursiveFindAllInterfaceApis(api); | ||
|
||
// All methods inherited from interfaces and the interfaces of interfaces. | ||
final List<Method> flutterMethodsFromInterfaces = <Method>[]; | ||
for (final AstProxyApi proxyApi in apisOfInterfaces) { | ||
flutterMethodsFromInterfaces.addAll(proxyApi.methods); | ||
} | ||
|
||
// A list of Flutter methods inherited from the ProxyApi that this ProxyApi | ||
// `extends`. This also recursively checks the ProxyApi that the super class | ||
// `extends` and so on. | ||
// | ||
// This also includes methods that super classes inherited from interfaces | ||
// with `implements`. | ||
final List<Method> flutterMethodsFromSuperClasses = <Method>[]; | ||
for (final AstProxyApi proxyApi in superClassApisChain.reversed) { | ||
flutterMethodsFromSuperClasses.addAll(proxyApi.flutterMethods); | ||
} | ||
if (api.superClass != null) { | ||
final Set<AstProxyApi> interfaceApisFromSuperClasses = | ||
recursiveFindAllInterfaceApis( | ||
api.superClass!.associatedProxyApi!, | ||
); | ||
for (final AstProxyApi proxyApi in interfaceApisFromSuperClasses) { | ||
flutterMethodsFromSuperClasses.addAll(proxyApi.methods); | ||
} | ||
} | ||
|
||
// Ast class used by code_builder to generate the code. | ||
// AST class used by code_builder to generate the code. | ||
final cb.Class proxyApi = cb.Class( | ||
(cb.ClassBuilder builder) => builder | ||
..name = api.name | ||
|
@@ -564,17 +527,18 @@ final BinaryMessenger? ${_varNamePrefix}binaryMessenger; | |
codecInstanceName: codecInstanceName, | ||
superClassApi: api.superClass?.associatedProxyApi, | ||
unattachedFields: api.unattachedFields, | ||
flutterMethodsFromSuperClasses: flutterMethodsFromSuperClasses, | ||
flutterMethodsFromInterfaces: flutterMethodsFromInterfaces, | ||
flutterMethodsFromSuperClasses: api.flutterMethodsFromSuperClasses(), | ||
flutterMethodsFromInterfaces: api.flutterMethodsFromInterfaces(), | ||
declaredFlutterMethods: api.flutterMethods, | ||
)) | ||
..constructors.add( | ||
_proxyApiDetachedConstructor( | ||
apiName: api.name, | ||
superClassApi: api.superClass?.associatedProxyApi, | ||
unattachedFields: api.unattachedFields, | ||
flutterMethodsFromSuperClasses: flutterMethodsFromSuperClasses, | ||
flutterMethodsFromInterfaces: flutterMethodsFromInterfaces, | ||
flutterMethodsFromSuperClasses: | ||
api.flutterMethodsFromSuperClasses(), | ||
flutterMethodsFromInterfaces: api.flutterMethodsFromInterfaces(), | ||
declaredFlutterMethods: api.flutterMethods, | ||
), | ||
) | ||
|
@@ -592,7 +556,7 @@ final BinaryMessenger? ${_varNamePrefix}binaryMessenger; | |
api.flutterMethods, | ||
apiName: api.name, | ||
)) | ||
..fields.addAll(_proxyApiInterfaceApiFields(apisOfInterfaces)) | ||
..fields.addAll(_proxyApiInterfaceApiFields(api.apisOfInterfaces)) | ||
..fields.addAll(_proxyApiAttachedFields(api.attachedFields)) | ||
..methods.add( | ||
_proxyApiSetUpMessageHandlerMethod( | ||
|
@@ -602,8 +566,8 @@ final BinaryMessenger? ${_varNamePrefix}binaryMessenger; | |
codecName: codecName, | ||
unattachedFields: api.unattachedFields, | ||
hasCallbackConstructor: api.flutterMethods | ||
.followedBy(flutterMethodsFromSuperClasses) | ||
.followedBy(flutterMethodsFromInterfaces) | ||
.followedBy(api.flutterMethodsFromSuperClasses()) | ||
.followedBy(api.flutterMethodsFromInterfaces()) | ||
.every((Method method) => !method.isRequired), | ||
), | ||
) | ||
|
@@ -623,17 +587,20 @@ final BinaryMessenger? ${_varNamePrefix}binaryMessenger; | |
codecInstanceName: codecInstanceName, | ||
codecName: codecName, | ||
)) | ||
..methods.add(_proxyApiCopyMethod( | ||
apiName: api.name, | ||
unattachedFields: api.unattachedFields, | ||
declaredAndInheritedFlutterMethods: flutterMethodsFromSuperClasses | ||
.followedBy(flutterMethodsFromInterfaces) | ||
.followedBy(api.flutterMethods), | ||
)), | ||
..methods.add( | ||
_proxyApiCopyMethod( | ||
apiName: api.name, | ||
unattachedFields: api.unattachedFields, | ||
declaredAndInheritedFlutterMethods: api | ||
.flutterMethodsFromSuperClasses() | ||
.followedBy(api.flutterMethodsFromInterfaces()) | ||
.followedBy(api.flutterMethods), | ||
), | ||
), | ||
); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems pretty nice. Definitely something to consider for the other Dart generation. |
||
|
||
final cb.DartEmitter emitter = cb.DartEmitter(useNullSafetySyntax: true); | ||
indent.write(DartFormatter().format('${proxyApi.accept(emitter)}')); | ||
indent.format(DartFormatter().format('${proxyApi.accept(emitter)}')); | ||
} | ||
|
||
/// Generates Dart source code for test support libraries based on the given AST | ||
|
@@ -1140,8 +1107,8 @@ if (${_varNamePrefix}replyList == null) { | |
/// The detached constructor present for every ProxyApi. | ||
/// | ||
/// This constructor doesn't include a host method call to create a new native | ||
/// class instance. It is mainly used when the native side once to create a | ||
/// Dart instance and when the `InstanceManager` wants to create a copy for | ||
/// class instance. It is mainly used when the native side wants to create a | ||
/// Dart instance or when the `InstanceManager` wants to create a copy for | ||
/// automatic garbage collection. | ||
cb.Constructor _proxyApiDetachedConstructor({ | ||
required String apiName, | ||
|
@@ -1260,17 +1227,13 @@ if (${_varNamePrefix}replyList == null) { | |
<String>[ | ||
...method.documentationComments, | ||
...<String>[ | ||
if (method.documentationComments.isNotEmpty) | ||
'' | ||
else ...<String>[ | ||
'Callback method.', | ||
'', | ||
], | ||
if (method.documentationComments.isEmpty) 'Callback method.', | ||
'', | ||
'For the associated Native object to be automatically garbage collected,', | ||
"it is required that the implementation of this `Function` doesn't have a", | ||
'strong reference to the encapsulating class instance. When this `Function`', | ||
'references a non-local variable, it is strongly recommended to access it', | ||
'from a `WeakReference`:', | ||
'with a `WeakReference`:', | ||
'', | ||
'```dart', | ||
'final WeakReference weakMyVariable = WeakReference(myVariable);', | ||
|
Uh oh!
There was an error while loading. Please reload this page.