Skip to content

Commit

Permalink
Support for variadic types as method arguments (#1241)
Browse files Browse the repository at this point in the history
* Added support for variadic types as method arguments

* Added changelog entry

* added example protocol with varargs

* support for vararg in return type's closure

* added missing member lookup
  • Loading branch information
art-divin authored Dec 19, 2023
1 parent db7cc85 commit 7f85e02
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 27 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
([#1224](https://github.com/krzysztofzablocki/Sourcery/pull/1224)
- Fix unit tests on Linux ([#1225](https://github.com/krzysztofzablocki/Sourcery/pull/1225))
- Updated XcodeProj to 8.16.0 ([#1228](https://github.com/krzysztofzablocki/Sourcery/pull/1228))
- Support for variadic arguments as method parameters ([#1222](https://github.com/krzysztofzablocki/Sourcery/issues/1222))

## 2.1.2
## Changes
Expand Down
18 changes: 0 additions & 18 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,6 @@
"version" : "0.9.1"
}
},
{
"identity" : "cwlcatchexception",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mattgallagher/CwlCatchException.git",
"state" : {
"revision" : "f809deb30dc5c9d9b78c872e553261a61177721a",
"version" : "2.0.0"
}
},
{
"identity" : "cwlpreconditiontesting",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mattgallagher/CwlPreconditionTesting.git",
"state" : {
"revision" : "02b7a39a99c4da27abe03cab2053a9034379639f",
"version" : "2.0.0"
}
},
{
"identity" : "nimble",
"kind" : "remoteSourceControl",
Expand Down
2 changes: 2 additions & 0 deletions SourceryRuntime/Sources/AST/MethodParameter_Linux.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public class MethodParameter: NSObject, SourceryModel, Typed, Annotated, Diffabl
return isClosure
case "typeAttributes":
return typeAttributes
case "isVariadic":
return isVariadic
default:
fatalError("unable to lookup: \(member) in \(self)")
}
Expand Down
20 changes: 12 additions & 8 deletions Templates/Templates/AutoMockable.stencil
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import {{ import }}
{% macro closureReturnTypeName method %}{% if method.isOptionalReturnType %}{{ method.unwrappedReturnTypeName }}?{% else %}{{ method.returnTypeName }}{% endif %}{% endmacro %}

{% macro methodClosureDeclaration method %}
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call methodClosureName method %}: (({% for param in method.parameters %}{% call existentialClosureVariableTypeName param.typeName %}{% if not forloop.last %}, {% endif %}{% endfor %}) {% if method.isAsync %}async {% endif %}{% if method.throws %}throws {% endif %}-> {% if method.isInitializer %}Void{% else %}{% call existentialVariableTypeName method.returnTypeName %}{% endif %})?
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call methodClosureName method %}: (({% for param in method.parameters %}{% call existentialClosureVariableTypeName param.typeName param.isVariadic %}{% if not forloop.last %}, {% endif %}{% endfor %}) {% if method.isAsync %}async {% endif %}{% if method.throws %}throws {% endif %}-> {% if method.isInitializer %}Void{% else %}{% call existentialVariableTypeName method.returnTypeName %}{% endif %})?
{% endmacro %}

{% macro methodClosureCallParameters method %}{% for param in method.parameters %}{{ param.name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endmacro %}
Expand All @@ -77,11 +77,11 @@ import {{ import }}
{% endfor -%}
{% endset %}
{% if method.parameters.count == 1 and not hasNonEscapingClosures %}
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method.selectorName %}Received{% for param in method.parameters %}{{ param.name|upperFirstLetter }}: {{ '(' if param.isClosure }}({% call existentialClosureVariableTypeName param.typeName.unwrappedTypeName %}{{ ')' if param.isClosure }})?{% endfor %}
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method.selectorName %}ReceivedInvocations{% for param in method.parameters %}: [{{ '(' if param.isClosure }}({% call existentialClosureVariableTypeName param.typeName.unwrappedTypeName %}){{ ')' if param.isClosure }}{%if param.typeName.isOptional%}?{%endif%}]{% endfor %} = []
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method.selectorName %}Received{% for param in method.parameters %}{{ param.name|upperFirstLetter }}: {{ '(' if param.isClosure }}({% call existentialClosureVariableTypeName param.typeName.unwrappedTypeName param.isVariadic %}{{ ')' if param.isClosure }})?{% endfor %}
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method.selectorName %}ReceivedInvocations{% for param in method.parameters %}: [{{ '(' if param.isClosure }}({% call existentialClosureVariableTypeName param.typeName.unwrappedTypeName param.isVariadic %}){{ ')' if param.isClosure }}{%if param.typeName.isOptional%}?{%endif%}]{% endfor %} = []
{% elif not method.parameters.count == 0 and not hasNonEscapingClosures %}
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method.selectorName %}ReceivedArguments: ({% for param in method.parameters %}{{ param.name }}: {% if param.typeAttributes.escaping %}{% call existentialClosureVariableTypeName param.typeName.unwrappedTypeName %}{% else %}{% call existentialClosureVariableTypeName param.typeName %}{% endif %}{{ ', ' if not forloop.last }}{% endfor %})?
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method.selectorName %}ReceivedInvocations: [({% for param in method.parameters %}{{ param.name }}: {% if param.typeAttributes.escaping %}{% call existentialClosureVariableTypeName param.typeName.unwrappedTypeName %}{% else %}{% call existentialClosureVariableTypeName param.typeName %}{% endif %}{{ ', ' if not forloop.last }}{% endfor %})] = []
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method.selectorName %}ReceivedArguments: ({% for param in method.parameters %}{{ param.name }}: {% if param.typeAttributes.escaping %}{% call existentialClosureVariableTypeName param.typeName.unwrappedTypeName param.isVariadic %}{% else %}{% call existentialClosureVariableTypeName param.typeName param.isVariadic %}{% endif %}{{ ', ' if not forloop.last }}{% endfor %})?
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method.selectorName %}ReceivedInvocations: [({% for param in method.parameters %}{{ param.name }}: {% if param.typeAttributes.escaping %}{% call existentialClosureVariableTypeName param.typeName.unwrappedTypeName param.isVariadic %}{% else %}{% call existentialClosureVariableTypeName param.typeName param.isVariadic %}{% endif %}{{ ', ' if not forloop.last }}{% endfor %})] = []
{% endif %}
{% if not method.returnTypeName.isVoid and not method.isInitializer %}
{% call accessLevel method.accessLevel %}{% call staticSpecifier method %}var {% call swiftifyMethodName method.selectorName %}ReturnValue: {{ '(' if method.returnTypeName.isClosure and not method.isOptionalReturnType or method.returnTypeName|contains:"any "}}{% call existentialVariableTypeName method.returnTypeName %}{{ ')' if method.returnTypeName.isClosure and not method.isOptionalReturnType or method.returnTypeName|contains:"any " }}{{ '!' if not method.isOptionalReturnType }}
Expand Down Expand Up @@ -221,7 +221,7 @@ import {{ import }}
{{ typeName }}
{%- endif -%}
{%- endmacro %}
{% macro existentialClosureVariableTypeName typeName -%}
{% macro existentialClosureVariableTypeName typeName isVariadic -%}
{%- if typeName|contains:"any " and typeName|contains:"!" -%}
{{ typeName | replace:"any","(any" | replace:"!",")?" }}
{%- elif typeName|contains:"any " and typeName.isClosure and typeName|contains:"?" -%}
Expand All @@ -234,11 +234,13 @@ import {{ import }}
{{ typeName | replace:"some","(any" | replace:"?",")?" }}
{%- elif typeName|contains:"some " and typeName|contains:"?" -%}
{{ typeName | replace:"some","(any" | replace:"?",")?" }}
{%- elif isVariadic -%}
{{ typeName }}...
{%- else -%}
{{ typeName|replace:"some ","any " }}
{%- endif -%}
{%- endmacro %}
{% macro existentialParameterTypeName typeName -%}
{% macro existentialParameterTypeName typeName isVariadic -%}
{%- if typeName|contains:"any " and typeName|contains:"?," and typeName|contains:">?" -%}
{{ typeName | replace:"any","(any" | replace:"?,",")?," }}
{%- elif typeName|contains:"any " and typeName|contains:"!" -%}
Expand All @@ -253,11 +255,13 @@ import {{ import }}
{{ typeName | replace:"some","(some" | replace:"?",")?" }}
{%- elif typeName|contains:"some " and typeName.isOptional -%}
{{ typeName | replace:"some","(some" | replace:"?",")?" }}
{%- elif isVariadic -%}
{{ typeName }}...
{%- else -%}
{{ typeName }}
{%- endif -%}
{%- endmacro %}
{% macro methodName method %}func {{ method.shortName}}({%- for param in method.parameters %}{% if param.argumentLabel == nil %}_ {{ param.name }}{%elif param.argumentLabel == param.name%}{{ param.name }}{%else%}{{ param.argumentLabel }} {{ param.name }}{% endif %}: {% call existentialParameterTypeName param.typeName %}{% if not forloop.last %}, {% endif %}{% endfor -%}){% endmacro %}
{% macro methodName method %}func {{ method.shortName}}({%- for param in method.parameters %}{% if param.argumentLabel == nil %}_ {{ param.name }}{%elif param.argumentLabel == param.name%}{{ param.name }}{%else%}{{ param.argumentLabel }} {{ param.name }}{% endif %}: {% call existentialParameterTypeName param.typeName param.isVariadic %}{% if not forloop.last %}, {% endif %}{% endfor -%}){% endmacro %}

{% for type in types.protocols where type.based.AutoMockable or type|annotated:"AutoMockable" %}{% if type.name != "AutoMockable" %}
{% call accessLevel type.accessLevel %}class {{ type.name }}Mock: {{ type.name }} {
Expand Down
5 changes: 5 additions & 0 deletions Templates/Tests/Context/AutoMockable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,8 @@ protocol HouseProtocol: AutoMockable {
var f3Publisher: GenericType<Never, Never, any PersonProtocol>? { get }
var f4Publisher: GenericType<any PersonProtocol, any PersonProtocol, any PersonProtocol>? { get }
}

// sourcery: AutoMockable
protocol ExampleVararg {
func string(key: String, args: CVarArg...) -> String
}
5 changes: 5 additions & 0 deletions Templates/Tests/Context_Linux/AutoMockable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,8 @@ protocol HouseProtocol: AutoMockable {
var f3Publisher: GenericType<Never, Never, any PersonProtocol>? { get }
var f4Publisher: GenericType<any PersonProtocol, any PersonProtocol, any PersonProtocol>? { get }
}

// sourcery: AutoMockable
protocol ExampleVararg {
func string(key: String, args: CVarArg...) -> String
}
30 changes: 29 additions & 1 deletion Templates/Tests/Expected/AutoMockable.expected
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.1.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable line_length
// swiftlint:disable variable_name
Expand Down Expand Up @@ -663,6 +663,34 @@ class CurrencyPresenterMock: CurrencyPresenter {
showSourceCurrencyClosure?(currency)
}

}
class ExampleVarargMock: ExampleVararg {




//MARK: - string

var stringKeyArgsCallsCount = 0
var stringKeyArgsCalled: Bool {
return stringKeyArgsCallsCount > 0
}
var stringKeyArgsReceivedArguments: (key: String, args: CVarArg...)?
var stringKeyArgsReceivedInvocations: [(key: String, args: CVarArg...)] = []
var stringKeyArgsReturnValue: String!
var stringKeyArgsClosure: ((String, CVarArg...) -> String)?

func string(key: String, args: CVarArg...) -> String {
stringKeyArgsCallsCount += 1
stringKeyArgsReceivedArguments = (key: key, args: args)
stringKeyArgsReceivedInvocations.append((key: key, args: args))
if let stringKeyArgsClosure = stringKeyArgsClosure {
return stringKeyArgsClosure(key, args)
} else {
return stringKeyArgsReturnValue
}
}

}
class ExtendableProtocolMock: ExtendableProtocol {

Expand Down

0 comments on commit 7f85e02

Please sign in to comment.