From e0a3d4cccb824b477d13b79eb52f257cd8e64c82 Mon Sep 17 00:00:00 2001 From: Liam Appelbe Date: Tue, 3 Dec 2024 14:40:00 +1100 Subject: [PATCH 1/2] async annotation --- .../src/ast/_core/interfaces/can_async.dart | 9 ++ .../interfaces/function_declaration.dart | 4 +- .../interfaces/variable_declaration.dart | 10 +- .../members/initializer_declaration.dart | 8 +- .../compounds/members/method_declaration.dart | 4 + .../members/property_declaration.dart | 4 + .../src/ast/declarations/globals/globals.dart | 8 ++ .../lib/src/generator/_core/utils.dart | 14 +++ .../generator/generators/class_generator.dart | 12 +-- .../parse_function_declaration.dart | 17 +++- .../parse_initializer_declaration.dart | 10 ++ .../parse_variable_declaration.dart | 14 +++ .../transformers/transform_compound.dart | 1 + .../transformers/transform_function.dart | 4 + .../transformers/transform_initializer.dart | 4 + .../transformers/transform_variable.dart | 1 + .../test/integration/async_input.swift | 12 +++ .../test/integration/async_output.swift | 39 ++++++++ .../test/unit/parse_function_info_test.dart | 94 +++++++++++++++++++ 19 files changed, 250 insertions(+), 19 deletions(-) create mode 100644 pkgs/swift2objc/lib/src/ast/_core/interfaces/can_async.dart create mode 100644 pkgs/swift2objc/test/integration/async_input.swift create mode 100644 pkgs/swift2objc/test/integration/async_output.swift diff --git a/pkgs/swift2objc/lib/src/ast/_core/interfaces/can_async.dart b/pkgs/swift2objc/lib/src/ast/_core/interfaces/can_async.dart new file mode 100644 index 000000000..1479d7a96 --- /dev/null +++ b/pkgs/swift2objc/lib/src/ast/_core/interfaces/can_async.dart @@ -0,0 +1,9 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// An interface to describe a Swift entity's ability to be annotated +/// with `async`. +abstract interface class CanAsync { + abstract final bool async; +} diff --git a/pkgs/swift2objc/lib/src/ast/_core/interfaces/function_declaration.dart b/pkgs/swift2objc/lib/src/ast/_core/interfaces/function_declaration.dart index ca90dc5c7..5ee39604b 100644 --- a/pkgs/swift2objc/lib/src/ast/_core/interfaces/function_declaration.dart +++ b/pkgs/swift2objc/lib/src/ast/_core/interfaces/function_declaration.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import '../shared/referred_type.dart'; +import 'can_async.dart'; import 'can_throw.dart'; import 'declaration.dart'; import 'executable.dart'; @@ -16,6 +17,7 @@ abstract interface class FunctionDeclaration Parameterizable, Executable, TypeParameterizable, - CanThrow { + CanThrow, + CanAsync { abstract final ReferredType returnType; } diff --git a/pkgs/swift2objc/lib/src/ast/_core/interfaces/variable_declaration.dart b/pkgs/swift2objc/lib/src/ast/_core/interfaces/variable_declaration.dart index c2c694e35..cf15229cf 100644 --- a/pkgs/swift2objc/lib/src/ast/_core/interfaces/variable_declaration.dart +++ b/pkgs/swift2objc/lib/src/ast/_core/interfaces/variable_declaration.dart @@ -3,15 +3,17 @@ // BSD-style license that can be found in the LICENSE file. import '../shared/referred_type.dart'; +import 'can_async.dart'; import 'can_throw.dart'; import 'declaration.dart'; /// Describes a variable-like entity. /// -/// This declaration [CanThrow] because Swift variables can have explicit -/// getters, which can be marked with `throws`. Such variables may not have a -/// setter. -abstract interface class VariableDeclaration implements Declaration, CanThrow { +/// This declaration implements [CanThrow] and [CanAsync] because Swift +/// variables can have explicit getters, which can be marked with `throws` and +/// `async`. Such variables may not have a setter. +abstract interface class VariableDeclaration + implements Declaration, CanThrow, CanAsync { abstract final bool isConstant; abstract final ReferredType type; } diff --git a/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/initializer_declaration.dart b/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/initializer_declaration.dart index 1fdf10d96..d7c5431b3 100644 --- a/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/initializer_declaration.dart +++ b/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/initializer_declaration.dart @@ -2,6 +2,7 @@ // 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 '../../../_core/interfaces/can_async.dart'; import '../../../_core/interfaces/can_throw.dart'; import '../../../_core/interfaces/declaration.dart'; import '../../../_core/interfaces/executable.dart'; @@ -18,7 +19,8 @@ class InitializerDeclaration Parameterizable, ObjCAnnotatable, Overridable, - CanThrow { + CanThrow, + CanAsync { @override String id; @@ -34,6 +36,9 @@ class InitializerDeclaration @override bool throws; + @override + bool async; + bool isFailable; @override @@ -54,6 +59,7 @@ class InitializerDeclaration required this.hasObjCAnnotation, required this.isOverriding, required this.throws, + required this.async, required this.isFailable, }); } diff --git a/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/method_declaration.dart b/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/method_declaration.dart index 72315a962..c7567fe9c 100644 --- a/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/method_declaration.dart +++ b/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/method_declaration.dart @@ -33,6 +33,9 @@ class MethodDeclaration @override bool throws; + @override + bool async; + @override List statements; @@ -57,5 +60,6 @@ class MethodDeclaration this.isStatic = false, this.isOverriding = false, this.throws = false, + this.async = false, }) : assert(!isStatic || !isOverriding); } diff --git a/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/property_declaration.dart b/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/property_declaration.dart index adf151e51..6bcced2d9 100644 --- a/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/property_declaration.dart +++ b/pkgs/swift2objc/lib/src/ast/declarations/compounds/members/property_declaration.dart @@ -28,6 +28,9 @@ class PropertyDeclaration implements VariableDeclaration, ObjCAnnotatable { @override bool throws; + @override + bool async; + bool hasSetter; PropertyStatements? getter; @@ -46,6 +49,7 @@ class PropertyDeclaration implements VariableDeclaration, ObjCAnnotatable { this.setter, this.isStatic = false, this.throws = false, + this.async = false, }) : assert(!(isConstant && hasSetter)), assert(!(hasSetter && throws)); } diff --git a/pkgs/swift2objc/lib/src/ast/declarations/globals/globals.dart b/pkgs/swift2objc/lib/src/ast/declarations/globals/globals.dart index 1dd6c248b..c06cc5077 100644 --- a/pkgs/swift2objc/lib/src/ast/declarations/globals/globals.dart +++ b/pkgs/swift2objc/lib/src/ast/declarations/globals/globals.dart @@ -36,6 +36,9 @@ class GlobalFunctionDeclaration implements FunctionDeclaration { @override bool throws; + @override + bool async; + @override ReferredType returnType; @@ -50,6 +53,7 @@ class GlobalFunctionDeclaration implements FunctionDeclaration { this.typeParams = const [], this.statements = const [], this.throws = false, + this.async = false, }); } @@ -70,11 +74,15 @@ class GlobalVariableDeclaration implements VariableDeclaration { @override bool throws; + @override + bool async; + GlobalVariableDeclaration({ required this.id, required this.name, required this.type, required this.isConstant, required this.throws, + required this.async, }) : assert(!(throws && !isConstant)); } diff --git a/pkgs/swift2objc/lib/src/generator/_core/utils.dart b/pkgs/swift2objc/lib/src/generator/_core/utils.dart index 9ab8a6fba..2294390c5 100644 --- a/pkgs/swift2objc/lib/src/generator/_core/utils.dart +++ b/pkgs/swift2objc/lib/src/generator/_core/utils.dart @@ -1,5 +1,8 @@ import 'dart:io'; import 'package:path/path.dart' as path; +import '../../ast/_core/interfaces/can_async.dart'; +import '../../ast/_core/interfaces/can_throw.dart'; +import '../../ast/_core/interfaces/declaration.dart'; import '../../ast/_core/shared/parameter.dart'; String generateParameters(List params) { @@ -34,3 +37,14 @@ void outputNextToFile({ File(outputPath).writeAsStringSync(content); } + +String generateAnnotations(Declaration decl) { + final annotations = StringBuffer(); + if (decl is CanAsync && (decl as CanAsync).async) { + annotations.write(' async'); + } + if (decl is CanThrow && (decl as CanThrow).throws) { + annotations.write(' throws'); + } + return annotations.toString(); +} diff --git a/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart b/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart index c54837fd7..911c4d90a 100644 --- a/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart +++ b/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart @@ -87,12 +87,8 @@ List _generateInitializer(InitializerDeclaration initializer) { header.write('(${generateParameters(initializer.params)})'); - if (initializer.throws) { - header.write(' throws'); - } - return [ - '$header {', + '$header ${generateAnnotations(initializer)}{', ...initializer.statements.indent(), '}\n', ]; @@ -120,9 +116,7 @@ List _generateClassMethod(MethodDeclaration method) { 'public func ${method.name}(${generateParameters(method.params)})', ); - if (method.throws) { - header.write(' throws'); - } + header.write(generateAnnotations(method)); if (!method.returnType.sameAs(voidType)) { header.write(' -> ${method.returnType.swiftType}'); @@ -154,7 +148,7 @@ List _generateClassProperty(PropertyDeclaration property) { header.write('public var ${property.name}: ${property.type.swiftType} {'); final getterLines = [ - 'get {', + 'get ${generateAnnotations(property)}{', ...(property.getter?.statements.indent() ?? []), '}' ]; diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_function_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_function_declaration.dart index 6f0acf973..769677d87 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_function_declaration.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_function_declaration.dart @@ -24,6 +24,7 @@ GlobalFunctionDeclaration parseGlobalFunctionDeclaration( returnType: _parseFunctionReturnType(globalFunctionSymbolJson, symbolgraph), params: info.params, throws: info.throws, + async: info.async, ); } @@ -33,7 +34,7 @@ MethodDeclaration parseMethodDeclaration( bool isStatic = false, }) { final info = - parseFunctionInfo(methodSymbolJson['declarationFragments'], symbolgraph); + parseFunctionInfo(methodSymbolJson['declarationFragments'], symbolgraph, parseSymbolName(methodSymbolJson)); return MethodDeclaration( id: parseSymbolId(methodSymbolJson), name: parseSymbolName(methodSymbolJson), @@ -42,17 +43,20 @@ MethodDeclaration parseMethodDeclaration( hasObjCAnnotation: parseSymbolHasObjcAnnotation(methodSymbolJson), isStatic: isStatic, throws: info.throws, + async: info.async, ); } typedef ParsedFunctionInfo = ({ List params, bool throws, + bool async, }); ParsedFunctionInfo parseFunctionInfo( Json declarationFragments, ParsedSymbolgraph symbolgraph, + [String? name] ) { // `declarationFragments` describes each part of the function declaration, // things like the `func` keyword, brackets, spaces, etc. We only care about @@ -120,17 +124,22 @@ ParsedFunctionInfo parseFunctionInfo( } } - // Parse annotations until we run out. + // Parse annotations until we run out. The annotations are keywords separated + // by whitespace tokens. final annotations = {}; while (true) { final keyword = maybeConsume('keyword'); - if (keyword == null) break; - annotations.add(keyword); + if (keyword == null) { + if (maybeConsume('text') != '') break; + } else { + annotations.add(keyword); + } } return ( params: parameters, throws: annotations.contains('throws'), + async: annotations.contains('async'), ); } diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_initializer_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_initializer_declaration.dart index b9ce98411..d4f0dc3a1 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_initializer_declaration.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_initializer_declaration.dart @@ -20,6 +20,15 @@ InitializerDeclaration parseInitializerDeclaration( } final info = parseFunctionInfo(declarationFragments, symbolgraph); + + if (info.async) { + // TODO(https://github.com/dart-lang/native/issues/1778): Support async + // initializerse. + throw Exception( + "Async initializers aren't supported yet, at " + '${initializerSymbolJson.path}'); + } + return InitializerDeclaration( id: id, params: info.params, @@ -27,6 +36,7 @@ InitializerDeclaration parseInitializerDeclaration( isOverriding: parseIsOverriding(initializerSymbolJson), isFailable: parseIsFailableInit(id, declarationFragments), throws: info.throws, + async: info.async, ); } diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_variable_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_variable_declaration.dart index b1aa8c78d..960e248b3 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_variable_declaration.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_variable_declaration.dart @@ -25,6 +25,7 @@ PropertyDeclaration parsePropertyDeclaration( hasSetter: isConstant ? false : _parsePropertyHasSetter(propertySymbolJson), isStatic: isStatic, throws: _parseVariableThrows(propertySymbolJson), + async: _parseVariableAsync(propertySymbolJson), ); } @@ -41,6 +42,7 @@ GlobalVariableDeclaration parseGlobalVariableDeclaration( type: _parseVariableType(variableSymbolJson, symbolgraph), isConstant: isConstant || !hasSetter, throws: _parseVariableThrows(variableSymbolJson), + async: _parseVariableAsync(variableSymbolJson), ); } @@ -78,6 +80,18 @@ bool _parseVariableThrows(Json json) { return throws; } +bool _parseVariableAsync(Json json) { + final async = json['declarationFragments'] + .any((frag) => matchFragment(frag, 'keyword', 'async')); + if (async) { + // TODO(https://github.com/dart-lang/native/issues/1778): Support async + // getters. + throw Exception("Async getters aren't supported yet, at ${json.path}"); + } + return async; +} + + bool _parsePropertyHasSetter(Json propertySymbolJson) { final fragmentsJson = propertySymbolJson['declarationFragments']; diff --git a/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart b/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart index d01bd06f8..cd06487a0 100644 --- a/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart +++ b/pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart @@ -101,6 +101,7 @@ InitializerDeclaration _buildWrapperInitializer( isOverriding: false, isFailable: false, throws: false, + async: false, statements: ['self.${wrappedClassInstance.name} = wrappedInstance'], hasObjCAnnotation: wrappedClassInstance.hasObjCAnnotation, ); diff --git a/pkgs/swift2objc/lib/src/transformer/transformers/transform_function.dart b/pkgs/swift2objc/lib/src/transformer/transformers/transform_function.dart index a1ce97dc0..c5e375282 100644 --- a/pkgs/swift2objc/lib/src/transformer/transformers/transform_function.dart +++ b/pkgs/swift2objc/lib/src/transformer/transformers/transform_function.dart @@ -100,6 +100,7 @@ MethodDeclaration _transformFunction( ? originalFunction.isStatic : true, throws: originalFunction.throws, + async: originalFunction.async, ); transformedMethod.statements = _generateStatements( @@ -150,6 +151,9 @@ List _generateStatements( final arguments = generateInvocationParams( localNamer, originalFunction.params, transformedMethod.params); var originalMethodCall = originalCallGenerator(arguments); + if (transformedMethod.async) { + originalMethodCall = 'await $originalMethodCall'; + } if (transformedMethod.throws) { originalMethodCall = 'try $originalMethodCall'; } diff --git a/pkgs/swift2objc/lib/src/transformer/transformers/transform_initializer.dart b/pkgs/swift2objc/lib/src/transformer/transformers/transform_initializer.dart index a7af3c365..293ec96fa 100644 --- a/pkgs/swift2objc/lib/src/transformer/transformers/transform_initializer.dart +++ b/pkgs/swift2objc/lib/src/transformer/transformers/transform_initializer.dart @@ -36,6 +36,7 @@ InitializerDeclaration transformInitializer( hasObjCAnnotation: true, isFailable: originalInitializer.isFailable, throws: originalInitializer.throws, + async: originalInitializer.async, // Because the wrapper class extends NSObject that has an initializer with // no parameters. If we make a similar parameterless initializer we need // to add `override` keyword. @@ -60,6 +61,9 @@ List _generateInitializerStatements( localNamer, originalInitializer.params, transformedInitializer.params); var instanceConstruction = '${wrappedClassInstance.type.swiftType}($arguments)'; + if (transformedInitializer.async) { + instanceConstruction = 'await $instanceConstruction'; + } if (transformedInitializer.throws) { instanceConstruction = 'try $instanceConstruction'; } diff --git a/pkgs/swift2objc/lib/src/transformer/transformers/transform_variable.dart b/pkgs/swift2objc/lib/src/transformer/transformers/transform_variable.dart index 9c061542e..c18e02a50 100644 --- a/pkgs/swift2objc/lib/src/transformer/transformers/transform_variable.dart +++ b/pkgs/swift2objc/lib/src/transformer/transformers/transform_variable.dart @@ -82,6 +82,7 @@ PropertyDeclaration _transformVariable( : true, isConstant: originalVariable.isConstant, throws: originalVariable.throws, + async: originalVariable.async, ); final getterStatements = _generateGetterStatements( diff --git a/pkgs/swift2objc/test/integration/async_input.swift b/pkgs/swift2objc/test/integration/async_input.swift new file mode 100644 index 000000000..44ebd6ef9 --- /dev/null +++ b/pkgs/swift2objc/test/integration/async_input.swift @@ -0,0 +1,12 @@ +import Foundation + +public class MyClass { + public func voidMethod() async {} + public func intMethod(y: Int) async -> MyClass { return MyClass() } + public func asyncThrowsMethod(y: Int) async throws -> MyClass { + return MyClass() + } +} + +public func voidFunc(x: Int, y: Int) async {} +public func intFunc() async -> MyClass { return MyClass() } diff --git a/pkgs/swift2objc/test/integration/async_output.swift b/pkgs/swift2objc/test/integration/async_output.swift new file mode 100644 index 000000000..d10445bb7 --- /dev/null +++ b/pkgs/swift2objc/test/integration/async_output.swift @@ -0,0 +1,39 @@ +// Test preamble text + +import Foundation + +@objc public class GlobalsWrapper: NSObject { + @objc static public func intFuncWrapper() async -> MyClassWrapper { + let result = await intFunc() + return MyClassWrapper(result) + } + + @objc static public func voidFuncWrapper(x: Int, y: Int) async { + return await voidFunc(x: x, y: y) + } + +} + +@objc public class MyClassWrapper: NSObject { + var wrappedInstance: MyClass + + init(_ wrappedInstance: MyClass) { + self.wrappedInstance = wrappedInstance + } + + @objc public func voidMethod() async { + return await wrappedInstance.voidMethod() + } + + @objc public func asyncThrowsMethod(y: Int) async throws -> MyClassWrapper { + let result = try await wrappedInstance.asyncThrowsMethod(y: y) + return MyClassWrapper(result) + } + + @objc public func intMethod(y: Int) async -> MyClassWrapper { + let result = await wrappedInstance.intMethod(y: y) + return MyClassWrapper(result) + } + +} + diff --git a/pkgs/swift2objc/test/unit/parse_function_info_test.dart b/pkgs/swift2objc/test/unit/parse_function_info_test.dart index 909b07cd0..3d86a1b7b 100644 --- a/pkgs/swift2objc/test/unit/parse_function_info_test.dart +++ b/pkgs/swift2objc/test/unit/parse_function_info_test.dart @@ -79,6 +79,7 @@ void main() { expectEqualParams(info.params, expectedParams); expect(info.throws, isFalse); + expect(info.async, isFalse); }); test('Three params with some optional', () { @@ -140,6 +141,7 @@ void main() { expectEqualParams(info.params, expectedParams); expect(info.throws, isFalse); + expect(info.async, isFalse); }); test('One param', () { @@ -171,6 +173,7 @@ void main() { expectEqualParams(info.params, expectedParams); expect(info.throws, isFalse); + expect(info.async, isFalse); }); test('No params', () { @@ -187,6 +190,7 @@ void main() { expectEqualParams(info.params, []); expect(info.throws, isFalse); + expect(info.async, isFalse); }); test('Function with return type', () { @@ -227,6 +231,7 @@ void main() { expectEqualParams(info.params, expectedParams); expect(info.throws, isFalse); + expect(info.async, isFalse); }); test('Function with no params with return type', () { @@ -250,6 +255,7 @@ void main() { expectEqualParams(info.params, []); expect(info.throws, isFalse); + expect(info.async, isFalse); }); test('Function with no params and no return type', () { @@ -268,6 +274,7 @@ void main() { expectEqualParams(info.params, []); expect(info.throws, isFalse); + expect(info.async, isFalse); }); test('Function with return type that throws', () { @@ -308,6 +315,7 @@ void main() { expectEqualParams(info.params, expectedParams); expect(info.throws, isTrue); + expect(info.async, isFalse); }); test('Function with no return type that throws', () { @@ -342,6 +350,7 @@ void main() { expectEqualParams(info.params, expectedParams); expect(info.throws, isTrue); + expect(info.async, isFalse); }); test('Function with no params that throws', () { @@ -361,6 +370,91 @@ void main() { expectEqualParams(info.params, []); expect(info.throws, isTrue); + expect(info.async, isFalse); + }); + + test('Function with async annotation', () { + final json = Json(jsonDecode( + ''' + [ + { "kind": "keyword", "spelling": "func" }, + { "kind": "text", "spelling": " " }, + { "kind": "identifier", "spelling": "foo" }, + { "kind": "text", "spelling": "(" }, + { "kind": "externalParam", "spelling": "parameter" }, + { "kind": "text", "spelling": ": " }, + { + "kind": "typeIdentifier", + "spelling": "Int", + "preciseIdentifier": "s:Si" + }, + { "kind": "text", "spelling": ") " }, + { "kind": "keyword", "spelling": "async" }, + { "kind": "text", "spelling": " -> " }, + { + "kind": "typeIdentifier", + "spelling": "Int", + "preciseIdentifier": "s:Si" + } + ] + ''', + )); + + final info = parseFunctionInfo(json, emptySymbolgraph); + + final expectedParams = [ + Parameter( + name: 'parameter', + type: intType, + ), + ]; + + expectEqualParams(info.params, expectedParams); + expect(info.throws, isFalse); + expect(info.async, isTrue); + }); + + test('Function with async and throws annotations', () { + final json = Json(jsonDecode( + ''' + [ + { "kind": "keyword", "spelling": "func" }, + { "kind": "text", "spelling": " " }, + { "kind": "identifier", "spelling": "foo" }, + { "kind": "text", "spelling": "(" }, + { "kind": "externalParam", "spelling": "parameter" }, + { "kind": "text", "spelling": ": " }, + { + "kind": "typeIdentifier", + "spelling": "Int", + "preciseIdentifier": "s:Si" + }, + { "kind": "text", "spelling": ") " }, + { "kind": "keyword", "spelling": "async" }, + { "kind": "text", "spelling": " " }, + { "kind": "keyword", "spelling": "throws" }, + { "kind": "text", "spelling": " -> " }, + { + "kind": "typeIdentifier", + "spelling": "Int", + "preciseIdentifier": "s:Si" + } + ] + ''', + )); + + final info = parseFunctionInfo(json, emptySymbolgraph); + + final expectedParams = [ + Parameter( + name: 'parameter', + type: intType, + ), + ]; + + expectEqualParams(info.params, expectedParams); + expect(info.throws, isTrue); + expect(info.async, isTrue); }); }); From dedbf1a9b1dc817ce5c82cd1ea9db70f3d4a991f Mon Sep 17 00:00:00 2001 From: Liam Appelbe Date: Tue, 3 Dec 2024 14:46:52 +1100 Subject: [PATCH 2/2] fmt --- pkgs/swift2objc/lib/src/generator/_core/utils.dart | 4 ++-- .../lib/src/generator/generators/class_generator.dart | 6 +++--- .../declaration_parsers/parse_function_declaration.dart | 3 +-- .../declaration_parsers/parse_initializer_declaration.dart | 3 +-- .../declaration_parsers/parse_variable_declaration.dart | 1 - 5 files changed, 7 insertions(+), 10 deletions(-) diff --git a/pkgs/swift2objc/lib/src/generator/_core/utils.dart b/pkgs/swift2objc/lib/src/generator/_core/utils.dart index 2294390c5..83dc01a3b 100644 --- a/pkgs/swift2objc/lib/src/generator/_core/utils.dart +++ b/pkgs/swift2objc/lib/src/generator/_core/utils.dart @@ -41,10 +41,10 @@ void outputNextToFile({ String generateAnnotations(Declaration decl) { final annotations = StringBuffer(); if (decl is CanAsync && (decl as CanAsync).async) { - annotations.write(' async'); + annotations.write('async '); } if (decl is CanThrow && (decl as CanThrow).throws) { - annotations.write(' throws'); + annotations.write('throws '); } return annotations.toString(); } diff --git a/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart b/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart index 911c4d90a..b5161bfb2 100644 --- a/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart +++ b/pkgs/swift2objc/lib/src/generator/generators/class_generator.dart @@ -113,17 +113,17 @@ List _generateClassMethod(MethodDeclaration method) { } header.write( - 'public func ${method.name}(${generateParameters(method.params)})', + 'public func ${method.name}(${generateParameters(method.params)}) ', ); header.write(generateAnnotations(method)); if (!method.returnType.sameAs(voidType)) { - header.write(' -> ${method.returnType.swiftType}'); + header.write('-> ${method.returnType.swiftType} '); } return [ - '$header {', + '$header{', ...method.statements.indent(), '}\n', ]; diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_function_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_function_declaration.dart index 769677d87..02d705d22 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_function_declaration.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_function_declaration.dart @@ -34,7 +34,7 @@ MethodDeclaration parseMethodDeclaration( bool isStatic = false, }) { final info = - parseFunctionInfo(methodSymbolJson['declarationFragments'], symbolgraph, parseSymbolName(methodSymbolJson)); + parseFunctionInfo(methodSymbolJson['declarationFragments'], symbolgraph); return MethodDeclaration( id: parseSymbolId(methodSymbolJson), name: parseSymbolName(methodSymbolJson), @@ -56,7 +56,6 @@ typedef ParsedFunctionInfo = ({ ParsedFunctionInfo parseFunctionInfo( Json declarationFragments, ParsedSymbolgraph symbolgraph, - [String? name] ) { // `declarationFragments` describes each part of the function declaration, // things like the `func` keyword, brackets, spaces, etc. We only care about diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_initializer_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_initializer_declaration.dart index d4f0dc3a1..74583e447 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_initializer_declaration.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_initializer_declaration.dart @@ -24,8 +24,7 @@ InitializerDeclaration parseInitializerDeclaration( if (info.async) { // TODO(https://github.com/dart-lang/native/issues/1778): Support async // initializerse. - throw Exception( - "Async initializers aren't supported yet, at " + throw Exception("Async initializers aren't supported yet, at " '${initializerSymbolJson.path}'); } diff --git a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_variable_declaration.dart b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_variable_declaration.dart index 960e248b3..1877af6c1 100644 --- a/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_variable_declaration.dart +++ b/pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_variable_declaration.dart @@ -91,7 +91,6 @@ bool _parseVariableAsync(Json json) { return async; } - bool _parsePropertyHasSetter(Json propertySymbolJson) { final fragmentsJson = propertySymbolJson['declarationFragments'];