Add support for inheritance generic parameters in methods.
This commit is contained in:
parent
807dc8953b
commit
a2f9e68e72
|
@ -28,13 +28,13 @@ public struct Generator {
|
|||
}
|
||||
|
||||
ext.registerFilter("matchableGenericNames") { (value: Any?) in
|
||||
guard let parameters = value as? [MethodParameter] else { return value }
|
||||
return self.matchableGenerics(with: parameters)
|
||||
guard let method = value as? Method else { return value }
|
||||
return self.matchableGenericTypes(from: method)
|
||||
}
|
||||
|
||||
ext.registerFilter("matchableGenericWhere") { (value: Any?) in
|
||||
guard let parameters = value as? [MethodParameter] else { return value }
|
||||
return self.matchableGenerics(where: parameters)
|
||||
ext.registerFilter("matchableGenericWhereClause") { (value: Any?) in
|
||||
guard let method = value as? Method else { return value }
|
||||
return self.matchableGenericsWhereClause(from: method)
|
||||
}
|
||||
|
||||
ext.registerFilter("matchableParameterSignature") { (value: Any?) in
|
||||
|
@ -68,24 +68,20 @@ public struct Generator {
|
|||
return try environment.renderTemplate(string: Templates.mock, context: ["containers": containers, "debug": debug])
|
||||
}
|
||||
|
||||
private func matchableGenerics(with parameters: [MethodParameter]) -> String {
|
||||
guard parameters.isEmpty == false else { return "" }
|
||||
private func matchableGenericTypes(from method: Method) -> String {
|
||||
guard method.parameters.isEmpty == false else { return "" }
|
||||
|
||||
let genericParameters = parameters.enumerated().map { index, parameter -> String in
|
||||
let type = parameter.isOptional ? "OptionalMatchable" : "Matchable"
|
||||
return "M\(index + 1): Cuckoo.\(type)"
|
||||
}.joined(separator: ", ")
|
||||
return "<\(genericParameters)>"
|
||||
let matchableGenericParameters = (1...method.parameters.count).map { "M\($0): Cuckoo.Matchable" }
|
||||
let methodGenericParameters = method.genericParameters.map { $0.description }
|
||||
return "<\((matchableGenericParameters + methodGenericParameters).joined(separator: ", "))>"
|
||||
}
|
||||
|
||||
private func matchableGenerics(where parameters: [MethodParameter]) -> String {
|
||||
guard parameters.isEmpty == false else { return "" }
|
||||
private func matchableGenericsWhereClause(from method: Method) -> String {
|
||||
guard method.parameters.isEmpty == false else { return "" }
|
||||
|
||||
let whereClause = parameters.enumerated().map { index, parameter in
|
||||
let type = parameter.isOptional ? "OptionalMatchedType" : "MatchedType"
|
||||
return "M\(index + 1).\(type) == \(genericSafeType(from: parameter.type.withoutAttributes.unoptionaled.sugarized))"
|
||||
}.joined(separator: ", ")
|
||||
return " where \(whereClause)"
|
||||
let matchableWhereConstraints = method.parameters.enumerated().map { "M\($0 + 1).MatchedType == \(genericSafeType(from: $1.typeWithoutAttributes))" }
|
||||
let methodWhereConstraints = method.whereConstraints
|
||||
return " where \((matchableWhereConstraints + methodWhereConstraints).joined(separator: ", "))"
|
||||
}
|
||||
|
||||
private func matchableParameterSignature(with parameters: [MethodParameter]) -> String {
|
||||
|
|
|
@ -102,7 +102,7 @@ extension Templates {
|
|||
{% for attribute in method.attributes %}
|
||||
{{ attribute.text }}
|
||||
{% endfor %}
|
||||
{{ method.accessibility }}{% if container.isImplementation and method.isOverriding %} override{% endif %} func {{ method.name }}({{ method.parameterSignature }}) {{ method.returnSignature }} {
|
||||
{{ method.accessibility }}{% if container.isImplementation and method.isOverriding %} override{% endif %} func {{ method.name }}{{ method.genericParameters }}({{ method.parameterSignature }}) {{ method.returnSignature }} {{ method.whereClause }} {
|
||||
{{ method.parameters|openNestedClosure:method.isThrowing }}
|
||||
return{% if method.isThrowing %} try{% endif %} cuckoo_manager.call{% if method.isThrowing %}Throws{% endif %}("{{method.fullyQualifiedName}}",
|
||||
parameters: ({{method.parameterNames}}),
|
||||
|
|
|
@ -28,7 +28,7 @@ extension Templates {
|
|||
{% endfor %}
|
||||
|
||||
{% for method in container.methods %}
|
||||
{{ method.accessibility }}{% if container.@type == "ClassDeclaration" and method.isOverriding %} override{% endif %} func {{ method.name }}({{ method.parameterSignature }}) {{ method.returnSignature }} {
|
||||
{{ method.accessibility }}{% if container.@type == "ClassDeclaration" and method.isOverriding %} override{% endif %} func {{ method.name }}{{ method.genericParameters }}({{ method.parameterSignature }}) {{ method.returnSignature }} {{ method.whereClause }} {
|
||||
return DefaultValueRegistry.defaultValue(for: {{method.returnType|genericSafe}}.self)
|
||||
}
|
||||
{% endfor %}
|
||||
|
|
|
@ -21,7 +21,7 @@ extension Templates {
|
|||
}
|
||||
{% endfor %}
|
||||
{% for method in container.methods %}
|
||||
func {{method.name}}{{method.parameters|matchableGenericNames}}({{method.parameters|matchableParameterSignature}}) -> {{method.stubFunction}}<({{method.inputTypes|genericSafe}}){%if method.returnType != "Void" %}, {{method.returnType|genericSafe}}{%endif%}>{{method.parameters|matchableGenericWhere}} {
|
||||
func {{method.name}}{{method.self|matchableGenericNames}}({{method.parameters|matchableParameterSignature}}) -> {{method.stubFunction}}<({{method.inputTypes|genericSafe}}){%if method.returnType != "Void" %}, {{method.returnType|genericSafe}}{%endif%}>{{method.self|matchableGenericWhereClause}} {
|
||||
{{method.parameters|parameterMatchers}}
|
||||
return .init(stub: cuckoo_manager.createStub(for: {{ container.mockName }}.self, method: "{{method.fullyQualifiedName}}", parameterMatchers: matchers))
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ extension Templates {
|
|||
|
||||
{% for method in container.methods %}
|
||||
@discardableResult
|
||||
func {{method.name}}{{method.parameters|matchableGenericNames}}({{method.parameters|matchableParameterSignature}}) -> Cuckoo.__DoNotUse<({{method.inputTypes|genericSafe}}), {{method.returnType|genericSafe}}>{{method.parameters|matchableGenericWhere}} {
|
||||
func {{method.name}}{{method.self|matchableGenericNames}}({{method.parameters|matchableParameterSignature}}) -> Cuckoo.__DoNotUse<{{method.returnType|genericSafe}}>{{method.self|matchableGenericWhereClause}} {
|
||||
{{method.parameters|parameterMatchers}}
|
||||
return cuckoo_manager.verify("{{method.fullyQualifiedName}}", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation)
|
||||
}
|
||||
|
|
|
@ -192,6 +192,23 @@ public struct Tokenizer {
|
|||
returnTypeString = "Void"
|
||||
}
|
||||
let returnType = WrappableType(parsing: returnTypeString)
|
||||
let genericParameters = tokenize(dictionary[Key.Substructure.rawValue] as? [SourceKitRepresentable] ?? []).only(GenericParameter.self)
|
||||
|
||||
// TODO: add support for where constraints
|
||||
let whereConstraints: [String] = []
|
||||
// if let bodyRange = bodyRange {
|
||||
// returnSignature = source.utf8[nameRange!.endIndex..<bodyRange.startIndex].takeUntil(occurence: "{")?.trimmed ?? ""
|
||||
// } else {
|
||||
// returnSignature = source.utf8[nameRange!.endIndex..<range!.endIndex].trimmed
|
||||
// if returnSignature.isEmpty {
|
||||
// let untilThrows = String(source.utf8.dropFirst(nameRange!.endIndex))?
|
||||
// .takeUntil(occurence: "throws").map { $0 + "throws" }?
|
||||
// .trimmed
|
||||
// if let untilThrows = untilThrows, untilThrows == "throws" || untilThrows == "rethrows" {
|
||||
// returnSignature = "\(untilThrows)"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// When bodyRange != nil, we need to create .ClassMethod instead of .ProtocolMethod
|
||||
if let bodyRange = bodyRange {
|
||||
|
@ -204,7 +221,9 @@ public struct Tokenizer {
|
|||
nameRange: nameRange!,
|
||||
parameters: parameters,
|
||||
bodyRange: bodyRange,
|
||||
attributes: attributes)
|
||||
attributes: attributes,
|
||||
genericParameters: genericParameters,
|
||||
whereConstraints: whereConstraints)
|
||||
} else {
|
||||
return ProtocolMethod(
|
||||
name: name,
|
||||
|
@ -214,7 +233,9 @@ public struct Tokenizer {
|
|||
range: range!,
|
||||
nameRange: nameRange!,
|
||||
parameters: parameters,
|
||||
attributes: attributes)
|
||||
attributes: attributes,
|
||||
genericParameters: genericParameters,
|
||||
whereConstraints: whereConstraints)
|
||||
}
|
||||
|
||||
case Kinds.GenericParameter.rawValue:
|
||||
|
|
|
@ -16,6 +16,8 @@ public struct ClassMethod: Method {
|
|||
public var parameters: [MethodParameter]
|
||||
public var bodyRange: CountableRange<Int>
|
||||
public var attributes: [Attribute]
|
||||
public var genericParameters: [GenericParameter]
|
||||
public var whereConstraints: [String]
|
||||
public var isOptional: Bool {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ public struct Initializer: Method, HasAccessibility {
|
|||
public var isOverriding: Bool
|
||||
public var required: Bool
|
||||
public var attributes: [Attribute]
|
||||
public var genericParameters: [GenericParameter]
|
||||
public var whereConstraints: [String]
|
||||
|
||||
public var isOptional: Bool {
|
||||
return false
|
||||
|
|
|
@ -19,6 +19,8 @@ public protocol Method: Token, HasAccessibility {
|
|||
var hasClosureParams: Bool { get }
|
||||
var hasOptionalParams: Bool { get }
|
||||
var attributes: [Attribute] { get }
|
||||
var genericParameters: [GenericParameter] { get }
|
||||
var whereConstraints: [String] { get }
|
||||
}
|
||||
|
||||
public extension Method {
|
||||
|
@ -95,7 +97,11 @@ public extension Method {
|
|||
}
|
||||
}.joined(separator: ", ")
|
||||
|
||||
let genericParametersString = genericParameters.map { $0.description }.joined(separator: ", ")
|
||||
let isGeneric = !genericParameters.isEmpty
|
||||
|
||||
return [
|
||||
"self": self,
|
||||
"name": rawName,
|
||||
"accessibility": accessibility.sourceName,
|
||||
"returnSignature": returnSignature,
|
||||
|
@ -117,6 +123,8 @@ public extension Method {
|
|||
"hasClosureParams": hasClosureParams,
|
||||
"hasOptionalParams": hasOptionalParams,
|
||||
"attributes": attributes.filter { $0.isSupported },
|
||||
"genericParameters": isGeneric ? "<\(genericParametersString)>" : "",
|
||||
"whereClause": whereConstraints.isEmpty ? "" : "where \(whereConstraints.joined(separator: ", "))"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ public struct ProtocolMethod: Method {
|
|||
public var nameRange: CountableRange<Int>
|
||||
public var parameters: [MethodParameter]
|
||||
public var attributes: [Attribute]
|
||||
public var genericParameters: [GenericParameter]
|
||||
public var whereConstraints: [String]
|
||||
|
||||
public var isOptional: Bool {
|
||||
return attributes.map { $0.kind }.contains(.optional)
|
||||
|
|
|
@ -201,6 +201,15 @@ final class FinalClass {
|
|||
var shouldBeIgnoredByCuckoo = true
|
||||
}
|
||||
|
||||
protocol GenericFunctionProtocol {
|
||||
func method<T>(param: T)
|
||||
}
|
||||
|
||||
class GenericFunctionClass {
|
||||
func method<T>(param: T) where T: CustomStringConvertible {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class InternalFieldsInPublicClass {
|
||||
internal var field: Int? = nil
|
||||
|
|
Loading…
Reference in New Issue