diff --git a/.swift-format b/.swift-format index 41a022f2627..176687e2845 100644 --- a/.swift-format +++ b/.swift-format @@ -13,6 +13,8 @@ "NoBlockComments": false, "OrderedImports": true, "UseLetInEveryBoundCaseVariable": false, - "UseSynthesizedInitializer": false + "UseSynthesizedInitializer": false, + "ReturnVoidInsteadOfEmptyTuple": true, + "NoVoidReturnOnFunctionSignature": true, } } diff --git a/Examples/Sources/MacroExamples/Implementation/Peer/AddAsyncMacro.swift b/Examples/Sources/MacroExamples/Implementation/Peer/AddAsyncMacro.swift index 923f002c6c4..1ebe01a8a07 100644 --- a/Examples/Sources/MacroExamples/Implementation/Peer/AddAsyncMacro.swift +++ b/Examples/Sources/MacroExamples/Implementation/Peer/AddAsyncMacro.swift @@ -42,7 +42,9 @@ public struct AddAsyncMacro: PeerMacro { } // This only makes sense void functions - if funcDecl.signature.returnClause?.type.as(IdentifierTypeSyntax.self)?.name.text != "Void" { + if let returnClause = funcDecl.signature.returnClause, + returnClause.type.as(IdentifierTypeSyntax.self)?.name.text != "Void" + { throw CustomError.message( "@addAsync requires an function that returns void" ) diff --git a/Examples/Sources/MacroExamples/Playground/PeerMacrosPlayground.swift b/Examples/Sources/MacroExamples/Playground/PeerMacrosPlayground.swift index bc5ba242ca1..f4bfaf335fc 100644 --- a/Examples/Sources/MacroExamples/Playground/PeerMacrosPlayground.swift +++ b/Examples/Sources/MacroExamples/Playground/PeerMacrosPlayground.swift @@ -17,12 +17,12 @@ func runPeerMacrosPlayground() { struct MyStruct { @AddAsync - func c(a: Int, for b: String, _ value: Double, completionBlock: @escaping (Result) -> Void) -> Void { + func c(a: Int, for b: String, _ value: Double, completionBlock: @escaping (Result) -> Void) { completionBlock(.success("a: \(a), b: \(b), value: \(value)")) } @AddAsync - func d(a: Int, for b: String, _ value: Double, completionBlock: @escaping (Bool) -> Void) -> Void { + func d(a: Int, for b: String, _ value: Double, completionBlock: @escaping (Bool) -> Void) { completionBlock(true) } } diff --git a/Examples/Tests/MacroExamples/Implementation/Peer/AddAsyncMacroTests.swift b/Examples/Tests/MacroExamples/Implementation/Peer/AddAsyncMacroTests.swift index 79178633770..f936f425dd0 100644 --- a/Examples/Tests/MacroExamples/Implementation/Peer/AddAsyncMacroTests.swift +++ b/Examples/Tests/MacroExamples/Implementation/Peer/AddAsyncMacroTests.swift @@ -79,6 +79,32 @@ final class AddAsyncMacroTests: XCTestCase { ) } + func testImplicitVoidResult() { + assertMacroExpansion( + """ + @AddAsync + func d(a: Int, completionBlock: @escaping (Bool) -> Void) { + } + """, + expandedSource: """ + func d(a: Int, completionBlock: @escaping (Bool) -> Void) { + } + + func d(a: Int) async -> Bool { + await withCheckedContinuation { continuation in + d(a: a) { returnValue in + + continuation.resume(returning: returnValue) + } + } + + } + """, + macros: macros, + indentationWidth: .spaces(2) + ) + } + func testExpansionOnStoredPropertyEmitsError() { assertMacroExpansion( """ @@ -105,18 +131,18 @@ final class AddAsyncMacroTests: XCTestCase { ) } - func testExpansionOnAsyncFunctionEmitsError() { + func testNonVoidResult() { assertMacroExpansion( """ struct Test { @AddAsync - async func sayHello() { + func sayHello() -> Int { } } """, expandedSource: """ struct Test { - async func sayHello() { + func sayHello() -> Int { } } """, @@ -132,4 +158,50 @@ final class AddAsyncMacroTests: XCTestCase { indentationWidth: .spaces(2) ) } + + func testAlreadyAsync() { + assertMacroExpansion( + """ + @AddAsync + func d(a: Int, completionBlock: @escaping (Bool) -> Void) async { + } + """, + expandedSource: """ + func d(a: Int, completionBlock: @escaping (Bool) -> Void) async { + } + """, + diagnostics: [ + DiagnosticSpec( + message: "@addAsync requires an non async function", + line: 1, + column: 1, + severity: .error + ) + ], + macros: macros, + indentationWidth: .spaces(2) + ) + } + + func testNoCompletionHandler() { + assertMacroExpansion( + """ + @AddAsync + func sayHello(x: Int) {} + """, + expandedSource: """ + func sayHello(x: Int) {} + """, + diagnostics: [ + DiagnosticSpec( + message: "@addAsync requires an function that has a completion handler as last parameter", + line: 1, + column: 1, + severity: .error + ) + ], + macros: macros, + indentationWidth: .spaces(2) + ) + } } diff --git a/Sources/SwiftParser/IncrementalParseTransition.swift b/Sources/SwiftParser/IncrementalParseTransition.swift index c2ebb127817..730f5112da0 100644 --- a/Sources/SwiftParser/IncrementalParseTransition.swift +++ b/Sources/SwiftParser/IncrementalParseTransition.swift @@ -47,7 +47,7 @@ extension Parser { /// /// This is also used for testing purposes to ensure incremental reparsing /// worked as expected. -public typealias ReusedNodeCallback = (_ node: Syntax) -> () +public typealias ReusedNodeCallback = (_ node: Syntax) -> Void /// Keeps track of a previously parsed syntax tree and the source edits that /// occurred since it was created. diff --git a/Sources/SwiftSyntax/SourceLocation.swift b/Sources/SwiftSyntax/SourceLocation.swift index dcca9d2a74f..4cd64d612b9 100644 --- a/Sources/SwiftSyntax/SourceLocation.swift +++ b/Sources/SwiftSyntax/SourceLocation.swift @@ -701,7 +701,7 @@ fileprivate extension SyntaxText { /// - Returns: The position at the end of the walk. func forEachEndOfLine( position: AbsolutePosition, - body: (AbsolutePosition) -> () + body: (AbsolutePosition) -> Void ) -> AbsolutePosition { guard let startPtr = buffer.baseAddress else { return position @@ -745,7 +745,7 @@ fileprivate extension RawTriviaPiece { /// - Returns: The position at the end of the walk. func forEachEndOfLine( position: AbsolutePosition, - body: (AbsolutePosition) -> () + body: (AbsolutePosition) -> Void ) -> AbsolutePosition { var position = position switch self { @@ -788,7 +788,7 @@ fileprivate extension RawTriviaPieceBuffer { /// - Returns: The position at the end of the walk. func forEachEndOfLine( position: AbsolutePosition, - body: (AbsolutePosition) -> () + body: (AbsolutePosition) -> Void ) -> AbsolutePosition { var position = position for piece in self { @@ -810,8 +810,8 @@ fileprivate extension RawSyntax { /// - Returns: The position at the end of the walk. func forEachEndOfLine( position: AbsolutePosition, - body: (AbsolutePosition) -> (), - handleSourceLocationDirective: (_ position: AbsolutePosition, _ rawSyntax: RawSyntax) -> () + body: (AbsolutePosition) -> Void, + handleSourceLocationDirective: (_ position: AbsolutePosition, _ rawSyntax: RawSyntax) -> Void ) -> AbsolutePosition { var position = position switch self.rawData.payload {