Fix associatedtype generics (#1345)

* Preliminary associatedtype support

* Implemented associatedtype support with generic requirements

* Fixed failing test

* Squashed commit of the following:

commit 9d01e6f99a
Author: Ruslan A <r.alikhamov@gmail.com>
Date:   Fri Jun 14 20:06:41 2024 +0400

    Improved concurrency support in SwiftTemplate caching (#1344)

* Removed test code

* Removed comment

* Updated Linux classes

* update internal boilerplate code.

* Updated generated code

* Removed warnings

* Updated expected file

* Updated expected file

* Adjusted protocol type for Linux

* Removed protocol composition due to Swift compiler crash under Linux
This commit is contained in:
Ruslan A
2024-06-19 22:50:18 +04:00
committed by GitHub
parent 9d01e6f99a
commit 7153768c65
27 changed files with 889 additions and 148 deletions
@@ -246,16 +246,37 @@ class SyntaxTreeCollector: SyntaxVisitor {
let name = node.name.text.trimmed
var typeName: TypeName?
var type: Type?
if let possibleTypeName = node.inheritanceClause?.inheritedTypes.description.trimmed {
var genericRequirements: [GenericRequirement] = []
if let genericWhereClause = node.genericWhereClause {
genericRequirements = genericWhereClause.requirements.compactMap { requirement in
if let sameType = requirement.requirement.as(SameTypeRequirementSyntax.self) {
return GenericRequirement(sameType)
} else if let conformanceType = requirement.requirement.as(ConformanceRequirementSyntax.self) {
return GenericRequirement(conformanceType)
}
return nil
}
}
if let composition = processPossibleProtocolComposition(for: possibleTypeName, localName: "") {
type = composition
} else {
type = Protocol(name: possibleTypeName, genericRequirements: genericRequirements)
}
typeName = TypeName(possibleTypeName)
} else if let possibleTypeName = (node.initializer?.value as? TypeSyntax)?.description.trimmed {
type = processPossibleProtocolComposition(for: possibleTypeName, localName: "")
typeName = TypeName(possibleTypeName)
} else {
type = Type(name: "Any")
typeName = TypeName(name: "Any", actualTypeName: TypeName(name: "Any"))
}
sourceryProtocol.associatedTypes[name] = AssociatedType(name: name, typeName: typeName, type: type)
return .skipChildren
}
public override func visit(_ node: OperatorDeclSyntax) -> SyntaxVisitorContinueKind {
return .skipChildren
}
@@ -6,8 +6,12 @@ import Foundation
@objc(SwiftActor) @objcMembers
#endif
public final class Actor: Type {
// sourcery: skipJSExport
public class var kind: String { return "actor" }
/// Returns "actor"
public override var kind: String { return "actor" }
public override var kind: String { Self.kind }
/// Whether type is final
public var isFinal: Bool {
@@ -36,7 +40,8 @@ public final class Actor: Type {
annotations: [String: NSObject] = [:],
documentation: [String] = [],
isGeneric: Bool = false,
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = Actor.kind) {
super.init(
name: name,
parent: parent,
@@ -54,7 +59,8 @@ public final class Actor: Type {
annotations: annotations,
documentation: documentation,
isGeneric: isGeneric,
implements: implements
implements: implements,
kind: kind
)
}
@@ -5,8 +5,11 @@ import Foundation
@objc(SwiftClass) @objcMembers
#endif
public final class Class: Type {
// sourcery: skipJSExport
public class var kind: String { return "class" }
/// Returns "class"
public override var kind: String { return "class" }
public override var kind: String { Self.kind }
/// Whether type is final
public var isFinal: Bool {
@@ -30,7 +33,8 @@ public final class Class: Type {
annotations: [String: NSObject] = [:],
documentation: [String] = [],
isGeneric: Bool = false,
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = Class.kind) {
super.init(
name: name,
parent: parent,
@@ -48,7 +52,8 @@ public final class Class: Type {
annotations: annotations,
documentation: documentation,
isGeneric: isGeneric,
implements: implements
implements: implements,
kind: kind
)
}
@@ -8,17 +8,20 @@
import Foundation
#if canImport(ObjectiveC)
/// :nodoc:
public typealias SourceryProtocol = Protocol
/// Describes Swift protocol
#if canImport(ObjectiveC)
@objcMembers
#endif
public final class Protocol: Type {
// sourcery: skipJSExport
public class var kind: String { return "protocol" }
/// Returns "protocol"
public override var kind: String { return "protocol" }
public override var kind: String { Self.kind }
/// list of all declared associated types with their names as keys
public var associatedTypes: [String: AssociatedType] {
@@ -52,7 +55,8 @@ public final class Protocol: Type {
modifiers: [SourceryModifier] = [],
annotations: [String: NSObject] = [:],
documentation: [String] = [],
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = Protocol.kind) {
self.associatedTypes = associatedTypes
super.init(
name: name,
@@ -71,7 +75,8 @@ public final class Protocol: Type {
annotations: annotations,
documentation: documentation,
isGeneric: !associatedTypes.isEmpty || !genericRequirements.isEmpty,
implements: implements
implements: implements,
kind: kind
)
}
@@ -132,3 +137,4 @@ public final class Protocol: Type {
}
// sourcery:end
}
#endif
@@ -9,8 +9,11 @@ import Foundation
#endif
public final class ProtocolComposition: Type {
// sourcery: skipJSExport
public class var kind: String { return "protocolComposition" }
/// Returns "protocolComposition"
public override var kind: String { return "protocolComposition" }
public override var kind: String { Self.kind }
/// The names of the types composed to form this composition
public let composedTypeNames: [TypeName]
@@ -35,7 +38,8 @@ public final class ProtocolComposition: Type {
isGeneric: Bool = false,
composedTypeNames: [TypeName] = [],
composedTypes: [Type]? = nil,
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = ProtocolComposition.kind) {
self.composedTypeNames = composedTypeNames
self.composedTypes = composedTypes
super.init(
@@ -51,7 +55,8 @@ public final class ProtocolComposition: Type {
typealiases: typealiases,
annotations: annotations,
isGeneric: isGeneric,
implements: implements
implements: implements,
kind: kind
)
}
@@ -15,8 +15,11 @@ import Foundation
#endif
public final class Struct: Type {
// sourcery: skipJSExport
public class var kind: String { return "struct" }
/// Returns "struct"
public override var kind: String { return "struct" }
public override var kind: String { Self.kind }
/// :nodoc:
public override init(name: String = "",
@@ -35,7 +38,8 @@ public final class Struct: Type {
annotations: [String: NSObject] = [:],
documentation: [String] = [],
isGeneric: Bool = false,
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = Struct.kind) {
super.init(
name: name,
parent: parent,
@@ -53,7 +57,8 @@ public final class Struct: Type {
annotations: annotations,
documentation: documentation,
isGeneric: isGeneric,
implements: implements
implements: implements,
kind: kind
)
}
@@ -25,11 +25,11 @@ public enum Composer {
let composed = ParserResultsComposed(parserResult: parserResult)
let resolveType = { (typeName: TypeName, containingType: Type?) -> Type? in
return composed.resolveType(typeName: typeName, containingType: containingType)
composed.resolveType(typeName: typeName, containingType: containingType)
}
let methodResolveType = { (typeName: TypeName, containingType: Type?, method: Method) -> Type? in
return composed.resolveType(typeName: typeName, containingType: containingType, method: method)
composed.resolveType(typeName: typeName, containingType: containingType, method: method)
}
let processType = { (type: Type) in
@@ -52,7 +52,7 @@ public enum Composer {
}
if let sourceryProtocol = type as? SourceryProtocol {
resolveProtocolTypes(sourceryProtocol, resolve: resolveType)
resolveAssociatedTypes(sourceryProtocol, resolve: resolveType)
}
}
@@ -180,11 +180,13 @@ public enum Composer {
protocolComposition.composedTypes = composedTypes
}
private static func resolveProtocolTypes(_ sourceryProtocol: SourceryProtocol, resolve: TypeResolver) {
private static func resolveAssociatedTypes(_ sourceryProtocol: SourceryProtocol, resolve: TypeResolver) {
sourceryProtocol.associatedTypes.forEach { (_, value) in
guard let typeName = value.typeName,
let type = resolve(typeName, sourceryProtocol)
else { return }
else {
return
}
value.type = type
}
@@ -13,6 +13,7 @@ internal struct ParserResultsComposed {
let parsedTypes: [Type]
let functions: [SourceryMethod]
let resolvedTypealiases: [String: Typealias]
let associatedTypes: [String: AssociatedType]
let unresolvedTypealiases: [String: Typealias]
init(parserResult: FileParserResult) {
@@ -23,6 +24,7 @@ internal struct ParserResultsComposed {
let aliases = Self.typealiases(parserResult)
resolvedTypealiases = aliases.resolved
unresolvedTypealiases = aliases.unresolved
associatedTypes = Self.extractAssociatedTypes(parserResult)
parsedTypes = parserResult.types
// set definedInType for all methods and variables
@@ -51,6 +53,11 @@ internal struct ParserResultsComposed {
alias.type = resolveType(typeName: alias.typeName, containingType: alias.parent)
}
/// Map associated types
associatedTypes.forEach {
typeMap[$0.key] = $0.value.type
}
types = unifyTypes()
}
@@ -96,7 +103,7 @@ internal struct ParserResultsComposed {
resolveExtensionOfNestedType(type)
}
if let resolved = resolveGlobalName(for: oldName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases)?.name {
if let resolved = resolveGlobalName(for: oldName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases, associatedTypes: associatedTypes)?.name {
var moduleName: String = ""
if let module = type.module {
moduleName = "\(module)."
@@ -116,7 +123,7 @@ internal struct ParserResultsComposed {
// extend all types with their extensions
parsedTypes.forEach { type in
let inheritedTypes: [[String]] = type.inheritedTypes.compactMap { inheritedName in
if let resolvedGlobalName = resolveGlobalName(for: inheritedName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases)?.name {
if let resolvedGlobalName = resolveGlobalName(for: inheritedName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases, associatedTypes: associatedTypes)?.name {
return [resolvedGlobalName]
}
if let baseType = Composer.findBaseType(for: type, name: inheritedName, typesByName: typeMap) {
@@ -175,6 +182,14 @@ internal struct ParserResultsComposed {
})
}
// extract associated types from all types and add them to types
private static func extractAssociatedTypes(_ parserResult: FileParserResult) -> [String: AssociatedType] {
parserResult.types
.compactMap { $0 as? SourceryProtocol }
.map { $0.associatedTypes }
.flatMap { $0 }.reduce(into: [:]) { $0[$1.key] = $1.value }
}
/// returns typealiases map to their full names, with `resolved` removing intermediate
/// typealises and `unresolved` including typealiases that reference other typealiases.
private static func typealiases(_ parserResult: FileParserResult) -> (resolved: [String: Typealias], unresolved: [String: Typealias]) {
@@ -207,11 +222,14 @@ internal struct ParserResultsComposed {
}
/// Resolves type identifier for name
func resolveGlobalName(for type: String,
containingType: Type? = nil,
unique: [String: Type]? = nil,
modules: [String: [String: Type]],
typealiases: [String: Typealias]) -> (name: String, typealias: Typealias?)? {
func resolveGlobalName(
for type: String,
containingType: Type? = nil,
unique: [String: Type]? = nil,
modules: [String: [String: Type]],
typealiases: [String: Typealias],
associatedTypes: [String: AssociatedType]
) -> (name: String, typealias: Typealias?)? {
// if the type exists for this name and isn't an extension just return it's name
// if it's extension we need to check if there aren't other options TODO: verify
if let realType = unique?[type], realType.isExtension == false {
@@ -222,6 +240,13 @@ internal struct ParserResultsComposed {
return (name: alias.type?.globalName ?? alias.typeName.name, typealias: alias)
}
if let associatedType = associatedTypes[type],
let actualType = associatedType.type
{
let typeName = associatedType.typeName ?? TypeName(name: actualType.name)
return (name: actualType.globalName, typealias: Typealias(aliasName: type, typeName: typeName))
}
if let containingType = containingType {
if type == "Self" {
return (name: containingType.globalName, typealias: nil)
@@ -231,7 +256,7 @@ internal struct ParserResultsComposed {
while currentContainer != nil, let parentName = currentContainer?.globalName {
/// TODO: no parent for sure?
/// manually walk the containment tree
if let name = resolveGlobalName(for: "\(parentName).\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases) {
if let name = resolveGlobalName(for: "\(parentName).\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases, associatedTypes: associatedTypes) {
return name
}
@@ -565,20 +590,27 @@ internal struct ParserResultsComposed {
}
}
return unique[resolvedIdentifier]
if let associatedType = associatedTypes[resolvedIdentifier] {
return associatedType.type
}
return unique[resolvedIdentifier] ?? unique[typeName.name]
}
private func actualTypeName(for typeName: TypeName,
containingType: Type? = nil) -> TypeName? {
containingType: Type? = nil) -> TypeName? {
let unique = typeMap
let typealiases = resolvedTypealiases
let associatedTypes = associatedTypes
var unwrapped = typeName.unwrappedTypeName
if let generic = typeName.generic {
unwrapped = generic.name
} else if let type = associatedTypes[unwrapped] {
unwrapped = type.name
}
guard let aliased = resolveGlobalName(for: unwrapped, containingType: containingType, unique: unique, modules: modules, typealiases: typealiases) else {
guard let aliased = resolveGlobalName(for: unwrapped, containingType: containingType, unique: unique, modules: modules, typealiases: typealiases, associatedTypes: associatedTypes) else {
return nil
}
@@ -19,9 +19,12 @@ public final class Enum: Type {
}
}
// sourcery: skipJSExport
public class var kind: String { return "enum" }
// sourcery: skipDescription
/// Returns "enum"
public override var kind: String { return "enum" }
public override var kind: String { Self.kind }
/// Enum cases
public var cases: [EnumCase]
@@ -93,7 +96,7 @@ public final class Enum: Type {
self.rawTypeName = rawTypeName
self.hasRawType = rawTypeName != nil || !inheritedTypes.isEmpty
super.init(name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric)
super.init(name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric, kind: Self.kind)
if let rawTypeName = rawTypeName?.name, let index = self.inheritedTypes.firstIndex(of: rawTypeName) {
self.inheritedTypes.remove(at: index)
@@ -374,25 +374,25 @@ public final class Method: NSObject, SourceryModel, Annotated, Documented, Defin
/// :nodoc:
required public init?(coder aDecoder: NSCoder) {
guard let name: String = aDecoder.decode(forKey: "name") else {
guard let name: String = aDecoder.decode(forKey: "name") else {
withVaList(["name"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
}
fatalError()
}; self.name = name
guard let selectorName: String = aDecoder.decode(forKey: "selectorName") else {
guard let selectorName: String = aDecoder.decode(forKey: "selectorName") else {
withVaList(["selectorName"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
}
fatalError()
}; self.selectorName = selectorName
guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else {
guard let parameters: [MethodParameter] = aDecoder.decode(forKey: "parameters") else {
withVaList(["parameters"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
}
fatalError()
}; self.parameters = parameters
guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else {
guard let returnTypeName: TypeName = aDecoder.decode(forKey: "returnTypeName") else {
withVaList(["returnTypeName"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
}
@@ -402,7 +402,7 @@ public final class Method: NSObject, SourceryModel, Annotated, Documented, Defin
self.isAsync = aDecoder.decode(forKey: "isAsync")
self.`throws` = aDecoder.decode(forKey: "`throws`")
self.`rethrows` = aDecoder.decode(forKey: "`rethrows`")
guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else {
guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else {
withVaList(["accessLevel"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
}
@@ -411,13 +411,13 @@ public final class Method: NSObject, SourceryModel, Annotated, Documented, Defin
self.isStatic = aDecoder.decode(forKey: "isStatic")
self.isClass = aDecoder.decode(forKey: "isClass")
self.isFailableInitializer = aDecoder.decode(forKey: "isFailableInitializer")
guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else {
guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else {
withVaList(["annotations"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
}
fatalError()
}; self.annotations = annotations
guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else {
guard let documentation: Documentation = aDecoder.decode(forKey: "documentation") else {
withVaList(["documentation"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
}
@@ -425,25 +425,25 @@ public final class Method: NSObject, SourceryModel, Annotated, Documented, Defin
}; self.documentation = documentation
self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName")
self.definedInType = aDecoder.decode(forKey: "definedInType")
guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else {
guard let attributes: AttributeList = aDecoder.decode(forKey: "attributes") else {
withVaList(["attributes"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
}
fatalError()
}; self.attributes = attributes
guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else {
guard let modifiers: [SourceryModifier] = aDecoder.decode(forKey: "modifiers") else {
withVaList(["modifiers"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
}
fatalError()
}; self.modifiers = modifiers
guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else {
guard let genericRequirements: [GenericRequirement] = aDecoder.decode(forKey: "genericRequirements") else {
withVaList(["genericRequirements"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
}
fatalError()
}; self.genericRequirements = genericRequirements
guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else {
guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else {
withVaList(["genericParameters"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
}
@@ -0,0 +1,147 @@
//
// Protocol.swift
// Sourcery
//
// Created by Krzysztof Zablocki on 09/12/2016.
// Copyright © 2016 Pixle. All rights reserved.
//
import Foundation
#if !canImport(ObjectiveC)
/// :nodoc:
public typealias SourceryProtocol = Protocol
/// Describes Swift protocol
public final class Protocol: Type {
public override subscript(dynamicMember member: String) -> Any? {
switch member {
case "associatedTypes":
return associatedTypes
default:
return super[dynamicMember: member]
}
}
// sourcery: skipJSExport
public class var kind: String { return "protocol" }
/// Returns "protocol"
public override var kind: String { Self.kind }
/// list of all declared associated types with their names as keys
public var associatedTypes: [String: AssociatedType] {
didSet {
isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty
}
}
// sourcery: skipCoding
/// list of generic requirements
public override var genericRequirements: [GenericRequirement] {
didSet {
isGeneric = !associatedTypes.isEmpty || !genericRequirements.isEmpty
}
}
/// :nodoc:
public init(name: String = "",
parent: Type? = nil,
accessLevel: AccessLevel = .internal,
isExtension: Bool = false,
variables: [Variable] = [],
methods: [Method] = [],
subscripts: [Subscript] = [],
inheritedTypes: [String] = [],
containedTypes: [Type] = [],
typealiases: [Typealias] = [],
associatedTypes: [String: AssociatedType] = [:],
genericRequirements: [GenericRequirement] = [],
attributes: AttributeList = [:],
modifiers: [SourceryModifier] = [],
annotations: [String: NSObject] = [:],
documentation: [String] = [],
implements: [String: Type] = [:],
kind: String = Protocol.kind) {
self.associatedTypes = associatedTypes
super.init(
name: name,
parent: parent,
accessLevel: accessLevel,
isExtension: isExtension,
variables: variables,
methods: methods,
subscripts: subscripts,
inheritedTypes: inheritedTypes,
containedTypes: containedTypes,
typealiases: typealiases,
genericRequirements: genericRequirements,
attributes: attributes,
modifiers: modifiers,
annotations: annotations,
documentation: documentation,
isGeneric: !associatedTypes.isEmpty || !genericRequirements.isEmpty,
implements: implements,
kind: kind
)
}
/// :nodoc:
// sourcery: skipJSExport
override public var description: String {
var string = super.description
string.append(", ")
string.append("kind = \(String(describing: self.kind)), ")
string.append("associatedTypes = \(String(describing: self.associatedTypes)), ")
return string
}
override public func diffAgainst(_ object: Any?) -> DiffableResult {
let results = DiffableResult()
guard let castObject = object as? Protocol else {
results.append("Incorrect type <expected: Protocol, received: \(Swift.type(of: object))>")
return results
}
results.append(contentsOf: DiffableResult(identifier: "associatedTypes").trackDifference(actual: self.associatedTypes, expected: castObject.associatedTypes))
results.append(contentsOf: super.diffAgainst(castObject))
return results
}
/// :nodoc:
// sourcery: skipJSExport
public override var hash: Int {
var hasher = Hasher()
hasher.combine(self.associatedTypes)
hasher.combine(super.hash)
return hasher.finalize()
}
/// :nodoc:
public override func isEqual(_ object: Any?) -> Bool {
guard let rhs = object as? Protocol else { return false }
if self.associatedTypes != rhs.associatedTypes { return false }
return super.isEqual(rhs)
}
// sourcery:inline:Protocol.AutoCoding
/// :nodoc:
required public init?(coder aDecoder: NSCoder) {
guard let associatedTypes: [String: AssociatedType] = aDecoder.decode(forKey: "associatedTypes") else {
withVaList(["associatedTypes"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
}
fatalError()
}; self.associatedTypes = associatedTypes
super.init(coder: aDecoder)
}
/// :nodoc:
override public func encode(with aCoder: NSCoder) {
super.encode(with: aCoder)
aCoder.encode(self.associatedTypes, forKey: "associatedTypes")
}
// sourcery:end
}
#endif
@@ -92,7 +92,11 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, Sou
// sourcery: forceEquality
/// Kind of type declaration, i.e. `enum`, `struct`, `class`, `protocol` or `extension`
public var kind: String { isExtension ? "extension" : "unknown" }
public var kind: String { isExtension ? "extension" : _kind }
// sourcery: skipJSExport
/// Kind of a backing store for `self.kind`
private var _kind: String
/// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open`
public let accessLevel: String
@@ -422,7 +426,8 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, Sou
annotations: [String: NSObject] = [:],
documentation: [String] = [],
isGeneric: Bool = false,
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = "unknown") {
self.localName = name
self.accessLevel = accessLevel.rawValue
self.isExtension = isExtension
@@ -441,6 +446,7 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, Sou
self.isGeneric = isGeneric
self.genericRequirements = genericRequirements
self.implements = implements
self._kind = kind
super.init()
containedTypes.forEach {
containedType[$0.localName] = $0
@@ -471,13 +477,15 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, Sou
/// :nodoc:
// sourcery: skipJSExport
override public var description: String {
var string = "\(Swift.type(of: self)): "
let type: Type.Type = Swift.type(of: self)
var string = "\(type): "
string.append("module = \(String(describing: self.module)), ")
string.append("imports = \(String(describing: self.imports)), ")
string.append("allImports = \(String(describing: self.allImports)), ")
string.append("typealiases = \(String(describing: self.typealiases)), ")
string.append("isExtension = \(String(describing: self.isExtension)), ")
string.append("kind = \(String(describing: self.kind)), ")
string.append("_kind = \(String(describing: self._kind)), ")
string.append("accessLevel = \(String(describing: self.accessLevel)), ")
string.append("name = \(String(describing: self.name)), ")
string.append("isUnknownExtension = \(String(describing: self.isUnknownExtension)), ")
@@ -613,6 +621,12 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, Sou
fatalError()
}; self.typealiases = typealiases
self.isExtension = aDecoder.decode(forKey: "isExtension")
guard let _kind: String = aDecoder.decode(forKey: "_kind") else {
withVaList(["_kind"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
}
fatalError()
}; self._kind = _kind
guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else {
withVaList(["accessLevel"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
@@ -731,6 +745,7 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, Sou
aCoder.encode(self.imports, forKey: "imports")
aCoder.encode(self.typealiases, forKey: "typealiases")
aCoder.encode(self.isExtension, forKey: "isExtension")
aCoder.encode(self._kind, forKey: "_kind")
aCoder.encode(self.accessLevel, forKey: "accessLevel")
aCoder.encode(self.isGeneric, forKey: "isGeneric")
aCoder.encode(self.localName, forKey: "localName")
+6 -2
View File
@@ -9,9 +9,13 @@ import Foundation
/// Defines Swift enum
@objcMembers
public final class Enum: Type {
// sourcery: skipJSExport
public class var kind: String { return "enum" }
// sourcery: skipDescription
/// Returns "enum"
public override var kind: String { return "enum" }
public override var kind: String { Self.kind }
/// Enum cases
public var cases: [EnumCase]
@@ -83,7 +87,7 @@ public final class Enum: Type {
self.rawTypeName = rawTypeName
self.hasRawType = rawTypeName != nil || !inheritedTypes.isEmpty
super.init(name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric)
super.init(name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric, kind: Self.kind)
if let rawTypeName = rawTypeName?.name, let index = self.inheritedTypes.firstIndex(of: rawTypeName) {
self.inheritedTypes.remove(at: index)
@@ -404,7 +404,7 @@ public final class Method: NSObject, SourceryModel, Annotated, Documented, Defin
}
fatalError()
}; self.genericRequirements = genericRequirements
guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else {
guard let genericParameters: [GenericParameter] = aDecoder.decode(forKey: "genericParameters") else {
withVaList(["genericParameters"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
}
+16 -2
View File
@@ -48,7 +48,11 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable {
// sourcery: forceEquality
/// Kind of type declaration, i.e. `enum`, `struct`, `class`, `protocol` or `extension`
public var kind: String { isExtension ? "extension" : "unknown" }
public var kind: String { isExtension ? "extension" : _kind }
// sourcery: skipJSExport
/// Kind of a backing store for `self.kind`
private var _kind: String
/// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open`
public let accessLevel: String
@@ -378,7 +382,8 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable {
annotations: [String: NSObject] = [:],
documentation: [String] = [],
isGeneric: Bool = false,
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = "unknown") {
self.localName = name
self.accessLevel = accessLevel.rawValue
self.isExtension = isExtension
@@ -397,6 +402,7 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable {
self.isGeneric = isGeneric
self.genericRequirements = genericRequirements
self.implements = implements
self._kind = kind
super.init()
containedTypes.forEach {
containedType[$0.localName] = $0
@@ -435,6 +441,7 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable {
string.append("typealiases = \(String(describing: self.typealiases)), ")
string.append("isExtension = \(String(describing: self.isExtension)), ")
string.append("kind = \(String(describing: self.kind)), ")
string.append("_kind = \(String(describing: self._kind)), ")
string.append("accessLevel = \(String(describing: self.accessLevel)), ")
string.append("name = \(String(describing: self.name)), ")
string.append("isUnknownExtension = \(String(describing: self.isUnknownExtension)), ")
@@ -570,6 +577,12 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable {
fatalError()
}; self.typealiases = typealiases
self.isExtension = aDecoder.decode(forKey: "isExtension")
guard let _kind: String = aDecoder.decode(forKey: "_kind") else {
withVaList(["_kind"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
}
fatalError()
}; self._kind = _kind
guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else {
withVaList(["accessLevel"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
@@ -688,6 +701,7 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable {
aCoder.encode(self.imports, forKey: "imports")
aCoder.encode(self.typealiases, forKey: "typealiases")
aCoder.encode(self.isExtension, forKey: "isExtension")
aCoder.encode(self._kind, forKey: "_kind")
aCoder.encode(self.accessLevel, forKey: "accessLevel")
aCoder.encode(self.isGeneric, forKey: "isGeneric")
aCoder.encode(self.localName, forKey: "localName")
+40 -5
View File
@@ -63,6 +63,7 @@ public final class StencilTemplate: StencilSwiftKit.StencilSwiftTemplate {
ext.registerAccessLevelFilters(.private)
ext.registerAccessLevelFilters(.fileprivate)
ext.registerAccessLevelFilters(.internal)
ext.registerAccessLevelFilters(.package)
ext.registerBoolFilterOrWithArguments("based",
filter: { (t: Type, name: String) in t.based[name] != nil },
@@ -86,6 +87,14 @@ public final class StencilTemplate: StencilSwiftKit.StencilSwiftTemplate {
ext.registerFilter("isEmpty", filter: isEmpty)
ext.registerFilter("reversed", filter: reversed)
ext.registerFilter("toArray", filter: toArray)
ext.registerFilter("sortedValuesByKeys", filter: sortedValuesByKeys)
ext.registerFilter("last", filter: last)
ext.registerFilterWithArguments("push") { arg1, arg2 in
var array = arg1 as? [Any] ?? []
array.append(arg2)
return array
}
#if canImport(ObjectiveC)
ext.registerFilterWithArguments("sorted") { (array, propertyName: String) -> Any? in
@@ -172,7 +181,6 @@ public final class StencilTemplate: StencilSwiftKit.StencilSwiftTemplate {
public extension Annotated {
func isAnnotated(with annotation: String) -> Bool {
if annotation.contains("=") {
let components = annotation.components(separatedBy: "=").map({ $0.trimmingCharacters(in: .whitespaces) })
var keyPath = components[0].components(separatedBy: ".")
@@ -284,6 +292,29 @@ public extension Stencil.Extension {
}
private func last(_ value: Any?) -> Any? {
switch value {
case let arr as NSArray:
return arr.lastObject
default:
return nil
}
}
private func sortedValuesByKeys(_ value: Any?) -> Any? {
switch value {
case let dict as NSDictionary:
let keys = dict.allKeys.sorted { (($0 as? String) ?? "" < ($1 as? String) ?? "") }
var retVal: [Any?] = []
for key in keys {
retVal.append(dict[key])
}
return retVal
default:
return nil
}
}
private func toArray(_ value: Any?) -> Any? {
switch value {
case let array as NSArray:
@@ -310,11 +341,15 @@ private func count(_ value: Any?) -> Any? {
}
private func isEmpty(_ value: Any?) -> Any? {
guard let array = value as? NSArray else {
return false
switch value {
case let array as NSArray:
// swiftlint:disable:next empty_count
array.count == 0
case let string as NSString:
string.length == 0
default:
false
}
// swiftlint:disable:next empty_count
return array.count == 0
}
private struct Filter<T> {
@@ -31,8 +31,12 @@ import Foundation
@objc(SwiftActor) @objcMembers
#endif
public final class Actor: Type {
// sourcery: skipJSExport
public class var kind: String { return "actor" }
/// Returns "actor"
public override var kind: String { return "actor" }
public override var kind: String { Self.kind }
/// Whether type is final
public var isFinal: Bool {
@@ -61,7 +65,8 @@ public final class Actor: Type {
annotations: [String: NSObject] = [:],
documentation: [String] = [],
isGeneric: Bool = false,
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = Actor.kind) {
super.init(
name: name,
parent: parent,
@@ -79,7 +84,8 @@ public final class Actor: Type {
annotations: annotations,
documentation: documentation,
isGeneric: isGeneric,
implements: implements
implements: implements,
kind: kind
)
}
@@ -620,8 +626,11 @@ import Foundation
@objc(SwiftClass) @objcMembers
#endif
public final class Class: Type {
// sourcery: skipJSExport
public class var kind: String { return "class" }
/// Returns "class"
public override var kind: String { return "class" }
public override var kind: String { Self.kind }
/// Whether type is final
public var isFinal: Bool {
@@ -645,7 +654,8 @@ public final class Class: Type {
annotations: [String: NSObject] = [:],
documentation: [String] = [],
isGeneric: Bool = false,
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = Class.kind) {
super.init(
name: name,
parent: parent,
@@ -663,7 +673,8 @@ public final class Class: Type {
annotations: annotations,
documentation: documentation,
isGeneric: isGeneric,
implements: implements
implements: implements,
kind: kind
)
}
@@ -746,11 +757,11 @@ public enum Composer {
let composed = ParserResultsComposed(parserResult: parserResult)
let resolveType = { (typeName: TypeName, containingType: Type?) -> Type? in
return composed.resolveType(typeName: typeName, containingType: containingType)
composed.resolveType(typeName: typeName, containingType: containingType)
}
let methodResolveType = { (typeName: TypeName, containingType: Type?, method: Method) -> Type? in
return composed.resolveType(typeName: typeName, containingType: containingType, method: method)
composed.resolveType(typeName: typeName, containingType: containingType, method: method)
}
let processType = { (type: Type) in
@@ -773,7 +784,7 @@ public enum Composer {
}
if let sourceryProtocol = type as? SourceryProtocol {
resolveProtocolTypes(sourceryProtocol, resolve: resolveType)
resolveAssociatedTypes(sourceryProtocol, resolve: resolveType)
}
}
@@ -901,11 +912,13 @@ public enum Composer {
protocolComposition.composedTypes = composedTypes
}
private static func resolveProtocolTypes(_ sourceryProtocol: SourceryProtocol, resolve: TypeResolver) {
private static func resolveAssociatedTypes(_ sourceryProtocol: SourceryProtocol, resolve: TypeResolver) {
sourceryProtocol.associatedTypes.forEach { (_, value) in
guard let typeName = value.typeName,
let type = resolve(typeName, sourceryProtocol)
else { return }
else {
return
}
value.type = type
}
@@ -2218,6 +2231,7 @@ internal struct ParserResultsComposed {
let parsedTypes: [Type]
let functions: [SourceryMethod]
let resolvedTypealiases: [String: Typealias]
let associatedTypes: [String: AssociatedType]
let unresolvedTypealiases: [String: Typealias]
init(parserResult: FileParserResult) {
@@ -2228,6 +2242,7 @@ internal struct ParserResultsComposed {
let aliases = Self.typealiases(parserResult)
resolvedTypealiases = aliases.resolved
unresolvedTypealiases = aliases.unresolved
associatedTypes = Self.extractAssociatedTypes(parserResult)
parsedTypes = parserResult.types
// set definedInType for all methods and variables
@@ -2256,6 +2271,11 @@ internal struct ParserResultsComposed {
alias.type = resolveType(typeName: alias.typeName, containingType: alias.parent)
}
/// Map associated types
associatedTypes.forEach {
typeMap[$0.key] = $0.value.type
}
types = unifyTypes()
}
@@ -2301,7 +2321,7 @@ internal struct ParserResultsComposed {
resolveExtensionOfNestedType(type)
}
if let resolved = resolveGlobalName(for: oldName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases)?.name {
if let resolved = resolveGlobalName(for: oldName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases, associatedTypes: associatedTypes)?.name {
var moduleName: String = ""
if let module = type.module {
moduleName = "\\(module)."
@@ -2321,7 +2341,7 @@ internal struct ParserResultsComposed {
// extend all types with their extensions
parsedTypes.forEach { type in
let inheritedTypes: [[String]] = type.inheritedTypes.compactMap { inheritedName in
if let resolvedGlobalName = resolveGlobalName(for: inheritedName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases)?.name {
if let resolvedGlobalName = resolveGlobalName(for: inheritedName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases, associatedTypes: associatedTypes)?.name {
return [resolvedGlobalName]
}
if let baseType = Composer.findBaseType(for: type, name: inheritedName, typesByName: typeMap) {
@@ -2380,6 +2400,14 @@ internal struct ParserResultsComposed {
})
}
// extract associated types from all types and add them to types
private static func extractAssociatedTypes(_ parserResult: FileParserResult) -> [String: AssociatedType] {
parserResult.types
.compactMap { $0 as? SourceryProtocol }
.map { $0.associatedTypes }
.flatMap { $0 }.reduce(into: [:]) { $0[$1.key] = $1.value }
}
/// returns typealiases map to their full names, with `resolved` removing intermediate
/// typealises and `unresolved` including typealiases that reference other typealiases.
private static func typealiases(_ parserResult: FileParserResult) -> (resolved: [String: Typealias], unresolved: [String: Typealias]) {
@@ -2412,11 +2440,14 @@ internal struct ParserResultsComposed {
}
/// Resolves type identifier for name
func resolveGlobalName(for type: String,
containingType: Type? = nil,
unique: [String: Type]? = nil,
modules: [String: [String: Type]],
typealiases: [String: Typealias]) -> (name: String, typealias: Typealias?)? {
func resolveGlobalName(
for type: String,
containingType: Type? = nil,
unique: [String: Type]? = nil,
modules: [String: [String: Type]],
typealiases: [String: Typealias],
associatedTypes: [String: AssociatedType]
) -> (name: String, typealias: Typealias?)? {
// if the type exists for this name and isn't an extension just return it's name
// if it's extension we need to check if there aren't other options TODO: verify
if let realType = unique?[type], realType.isExtension == false {
@@ -2427,6 +2458,13 @@ internal struct ParserResultsComposed {
return (name: alias.type?.globalName ?? alias.typeName.name, typealias: alias)
}
if let associatedType = associatedTypes[type],
let actualType = associatedType.type
{
let typeName = associatedType.typeName ?? TypeName(name: actualType.name)
return (name: actualType.globalName, typealias: Typealias(aliasName: type, typeName: typeName))
}
if let containingType = containingType {
if type == "Self" {
return (name: containingType.globalName, typealias: nil)
@@ -2436,7 +2474,7 @@ internal struct ParserResultsComposed {
while currentContainer != nil, let parentName = currentContainer?.globalName {
/// TODO: no parent for sure?
/// manually walk the containment tree
if let name = resolveGlobalName(for: "\\(parentName).\\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases) {
if let name = resolveGlobalName(for: "\\(parentName).\\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases, associatedTypes: associatedTypes) {
return name
}
@@ -2770,20 +2808,27 @@ internal struct ParserResultsComposed {
}
}
return unique[resolvedIdentifier]
if let associatedType = associatedTypes[resolvedIdentifier] {
return associatedType.type
}
return unique[resolvedIdentifier] ?? unique[typeName.name]
}
private func actualTypeName(for typeName: TypeName,
containingType: Type? = nil) -> TypeName? {
containingType: Type? = nil) -> TypeName? {
let unique = typeMap
let typealiases = resolvedTypealiases
let associatedTypes = associatedTypes
var unwrapped = typeName.unwrappedTypeName
if let generic = typeName.generic {
unwrapped = generic.name
} else if let type = associatedTypes[unwrapped] {
unwrapped = type.name
}
guard let aliased = resolveGlobalName(for: unwrapped, containingType: containingType, unique: unique, modules: modules, typealiases: typealiases) else {
guard let aliased = resolveGlobalName(for: unwrapped, containingType: containingType, unique: unique, modules: modules, typealiases: typealiases, associatedTypes: associatedTypes) else {
return nil
}
@@ -2862,8 +2907,11 @@ public typealias SourceryProtocol = Protocol
#endif
public final class Protocol: Type {
// sourcery: skipJSExport
public class var kind: String { return "protocol" }
/// Returns "protocol"
public override var kind: String { return "protocol" }
public override var kind: String { Self.kind }
/// list of all declared associated types with their names as keys
public var associatedTypes: [String: AssociatedType] {
@@ -2897,7 +2945,8 @@ public final class Protocol: Type {
modifiers: [SourceryModifier] = [],
annotations: [String: NSObject] = [:],
documentation: [String] = [],
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = Protocol.kind) {
self.associatedTypes = associatedTypes
super.init(
name: name,
@@ -2916,7 +2965,8 @@ public final class Protocol: Type {
annotations: annotations,
documentation: documentation,
isGeneric: !associatedTypes.isEmpty || !genericRequirements.isEmpty,
implements: implements
implements: implements,
kind: kind
)
}
@@ -2992,8 +3042,11 @@ import Foundation
#endif
public final class ProtocolComposition: Type {
// sourcery: skipJSExport
public class var kind: String { return "protocolComposition" }
/// Returns "protocolComposition"
public override var kind: String { return "protocolComposition" }
public override var kind: String { Self.kind }
/// The names of the types composed to form this composition
public let composedTypeNames: [TypeName]
@@ -3018,7 +3071,8 @@ public final class ProtocolComposition: Type {
isGeneric: Bool = false,
composedTypeNames: [TypeName] = [],
composedTypes: [Type]? = nil,
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = ProtocolComposition.kind) {
self.composedTypeNames = composedTypeNames
self.composedTypes = composedTypes
super.init(
@@ -3034,7 +3088,8 @@ public final class ProtocolComposition: Type {
typealiases: typealiases,
annotations: annotations,
isGeneric: isGeneric,
implements: implements
implements: implements,
kind: kind
)
}
@@ -3224,8 +3279,11 @@ import Foundation
#endif
public final class Struct: Type {
// sourcery: skipJSExport
public class var kind: String { return "struct" }
/// Returns "struct"
public override var kind: String { return "struct" }
public override var kind: String { Self.kind }
/// :nodoc:
public override init(name: String = "",
@@ -3244,7 +3302,8 @@ public final class Struct: Type {
annotations: [String: NSObject] = [:],
documentation: [String] = [],
isGeneric: Bool = false,
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = Struct.kind) {
super.init(
name: name,
parent: parent,
@@ -3262,7 +3321,8 @@ public final class Struct: Type {
annotations: annotations,
documentation: documentation,
isGeneric: isGeneric,
implements: implements
implements: implements,
kind: kind
)
}
@@ -4238,9 +4298,13 @@ import Foundation
/// Defines Swift enum
@objcMembers
public final class Enum: Type {
// sourcery: skipJSExport
public class var kind: String { return "enum" }
// sourcery: skipDescription
/// Returns "enum"
public override var kind: String { return "enum" }
public override var kind: String { Self.kind }
/// Enum cases
public var cases: [EnumCase]
@@ -4312,7 +4376,7 @@ public final class Enum: Type {
self.rawTypeName = rawTypeName
self.hasRawType = rawTypeName != nil || !inheritedTypes.isEmpty
super.init(name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric)
super.init(name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric, kind: Self.kind)
if let rawTypeName = rawTypeName?.name, let index = self.inheritedTypes.firstIndex(of: rawTypeName) {
self.inheritedTypes.remove(at: index)
@@ -6025,7 +6089,11 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable {
// sourcery: forceEquality
/// Kind of type declaration, i.e. `enum`, `struct`, `class`, `protocol` or `extension`
public var kind: String { isExtension ? "extension" : "unknown" }
public var kind: String { isExtension ? "extension" : _kind }
// sourcery: skipJSExport
/// Kind of a backing store for `self.kind`
private var _kind: String
/// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open`
public let accessLevel: String
@@ -6355,7 +6423,8 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable {
annotations: [String: NSObject] = [:],
documentation: [String] = [],
isGeneric: Bool = false,
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = "unknown") {
self.localName = name
self.accessLevel = accessLevel.rawValue
self.isExtension = isExtension
@@ -6374,6 +6443,7 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable {
self.isGeneric = isGeneric
self.genericRequirements = genericRequirements
self.implements = implements
self._kind = kind
super.init()
containedTypes.forEach {
containedType[$0.localName] = $0
@@ -6412,6 +6482,7 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable {
string.append("typealiases = \\(String(describing: self.typealiases)), ")
string.append("isExtension = \\(String(describing: self.isExtension)), ")
string.append("kind = \\(String(describing: self.kind)), ")
string.append("_kind = \\(String(describing: self._kind)), ")
string.append("accessLevel = \\(String(describing: self.accessLevel)), ")
string.append("name = \\(String(describing: self.name)), ")
string.append("isUnknownExtension = \\(String(describing: self.isUnknownExtension)), ")
@@ -6547,6 +6618,12 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable {
fatalError()
}; self.typealiases = typealiases
self.isExtension = aDecoder.decode(forKey: "isExtension")
guard let _kind: String = aDecoder.decode(forKey: "_kind") else {
withVaList(["_kind"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
}
fatalError()
}; self._kind = _kind
guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else {
withVaList(["accessLevel"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
@@ -6665,6 +6742,7 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable {
aCoder.encode(self.imports, forKey: "imports")
aCoder.encode(self.typealiases, forKey: "typealiases")
aCoder.encode(self.isExtension, forKey: "isExtension")
aCoder.encode(self._kind, forKey: "_kind")
aCoder.encode(self.accessLevel, forKey: "accessLevel")
aCoder.encode(self.isGeneric, forKey: "isGeneric")
aCoder.encode(self.localName, forKey: "localName")
@@ -31,8 +31,12 @@ import Foundation
@objc(SwiftActor) @objcMembers
#endif
public final class Actor: Type {
// sourcery: skipJSExport
public class var kind: String { return "actor" }
/// Returns "actor"
public override var kind: String { return "actor" }
public override var kind: String { Self.kind }
/// Whether type is final
public var isFinal: Bool {
@@ -61,7 +65,8 @@ public final class Actor: Type {
annotations: [String: NSObject] = [:],
documentation: [String] = [],
isGeneric: Bool = false,
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = Actor.kind) {
super.init(
name: name,
parent: parent,
@@ -79,7 +84,8 @@ public final class Actor: Type {
annotations: annotations,
documentation: documentation,
isGeneric: isGeneric,
implements: implements
implements: implements,
kind: kind
)
}
@@ -620,8 +626,11 @@ import Foundation
@objc(SwiftClass) @objcMembers
#endif
public final class Class: Type {
// sourcery: skipJSExport
public class var kind: String { return "class" }
/// Returns "class"
public override var kind: String { return "class" }
public override var kind: String { Self.kind }
/// Whether type is final
public var isFinal: Bool {
@@ -645,7 +654,8 @@ public final class Class: Type {
annotations: [String: NSObject] = [:],
documentation: [String] = [],
isGeneric: Bool = false,
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = Class.kind) {
super.init(
name: name,
parent: parent,
@@ -663,7 +673,8 @@ public final class Class: Type {
annotations: annotations,
documentation: documentation,
isGeneric: isGeneric,
implements: implements
implements: implements,
kind: kind
)
}
@@ -746,11 +757,11 @@ public enum Composer {
let composed = ParserResultsComposed(parserResult: parserResult)
let resolveType = { (typeName: TypeName, containingType: Type?) -> Type? in
return composed.resolveType(typeName: typeName, containingType: containingType)
composed.resolveType(typeName: typeName, containingType: containingType)
}
let methodResolveType = { (typeName: TypeName, containingType: Type?, method: Method) -> Type? in
return composed.resolveType(typeName: typeName, containingType: containingType, method: method)
composed.resolveType(typeName: typeName, containingType: containingType, method: method)
}
let processType = { (type: Type) in
@@ -773,7 +784,7 @@ public enum Composer {
}
if let sourceryProtocol = type as? SourceryProtocol {
resolveProtocolTypes(sourceryProtocol, resolve: resolveType)
resolveAssociatedTypes(sourceryProtocol, resolve: resolveType)
}
}
@@ -901,11 +912,13 @@ public enum Composer {
protocolComposition.composedTypes = composedTypes
}
private static func resolveProtocolTypes(_ sourceryProtocol: SourceryProtocol, resolve: TypeResolver) {
private static func resolveAssociatedTypes(_ sourceryProtocol: SourceryProtocol, resolve: TypeResolver) {
sourceryProtocol.associatedTypes.forEach { (_, value) in
guard let typeName = value.typeName,
let type = resolve(typeName, sourceryProtocol)
else { return }
else {
return
}
value.type = type
}
@@ -2218,6 +2231,7 @@ internal struct ParserResultsComposed {
let parsedTypes: [Type]
let functions: [SourceryMethod]
let resolvedTypealiases: [String: Typealias]
let associatedTypes: [String: AssociatedType]
let unresolvedTypealiases: [String: Typealias]
init(parserResult: FileParserResult) {
@@ -2228,6 +2242,7 @@ internal struct ParserResultsComposed {
let aliases = Self.typealiases(parserResult)
resolvedTypealiases = aliases.resolved
unresolvedTypealiases = aliases.unresolved
associatedTypes = Self.extractAssociatedTypes(parserResult)
parsedTypes = parserResult.types
// set definedInType for all methods and variables
@@ -2256,6 +2271,11 @@ internal struct ParserResultsComposed {
alias.type = resolveType(typeName: alias.typeName, containingType: alias.parent)
}
/// Map associated types
associatedTypes.forEach {
typeMap[$0.key] = $0.value.type
}
types = unifyTypes()
}
@@ -2301,7 +2321,7 @@ internal struct ParserResultsComposed {
resolveExtensionOfNestedType(type)
}
if let resolved = resolveGlobalName(for: oldName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases)?.name {
if let resolved = resolveGlobalName(for: oldName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases, associatedTypes: associatedTypes)?.name {
var moduleName: String = ""
if let module = type.module {
moduleName = "\\(module)."
@@ -2321,7 +2341,7 @@ internal struct ParserResultsComposed {
// extend all types with their extensions
parsedTypes.forEach { type in
let inheritedTypes: [[String]] = type.inheritedTypes.compactMap { inheritedName in
if let resolvedGlobalName = resolveGlobalName(for: inheritedName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases)?.name {
if let resolvedGlobalName = resolveGlobalName(for: inheritedName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases, associatedTypes: associatedTypes)?.name {
return [resolvedGlobalName]
}
if let baseType = Composer.findBaseType(for: type, name: inheritedName, typesByName: typeMap) {
@@ -2380,6 +2400,14 @@ internal struct ParserResultsComposed {
})
}
// extract associated types from all types and add them to types
private static func extractAssociatedTypes(_ parserResult: FileParserResult) -> [String: AssociatedType] {
parserResult.types
.compactMap { $0 as? SourceryProtocol }
.map { $0.associatedTypes }
.flatMap { $0 }.reduce(into: [:]) { $0[$1.key] = $1.value }
}
/// returns typealiases map to their full names, with `resolved` removing intermediate
/// typealises and `unresolved` including typealiases that reference other typealiases.
private static func typealiases(_ parserResult: FileParserResult) -> (resolved: [String: Typealias], unresolved: [String: Typealias]) {
@@ -2412,11 +2440,14 @@ internal struct ParserResultsComposed {
}
/// Resolves type identifier for name
func resolveGlobalName(for type: String,
containingType: Type? = nil,
unique: [String: Type]? = nil,
modules: [String: [String: Type]],
typealiases: [String: Typealias]) -> (name: String, typealias: Typealias?)? {
func resolveGlobalName(
for type: String,
containingType: Type? = nil,
unique: [String: Type]? = nil,
modules: [String: [String: Type]],
typealiases: [String: Typealias],
associatedTypes: [String: AssociatedType]
) -> (name: String, typealias: Typealias?)? {
// if the type exists for this name and isn't an extension just return it's name
// if it's extension we need to check if there aren't other options TODO: verify
if let realType = unique?[type], realType.isExtension == false {
@@ -2427,6 +2458,13 @@ internal struct ParserResultsComposed {
return (name: alias.type?.globalName ?? alias.typeName.name, typealias: alias)
}
if let associatedType = associatedTypes[type],
let actualType = associatedType.type
{
let typeName = associatedType.typeName ?? TypeName(name: actualType.name)
return (name: actualType.globalName, typealias: Typealias(aliasName: type, typeName: typeName))
}
if let containingType = containingType {
if type == "Self" {
return (name: containingType.globalName, typealias: nil)
@@ -2436,7 +2474,7 @@ internal struct ParserResultsComposed {
while currentContainer != nil, let parentName = currentContainer?.globalName {
/// TODO: no parent for sure?
/// manually walk the containment tree
if let name = resolveGlobalName(for: "\\(parentName).\\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases) {
if let name = resolveGlobalName(for: "\\(parentName).\\(type)", containingType: nil, unique: unique, modules: modules, typealiases: typealiases, associatedTypes: associatedTypes) {
return name
}
@@ -2770,20 +2808,27 @@ internal struct ParserResultsComposed {
}
}
return unique[resolvedIdentifier]
if let associatedType = associatedTypes[resolvedIdentifier] {
return associatedType.type
}
return unique[resolvedIdentifier] ?? unique[typeName.name]
}
private func actualTypeName(for typeName: TypeName,
containingType: Type? = nil) -> TypeName? {
containingType: Type? = nil) -> TypeName? {
let unique = typeMap
let typealiases = resolvedTypealiases
let associatedTypes = associatedTypes
var unwrapped = typeName.unwrappedTypeName
if let generic = typeName.generic {
unwrapped = generic.name
} else if let type = associatedTypes[unwrapped] {
unwrapped = type.name
}
guard let aliased = resolveGlobalName(for: unwrapped, containingType: containingType, unique: unique, modules: modules, typealiases: typealiases) else {
guard let aliased = resolveGlobalName(for: unwrapped, containingType: containingType, unique: unique, modules: modules, typealiases: typealiases, associatedTypes: associatedTypes) else {
return nil
}
@@ -2862,8 +2907,11 @@ public typealias SourceryProtocol = Protocol
#endif
public final class Protocol: Type {
// sourcery: skipJSExport
public class var kind: String { return "protocol" }
/// Returns "protocol"
public override var kind: String { return "protocol" }
public override var kind: String { Self.kind }
/// list of all declared associated types with their names as keys
public var associatedTypes: [String: AssociatedType] {
@@ -2897,7 +2945,8 @@ public final class Protocol: Type {
modifiers: [SourceryModifier] = [],
annotations: [String: NSObject] = [:],
documentation: [String] = [],
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = Protocol.kind) {
self.associatedTypes = associatedTypes
super.init(
name: name,
@@ -2916,7 +2965,8 @@ public final class Protocol: Type {
annotations: annotations,
documentation: documentation,
isGeneric: !associatedTypes.isEmpty || !genericRequirements.isEmpty,
implements: implements
implements: implements,
kind: kind
)
}
@@ -2992,8 +3042,11 @@ import Foundation
#endif
public final class ProtocolComposition: Type {
// sourcery: skipJSExport
public class var kind: String { return "protocolComposition" }
/// Returns "protocolComposition"
public override var kind: String { return "protocolComposition" }
public override var kind: String { Self.kind }
/// The names of the types composed to form this composition
public let composedTypeNames: [TypeName]
@@ -3018,7 +3071,8 @@ public final class ProtocolComposition: Type {
isGeneric: Bool = false,
composedTypeNames: [TypeName] = [],
composedTypes: [Type]? = nil,
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = ProtocolComposition.kind) {
self.composedTypeNames = composedTypeNames
self.composedTypes = composedTypes
super.init(
@@ -3034,7 +3088,8 @@ public final class ProtocolComposition: Type {
typealiases: typealiases,
annotations: annotations,
isGeneric: isGeneric,
implements: implements
implements: implements,
kind: kind
)
}
@@ -3224,8 +3279,11 @@ import Foundation
#endif
public final class Struct: Type {
// sourcery: skipJSExport
public class var kind: String { return "struct" }
/// Returns "struct"
public override var kind: String { return "struct" }
public override var kind: String { Self.kind }
/// :nodoc:
public override init(name: String = "",
@@ -3244,7 +3302,8 @@ public final class Struct: Type {
annotations: [String: NSObject] = [:],
documentation: [String] = [],
isGeneric: Bool = false,
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = Struct.kind) {
super.init(
name: name,
parent: parent,
@@ -3262,7 +3321,8 @@ public final class Struct: Type {
annotations: annotations,
documentation: documentation,
isGeneric: isGeneric,
implements: implements
implements: implements,
kind: kind
)
}
@@ -4531,9 +4591,12 @@ public final class Enum: Type {
}
}
// sourcery: skipJSExport
public class var kind: String { return "enum" }
// sourcery: skipDescription
/// Returns "enum"
public override var kind: String { return "enum" }
public override var kind: String { Self.kind }
/// Enum cases
public var cases: [EnumCase]
@@ -4605,7 +4668,7 @@ public final class Enum: Type {
self.rawTypeName = rawTypeName
self.hasRawType = rawTypeName != nil || !inheritedTypes.isEmpty
super.init(name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric)
super.init(name: name, parent: parent, accessLevel: accessLevel, isExtension: isExtension, variables: variables, methods: methods, inheritedTypes: inheritedTypes, containedTypes: containedTypes, typealiases: typealiases, attributes: attributes, modifiers: modifiers, annotations: annotations, documentation: documentation, isGeneric: isGeneric, kind: Self.kind)
if let rawTypeName = rawTypeName?.name, let index = self.inheritedTypes.firstIndex(of: rawTypeName) {
self.inheritedTypes.remove(at: index)
@@ -6734,7 +6797,11 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, Sou
// sourcery: forceEquality
/// Kind of type declaration, i.e. `enum`, `struct`, `class`, `protocol` or `extension`
public var kind: String { isExtension ? "extension" : "unknown" }
public var kind: String { isExtension ? "extension" : _kind }
// sourcery: skipJSExport
/// Kind of a backing store for `self.kind`
private var _kind: String
/// Type access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open`
public let accessLevel: String
@@ -7064,7 +7131,8 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, Sou
annotations: [String: NSObject] = [:],
documentation: [String] = [],
isGeneric: Bool = false,
implements: [String: Type] = [:]) {
implements: [String: Type] = [:],
kind: String = "unknown") {
self.localName = name
self.accessLevel = accessLevel.rawValue
self.isExtension = isExtension
@@ -7083,6 +7151,7 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, Sou
self.isGeneric = isGeneric
self.genericRequirements = genericRequirements
self.implements = implements
self._kind = kind
super.init()
containedTypes.forEach {
containedType[$0.localName] = $0
@@ -7113,13 +7182,15 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, Sou
/// :nodoc:
// sourcery: skipJSExport
override public var description: String {
var string = "\\(Swift.type(of: self)): "
let type: Type.Type = Swift.type(of: self)
var string = "\\(type): "
string.append("module = \\(String(describing: self.module)), ")
string.append("imports = \\(String(describing: self.imports)), ")
string.append("allImports = \\(String(describing: self.allImports)), ")
string.append("typealiases = \\(String(describing: self.typealiases)), ")
string.append("isExtension = \\(String(describing: self.isExtension)), ")
string.append("kind = \\(String(describing: self.kind)), ")
string.append("_kind = \\(String(describing: self._kind)), ")
string.append("accessLevel = \\(String(describing: self.accessLevel)), ")
string.append("name = \\(String(describing: self.name)), ")
string.append("isUnknownExtension = \\(String(describing: self.isUnknownExtension)), ")
@@ -7255,6 +7326,12 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, Sou
fatalError()
}; self.typealiases = typealiases
self.isExtension = aDecoder.decode(forKey: "isExtension")
guard let _kind: String = aDecoder.decode(forKey: "_kind") else {
withVaList(["_kind"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
}
fatalError()
}; self._kind = _kind
guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else {
withVaList(["accessLevel"]) { arguments in
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
@@ -7373,6 +7450,7 @@ public class Type: NSObject, SourceryModel, Annotated, Documented, Diffable, Sou
aCoder.encode(self.imports, forKey: "imports")
aCoder.encode(self.typealiases, forKey: "typealiases")
aCoder.encode(self.isExtension, forKey: "isExtension")
aCoder.encode(self._kind, forKey: "_kind")
aCoder.encode(self.accessLevel, forKey: "accessLevel")
aCoder.encode(self.isGeneric, forKey: "isGeneric")
aCoder.encode(self.localName, forKey: "localName")
-9
View File
@@ -485,15 +485,6 @@ internal func == (lhs: EqEnum, rhs: EqEnum) -> Bool {
let outputInterceptor = OutputInterceptor()
sourcery.dryOutput = outputInterceptor.handleOutput(_:)
let expectedResults = ["Basic+Other.swift",
"Basic.swift",
"Basic+Other.swift",
"Basic.swift",
"Basic.swift",
"Basic.swift",
"Function.swift"]
.compactMap { try? (Stubs.resultDirectory + Path($0)).read(.utf8) }
expect {
try sourcery.processFiles(.sources(Paths(include: [Stubs.sourceDirectory])),
usingTemplates: Paths(include: templatePaths),
+2 -2
View File
@@ -1793,7 +1793,7 @@ class ParserComposerSpec: QuickSpec {
actualTypeName: givenTypealias.typeName
)
)
let actualProtocol = parse(code).first
let actualProtocol = parse(code).last
expect(actualProtocol).to(equal(expectedProtocol))
let actualTypeName = (actualProtocol as? SourceryProtocol)?.associatedTypes.first?.value.typeName?.actualTypeName
expect(actualTypeName).to(equal(givenTypealias.actualTypeName))
@@ -1902,7 +1902,7 @@ class ParserComposerSpec: QuickSpec {
it("resolves protocol generic requirement types and inherits associated types") {
let expectedRightType = Struct(name: "RightType")
let genericProtocol = Protocol(name: "GenericProtocol", associatedTypes: ["LeftType": AssociatedType(name: "LeftType")])
let genericProtocol = Protocol(name: "GenericProtocol", associatedTypes: ["LeftType": AssociatedType(name: "LeftType", typeName: TypeName(name: "Any"))])
let expectedProtocol = Protocol(name: "SomeGenericProtocol", inheritedTypes: ["GenericProtocol"])
expectedProtocol.associatedTypes = genericProtocol.associatedTypes
expectedProtocol.genericRequirements = [
@@ -33,7 +33,7 @@ final class FileParserAssociatedTypeSpec: QuickSpec {
associatedtype Bar
}
"""
expect(associatedType(code)).to(equal([AssociatedType(name: "Bar")]))
expect(associatedType(code)).to(equal([AssociatedType(name: "Bar", typeName: TypeName(name: "Any"))]))
}
}
@@ -45,7 +45,7 @@ final class FileParserAssociatedTypeSpec: QuickSpec {
associatedtype Baz
}
"""
expect(associatedType(code).sorted(by: { $0.name < $1.name })).to(equal([AssociatedType(name: "Bar"), AssociatedType(name: "Baz")]))
expect(associatedType(code).sorted(by: { $0.name < $1.name })).to(equal([AssociatedType(name: "Bar", typeName: TypeName(name: "Any")), AssociatedType(name: "Baz", typeName: TypeName(name: "Any"))]))
}
}
@@ -231,7 +231,7 @@ var variable: Bool
expect(arguments).toNot(beNil())
if let parsedArguments = arguments {
for expected in expectedArguments {
expect((parsedArguments[expected.key] as? NSObject)).to(equal(expected.value))
expect(parsedArguments[expected.key]).to(equal(expected.value))
}
}
}
+43 -1
View File
@@ -332,8 +332,50 @@ import {{ import }}
{%- endmacro %}
{% macro methodName method %}func {{ method.shortName}}({%- for param in method.parameters %}{% if param.argumentLabel == nil %}_ {% if not param.name == "" %}{{ param.name }}{% else %}arg{{ param.index }}{% endif %}{%elif param.argumentLabel == param.name%}{{ param.name }}{%else%}{{ param.argumentLabel }} {{ param.name }}{% endif %}: {% if param.typeName.isClosure and param.typeName.closure.parameters.count > 1 %}({% endif %}{% call existentialParameterTypeName param.typeName param.isVariadic %}{% if not forloop.last %}, {% endif %}{% endfor -%}){% endmacro %}
{% macro extractProtocolCompositionFromAssociatedTypes type -%}
{%- if type.associatedTypes|sortedValuesByKeys|count > 0 -%}
<
{%- for associatedType in type.associatedTypes|sortedValuesByKeys -%}
{% if associatedType.type.kind != nil and associatedType.type.kind|contains:"protocol" %}
{{ associatedType.name }}: {{ associatedType.typeName }},
{%- endif -%}
{%- endfor -%}
>
{%- endif -%}
{%- endmacro %}
{%- macro extractProtocolRequirementsFromAssociatedTypes associatedTypes -%}
{%- for associatedType in associatedTypes -%}
{%- if associatedType.type.kind != nil and associatedType.type.kind|contains:"protocol" -%}
{%- for requirement in associatedType.type.genericRequirements -%}
{%- set requirementString -%}
{{ requirement.leftType.name }} {{ requirement.relationshipSyntax }} {{ requirement.rightType.typeName.name }}
{%- endset -%}
{{ requirementString }},
{%- endfor -%}
{%- endif -%}
{%- endfor -%}
{%- endmacro -%}
{% macro extractProtocolRequirementsFromType type -%}
{%- set requirements -%}
{% call extractProtocolRequirementsFromAssociatedTypes type.associatedTypes|sortedValuesByKeys %}
{%- endset -%}
{% if requirements|isEmpty == false %}
where {{ requirements }}{
{%- else -%}
{
{% endif %}
{%- 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 }} {
{% call accessLevel type.accessLevel %}class {{ type.name }}Mock{% set generics %}{% call extractProtocolCompositionFromAssociatedTypes type %}{% endset %}{{ generics | replace:",>",">"}}: {{ type.name }} {%- set requirements -%}{% call extractProtocolRequirementsFromType type %}{%- endset -%} {{ requirements|replace:",{","{"|replace:"{"," {" }}
{% for associatedType in type.associatedTypes|sortedValuesByKeys %}
{% if associatedType.type.kind == nil or not associatedType.type.kind|contains:"protocol" %}
typealias {{ associatedType.name }} = {% if associatedType.type != nil %}{{ associatedType.type.name }}{% elif associatedType.typeName != nil %}{{ associatedType.typeName.name }}{% else %}Any{% endif %}
{% endif %}
{% endfor %}
{% if type.accessLevel == "public" %}public init() {}{% endif %}
@@ -270,3 +270,25 @@ public protocol ProtocolWithMethodWithInoutParameter {
func execute(param: inout String)
func execute(param: inout String, bar: Int)
}
//sourcery:AutoMockable
protocol TestProtocol {
associatedtype Value: Sequence where Value.Element: Collection, Value.Element: Hashable, Value.Element: Comparable
func getValue() -> Value
associatedtype Value2 = Int
func getValue2() -> Value2
associatedtype Value3: Collection where Value3.Element == String
func getValue3() -> Value3
associatedtype Value5: Sequence where Value5.Element == Int
func getValue5() -> Value5
associatedtype Value6: Sequence where Value6.Element == Int, Value6.Element: Hashable, Value6.Element: Comparable
func getValue6() -> Value6
}
@@ -270,3 +270,25 @@ public protocol ProtocolWithMethodWithInoutParameter {
func execute(param: inout String)
func execute(param: inout String, bar: Int)
}
//sourcery:AutoMockable
protocol TestProtocol {
associatedtype Value: Sequence where Value.Element: Collection, Value.Element: Hashable, Value.Element: Comparable
func getValue() -> Value
associatedtype Value2 = Int
func getValue2() -> Value2
associatedtype Value3: Collection where Value3.Element == String
func getValue3() -> Value3
associatedtype Value5: Sequence where Value5.Element == Int
func getValue5() -> Value5
associatedtype Value6: Sequence where Value6.Element == Int, Value6.Element: Hashable, Value6.Element: Comparable
func getValue6() -> Value6
}
+105 -1
View File
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.2.4 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable line_length
// swiftlint:disable variable_name
@@ -31,6 +31,7 @@ import AppKit
public class AccessLevelProtocolMock: AccessLevelProtocol {
@@ -1644,6 +1645,109 @@ class SubscriptProtocolMock: SubscriptProtocol {
subscript<T>(arg: String) -> T? where T : Cancellable {
get throws { fatalError("Subscripts are not fully supported yet") }
}
}
class TestProtocolMock<
Value: Sequence,
Value3: Collection,
Value5: Sequence,
Value6: Sequence>: TestProtocol
where Value.Element : Collection,Value.Element : Hashable,Value.Element : Comparable,Value3.Element == String,Value5.Element == Int,Value6.Element == Int,Value6.Element : Hashable,Value6.Element : Comparable {
typealias Value2 = Int
//MARK: - getValue
var getValueSequenceCallsCount = 0
var getValueSequenceCalled: Bool {
return getValueSequenceCallsCount > 0
}
var getValueSequenceReturnValue: Value!
var getValueSequenceClosure: (() -> Value)?
func getValue() -> Value {
getValueSequenceCallsCount += 1
if let getValueSequenceClosure = getValueSequenceClosure {
return getValueSequenceClosure()
} else {
return getValueSequenceReturnValue
}
}
//MARK: - getValue2
var getValue2Value2CallsCount = 0
var getValue2Value2Called: Bool {
return getValue2Value2CallsCount > 0
}
var getValue2Value2ReturnValue: Value2!
var getValue2Value2Closure: (() -> Value2)?
func getValue2() -> Value2 {
getValue2Value2CallsCount += 1
if let getValue2Value2Closure = getValue2Value2Closure {
return getValue2Value2Closure()
} else {
return getValue2Value2ReturnValue
}
}
//MARK: - getValue3
var getValue3CollectionCallsCount = 0
var getValue3CollectionCalled: Bool {
return getValue3CollectionCallsCount > 0
}
var getValue3CollectionReturnValue: Value3!
var getValue3CollectionClosure: (() -> Value3)?
func getValue3() -> Value3 {
getValue3CollectionCallsCount += 1
if let getValue3CollectionClosure = getValue3CollectionClosure {
return getValue3CollectionClosure()
} else {
return getValue3CollectionReturnValue
}
}
//MARK: - getValue5
var getValue5SequenceCallsCount = 0
var getValue5SequenceCalled: Bool {
return getValue5SequenceCallsCount > 0
}
var getValue5SequenceReturnValue: Value5!
var getValue5SequenceClosure: (() -> Value5)?
func getValue5() -> Value5 {
getValue5SequenceCallsCount += 1
if let getValue5SequenceClosure = getValue5SequenceClosure {
return getValue5SequenceClosure()
} else {
return getValue5SequenceReturnValue
}
}
//MARK: - getValue6
var getValue6SequenceCallsCount = 0
var getValue6SequenceCalled: Bool {
return getValue6SequenceCallsCount > 0
}
var getValue6SequenceReturnValue: Value6!
var getValue6SequenceClosure: (() -> Value6)?
func getValue6() -> Value6 {
getValue6SequenceCallsCount += 1
if let getValue6SequenceClosure = getValue6SequenceClosure {
return getValue6SequenceClosure()
} else {
return getValue6SequenceReturnValue
}
}
}
class ThrowableProtocolMock: ThrowableProtocol {
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.1.7 https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.2.4 https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable line_length
// swiftlint:disable variable_name
@@ -31,6 +31,7 @@ import AppKit
public class AccessLevelProtocolMock: AccessLevelProtocol {
@@ -1644,6 +1645,109 @@ class SubscriptProtocolMock: SubscriptProtocol {
subscript<T>(arg: String) -> T? where T : Cancellable {
get throws { fatalError("Subscripts are not fully supported yet") }
}
}
class TestProtocolMock<
Value: Sequence,
Value3: Collection,
Value5: Sequence,
Value6: Sequence>: TestProtocol
where Value.Element : Collection,Value.Element : Hashable,Value.Element : Comparable,Value3.Element == String,Value5.Element == Int,Value6.Element == Int,Value6.Element : Hashable,Value6.Element : Comparable {
typealias Value2 = Int
//MARK: - getValue
var getValueSequenceCallsCount = 0
var getValueSequenceCalled: Bool {
return getValueSequenceCallsCount > 0
}
var getValueSequenceReturnValue: Value!
var getValueSequenceClosure: (() -> Value)?
func getValue() -> Value {
getValueSequenceCallsCount += 1
if let getValueSequenceClosure = getValueSequenceClosure {
return getValueSequenceClosure()
} else {
return getValueSequenceReturnValue
}
}
//MARK: - getValue2
var getValue2Value2CallsCount = 0
var getValue2Value2Called: Bool {
return getValue2Value2CallsCount > 0
}
var getValue2Value2ReturnValue: Value2!
var getValue2Value2Closure: (() -> Value2)?
func getValue2() -> Value2 {
getValue2Value2CallsCount += 1
if let getValue2Value2Closure = getValue2Value2Closure {
return getValue2Value2Closure()
} else {
return getValue2Value2ReturnValue
}
}
//MARK: - getValue3
var getValue3CollectionCallsCount = 0
var getValue3CollectionCalled: Bool {
return getValue3CollectionCallsCount > 0
}
var getValue3CollectionReturnValue: Value3!
var getValue3CollectionClosure: (() -> Value3)?
func getValue3() -> Value3 {
getValue3CollectionCallsCount += 1
if let getValue3CollectionClosure = getValue3CollectionClosure {
return getValue3CollectionClosure()
} else {
return getValue3CollectionReturnValue
}
}
//MARK: - getValue5
var getValue5SequenceCallsCount = 0
var getValue5SequenceCalled: Bool {
return getValue5SequenceCallsCount > 0
}
var getValue5SequenceReturnValue: Value5!
var getValue5SequenceClosure: (() -> Value5)?
func getValue5() -> Value5 {
getValue5SequenceCallsCount += 1
if let getValue5SequenceClosure = getValue5SequenceClosure {
return getValue5SequenceClosure()
} else {
return getValue5SequenceReturnValue
}
}
//MARK: - getValue6
var getValue6SequenceCallsCount = 0
var getValue6SequenceCalled: Bool {
return getValue6SequenceCallsCount > 0
}
var getValue6SequenceReturnValue: Value6!
var getValue6SequenceClosure: (() -> Value6)?
func getValue6() -> Value6 {
getValue6SequenceCallsCount += 1
if let getValue6SequenceClosure = getValue6SequenceClosure {
return getValue6SequenceClosure()
} else {
return getValue6SequenceReturnValue
}
}
}
class ThrowableProtocolMock: ThrowableProtocol {