What version of Swift are you using (swift --version)?
swift-driver version: 1.113 Apple Swift version 6.0 (swiftlang-6.0.0.7.6 clang-1600.0.24.1)
Target: arm64-apple-macosx14.0
What did you do?
I'm using Sourcery 2.2.5 and the default Automockable.stencil template. The default template for Automockable, parses and generates not compiler safe code.
Given the following code:
// sourcery: AutoMockable
protocol AnyClosureProtocol {
func evaluateJavaScript(_ javaScriptString: String, completionHandler: (@MainActor @Sendable (Any?, (any Error)?) -> Void)?)
}
What did you expect to see?
I expect the default Automockable.stencil to generate compiler safe code. I expected that it generates the following code:
//MARK: - evaluateJavaScript
var evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidCallsCount = 0
var evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidCalled: Bool {
return evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidCallsCount > 0
}
var evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidClosure: ((String, (@MainActor @Sendable (Any?, (any Error)?) -> Void)?) -> Void)?
func evaluateJavaScript(_ javaScriptString: String, completionHandler: (@MainActor @Sendable (Any?, (any Error)?) -> Void)?) {
evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidCallsCount += 1
evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidClosure?(javaScriptString, completionHandler)
}
What did you see instead?
When building and trying to generate mocked code, the compiler will fail and tell that the newly generated code has wrong syntax.
This is the generated code it came up with:
//MARK: - evaluateJavaScript
var evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidCallsCount = 0
var evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidCalled: Bool {
return evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidCallsCount > 0
}
var evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidClosure: ((String, ((@MainActor @Sendable (Any)?, (any Error)?) -> Void))?) -> Void)?
func evaluateJavaScript(_ javaScriptString: String, completionHandler: (((@MainActor @Sendable (Any)?, (any Error)?) -> Void))?) {
evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidCallsCount += 1
evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidClosure?(javaScriptString, completionHandler)
}
This does not work because of the followintg compiler errors:


What is the actual problem?
The problem is, that it replaces every ? with )? which should not be the case for the Any? parameter.
This happens only, and only if:
- The parameter is a
closure
- Is
optional
contains:"any "
The replace function is too naive and adds too many parentheses.
Here are the lines, which are in my opinion, the places where the replace is to generous:
|
({{ typeName.unwrappedTypeName| replace:"inout ","" | replace:"any","(any" | replace:"?",")?" }})? |
|
({{ typeName.unwrappedTypeName | replace:"any","(any" | replace:"?",")?" }})? |
What version of Swift are you using (swift --version)?
What did you do?
I'm using Sourcery
2.2.5and the defaultAutomockable.stenciltemplate. The default template forAutomockable, parses and generates not compiler safe code.Given the following code:
What did you expect to see?
I expect the default
Automockable.stencilto generate compiler safe code. I expected that it generates the following code://MARK: - evaluateJavaScript var evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidCallsCount = 0 var evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidCalled: Bool { return evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidCallsCount > 0 } var evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidClosure: ((String, (@MainActor @Sendable (Any?, (any Error)?) -> Void)?) -> Void)? func evaluateJavaScript(_ javaScriptString: String, completionHandler: (@MainActor @Sendable (Any?, (any Error)?) -> Void)?) { evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidCallsCount += 1 evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidClosure?(javaScriptString, completionHandler) }What did you see instead?
When building and trying to generate mocked code, the compiler will fail and tell that the newly generated code has wrong syntax.
This is the generated code it came up with:
//MARK: - evaluateJavaScript var evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidCallsCount = 0 var evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidCalled: Bool { return evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidCallsCount > 0 } var evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidClosure: ((String, ((@MainActor @Sendable (Any)?, (any Error)?) -> Void))?) -> Void)? func evaluateJavaScript(_ javaScriptString: String, completionHandler: (((@MainActor @Sendable (Any)?, (any Error)?) -> Void))?) { evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidCallsCount += 1 evaluateJavaScriptJavaScriptStringStringCompletionHandlerMainActorSendableAnyAnyErrorVoidVoidClosure?(javaScriptString, completionHandler) }This does not work because of the followintg compiler errors:


What is the actual problem?
The problem is, that it replaces every
?with)?which should not be the case for theAny?parameter.This happens only, and only if:
closureoptionalcontains:"any "The replace function is too naive and adds too many parentheses.
Here are the lines, which are in my opinion, the places where the replace is to generous:
Sourcery/Templates/Templates/AutoMockable.stencil
Line 254 in 3da93a7
Sourcery/Templates/Templates/AutoMockable.stencil
Line 310 in 3da93a7