#if !canImport(ObjectiveC) import Foundation /// :nodoc: public typealias SourceryMethod = Method /// Describes method public final class Method: NSObject, SourceryModel, Annotated, Documented, Definition, Diffable, SourceryDynamicMemberLookup { public subscript(dynamicMember member: String) -> Any? { switch member { case "definedInType": return definedInType case "shortName": return shortName case "name": return name case "selectorName": return selectorName case "callName": return callName case "parameters": return parameters case "throws": return `throws` case "throwsTypeName": return throwsTypeName case "isInitializer": return isInitializer case "accessLevel": return accessLevel case "isStatic": return isStatic case "returnTypeName": return returnTypeName case "isAsync": return isAsync case "attributes": return attributes case "isOptionalReturnType": return isOptionalReturnType case "actualReturnTypeName": return actualReturnTypeName case "isThrowsTypeGeneric": return isThrowsTypeGeneric case "isDynamic": return isDynamic case "genericRequirements": return genericRequirements default: fatalError("unable to lookup: \(member) in \(self)") } } /// Full method name, including generic constraints, i.e. `foo(bar: T)` public let name: String /// Method name including arguments names, i.e. `foo(bar:)` public var selectorName: String // sourcery: skipEquality, skipDescription /// Method name without arguments names and parentheses, i.e. `foo` public var shortName: String { return name.range(of: "(").map({ String(name[..<$0.lowerBound]) }) ?? name } // sourcery: skipEquality, skipDescription /// Method name without arguments names, parentheses and generic types, i.e. `foo` (can be used to generate code for method call) public var callName: String { return shortName.range(of: "<").map({ String(shortName[..<$0.lowerBound]) }) ?? shortName } /// Method parameters public var parameters: [MethodParameter] /// Return value type name used in declaration, including generic constraints, i.e. `where T: Equatable` public var returnTypeName: TypeName // sourcery: skipEquality, skipDescription /// Actual return value type name if declaration uses typealias, otherwise just a `returnTypeName` public var actualReturnTypeName: TypeName { return returnTypeName.actualTypeName ?? returnTypeName } // sourcery: skipEquality, skipDescription /// Return if the throwsType is generic public var isThrowsTypeGeneric: Bool { return genericParameters.contains { $0.name == throwsTypeName?.name } } // sourcery: skipEquality, skipDescription /// Actual return value type, if known public var returnType: Type? // sourcery: skipEquality, skipDescription /// Whether return value type is optional public var isOptionalReturnType: Bool { return returnTypeName.isOptional || isFailableInitializer } // sourcery: skipEquality, skipDescription /// Whether return value type is implicitly unwrapped optional public var isImplicitlyUnwrappedOptionalReturnType: Bool { return returnTypeName.isImplicitlyUnwrappedOptional } // sourcery: skipEquality, skipDescription /// Return value type name without attributes and optional type information public var unwrappedReturnTypeName: String { return returnTypeName.unwrappedTypeName } /// Whether method is async method public let isAsync: Bool /// Whether method is distributed public var isDistributed: Bool { modifiers.contains(where: { $0.name == "distributed" }) } /// Whether method throws public let `throws`: Bool /// Type of thrown error if specified public let throwsTypeName: TypeName? /// Whether method rethrows public let `rethrows`: Bool /// Method access level, i.e. `internal`, `private`, `fileprivate`, `public`, `open` public let accessLevel: String /// Whether method is a static method public let isStatic: Bool /// Whether method is a class method public let isClass: Bool // sourcery: skipEquality, skipDescription /// Whether method is an initializer public var isInitializer: Bool { return selectorName.hasPrefix("init(") || selectorName == "init" } // sourcery: skipEquality, skipDescription /// Whether method is an deinitializer public var isDeinitializer: Bool { return selectorName == "deinit" } /// Whether method is a failable initializer public let isFailableInitializer: Bool // sourcery: skipEquality, skipDescription /// Whether method is a convenience initializer public var isConvenienceInitializer: Bool { modifiers.contains { $0.name == Attribute.Identifier.convenience.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is required public var isRequired: Bool { modifiers.contains { $0.name == Attribute.Identifier.required.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is final public var isFinal: Bool { modifiers.contains { $0.name == Attribute.Identifier.final.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is mutating public var isMutating: Bool { modifiers.contains { $0.name == Attribute.Identifier.mutating.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is generic public var isGeneric: Bool { shortName.hasSuffix(">") } // sourcery: skipEquality, skipDescription /// Whether method is optional (in an Objective-C protocol) public var isOptional: Bool { modifiers.contains { $0.name == Attribute.Identifier.optional.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is nonisolated (this modifier only applies to actor methods) public var isNonisolated: Bool { modifiers.contains { $0.name == Attribute.Identifier.nonisolated.rawValue } } // sourcery: skipEquality, skipDescription /// Whether method is dynamic public var isDynamic: Bool { modifiers.contains { $0.name == Attribute.Identifier.dynamic.rawValue } } /// Annotations, that were created with // sourcery: annotation1, other = "annotation value", alterantive = 2 public let annotations: Annotations public let documentation: Documentation /// Reference to type name where the method is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc public let definedInTypeName: TypeName? // sourcery: skipEquality, skipDescription /// Reference to actual type name where the method is defined if declaration uses typealias, otherwise just a `definedInTypeName` public var actualDefinedInTypeName: TypeName? { return definedInTypeName?.actualTypeName ?? definedInTypeName } // sourcery: skipEquality, skipDescription /// Reference to actual type where the object is defined, /// nil if defined outside of any `enum`, `struct`, `class` etc or type is unknown public var definedInType: Type? /// Method attributes, i.e. `@discardableResult` public let attributes: AttributeList /// Method modifiers, i.e. `private` public let modifiers: [SourceryModifier] // Underlying parser data, never to be used by anything else // sourcery: skipEquality, skipDescription, skipCoding, skipJSExport /// :nodoc: public var __parserData: Any? /// list of generic requirements public var genericRequirements: [GenericRequirement] /// List of generic parameters /// /// - Example: /// /// ```swift /// func method(foo: GenericParameter) /// ^ ~ a generic parameter /// ``` public var genericParameters: [GenericParameter] /// :nodoc: public init(name: String, selectorName: String? = nil, parameters: [MethodParameter] = [], returnTypeName: TypeName = TypeName(name: "Void"), isAsync: Bool = false, throws: Bool = false, throwsTypeName: TypeName? = nil, rethrows: Bool = false, accessLevel: AccessLevel = .internal, isStatic: Bool = false, isClass: Bool = false, isFailableInitializer: Bool = false, attributes: AttributeList = [:], modifiers: [SourceryModifier] = [], annotations: [String: NSObject] = [:], documentation: [String] = [], definedInTypeName: TypeName? = nil, genericRequirements: [GenericRequirement] = [], genericParameters: [GenericParameter] = []) { self.name = name self.selectorName = selectorName ?? name self.parameters = parameters self.returnTypeName = returnTypeName self.isAsync = isAsync self.throws = `throws` self.throwsTypeName = throwsTypeName self.rethrows = `rethrows` self.accessLevel = accessLevel.rawValue self.isStatic = isStatic self.isClass = isClass self.isFailableInitializer = isFailableInitializer self.attributes = attributes self.modifiers = modifiers self.annotations = annotations self.documentation = documentation self.definedInTypeName = definedInTypeName self.genericRequirements = genericRequirements self.genericParameters = genericParameters } /// :nodoc: // sourcery: skipJSExport override public var description: String { var string = "\(Swift.type(of: self)): " string.append("name = \(String(describing: self.name)), ") string.append("selectorName = \(String(describing: self.selectorName)), ") string.append("parameters = \(String(describing: self.parameters)), ") string.append("returnTypeName = \(String(describing: self.returnTypeName)), ") string.append("isAsync = \(String(describing: self.isAsync)), ") string.append("`throws` = \(String(describing: self.`throws`)), ") string.append("throwsTypeName = \(String(describing: self.throwsTypeName)), ") string.append("`rethrows` = \(String(describing: self.`rethrows`)), ") string.append("accessLevel = \(String(describing: self.accessLevel)), ") string.append("isStatic = \(String(describing: self.isStatic)), ") string.append("isClass = \(String(describing: self.isClass)), ") string.append("isFailableInitializer = \(String(describing: self.isFailableInitializer)), ") string.append("annotations = \(String(describing: self.annotations)), ") string.append("documentation = \(String(describing: self.documentation)), ") string.append("definedInTypeName = \(String(describing: self.definedInTypeName)), ") string.append("attributes = \(String(describing: self.attributes)), ") string.append("modifiers = \(String(describing: self.modifiers)), ") string.append("genericRequirements = \(String(describing: self.genericRequirements)), ") string.append("genericParameters = \(String(describing: self.genericParameters))") return string } public func diffAgainst(_ object: Any?) -> DiffableResult { let results = DiffableResult() guard let castObject = object as? Method else { results.append("Incorrect type ") return results } results.append(contentsOf: DiffableResult(identifier: "name").trackDifference(actual: self.name, expected: castObject.name)) results.append(contentsOf: DiffableResult(identifier: "selectorName").trackDifference(actual: self.selectorName, expected: castObject.selectorName)) results.append(contentsOf: DiffableResult(identifier: "parameters").trackDifference(actual: self.parameters, expected: castObject.parameters)) results.append(contentsOf: DiffableResult(identifier: "returnTypeName").trackDifference(actual: self.returnTypeName, expected: castObject.returnTypeName)) results.append(contentsOf: DiffableResult(identifier: "isAsync").trackDifference(actual: self.isAsync, expected: castObject.isAsync)) results.append(contentsOf: DiffableResult(identifier: "`throws`").trackDifference(actual: self.`throws`, expected: castObject.`throws`)) results.append(contentsOf: DiffableResult(identifier: "throwsTypeName").trackDifference(actual: self.throwsTypeName, expected: castObject.throwsTypeName)) results.append(contentsOf: DiffableResult(identifier: "`rethrows`").trackDifference(actual: self.`rethrows`, expected: castObject.`rethrows`)) results.append(contentsOf: DiffableResult(identifier: "accessLevel").trackDifference(actual: self.accessLevel, expected: castObject.accessLevel)) results.append(contentsOf: DiffableResult(identifier: "isStatic").trackDifference(actual: self.isStatic, expected: castObject.isStatic)) results.append(contentsOf: DiffableResult(identifier: "isClass").trackDifference(actual: self.isClass, expected: castObject.isClass)) results.append(contentsOf: DiffableResult(identifier: "isFailableInitializer").trackDifference(actual: self.isFailableInitializer, expected: castObject.isFailableInitializer)) results.append(contentsOf: DiffableResult(identifier: "annotations").trackDifference(actual: self.annotations, expected: castObject.annotations)) results.append(contentsOf: DiffableResult(identifier: "documentation").trackDifference(actual: self.documentation, expected: castObject.documentation)) results.append(contentsOf: DiffableResult(identifier: "definedInTypeName").trackDifference(actual: self.definedInTypeName, expected: castObject.definedInTypeName)) results.append(contentsOf: DiffableResult(identifier: "attributes").trackDifference(actual: self.attributes, expected: castObject.attributes)) results.append(contentsOf: DiffableResult(identifier: "modifiers").trackDifference(actual: self.modifiers, expected: castObject.modifiers)) results.append(contentsOf: DiffableResult(identifier: "genericRequirements").trackDifference(actual: self.genericRequirements, expected: castObject.genericRequirements)) results.append(contentsOf: DiffableResult(identifier: "genericParameters").trackDifference(actual: self.genericParameters, expected: castObject.genericParameters)) return results } /// :nodoc: // sourcery: skipJSExport public override var hash: Int { var hasher = Hasher() hasher.combine(self.name) hasher.combine(self.selectorName) hasher.combine(self.parameters) hasher.combine(self.returnTypeName) hasher.combine(self.isAsync) hasher.combine(self.`throws`) hasher.combine(self.throwsTypeName) hasher.combine(self.`rethrows`) hasher.combine(self.accessLevel) hasher.combine(self.isStatic) hasher.combine(self.isClass) hasher.combine(self.isFailableInitializer) hasher.combine(self.annotations) hasher.combine(self.documentation) hasher.combine(self.definedInTypeName) hasher.combine(self.attributes) hasher.combine(self.modifiers) hasher.combine(self.genericRequirements) hasher.combine(self.genericParameters) return hasher.finalize() } /// :nodoc: public override func isEqual(_ object: Any?) -> Bool { guard let rhs = object as? Method else { return false } if self.name != rhs.name { return false } if self.selectorName != rhs.selectorName { return false } if self.parameters != rhs.parameters { return false } if self.returnTypeName != rhs.returnTypeName { return false } if self.isAsync != rhs.isAsync { return false } if self.isDistributed != rhs.isDistributed { return false } if self.`throws` != rhs.`throws` { return false } if self.throwsTypeName != rhs.throwsTypeName { return false } if self.`rethrows` != rhs.`rethrows` { return false } if self.accessLevel != rhs.accessLevel { return false } if self.isStatic != rhs.isStatic { return false } if self.isClass != rhs.isClass { return false } if self.isFailableInitializer != rhs.isFailableInitializer { return false } if self.annotations != rhs.annotations { return false } if self.documentation != rhs.documentation { return false } if self.definedInTypeName != rhs.definedInTypeName { return false } if self.attributes != rhs.attributes { return false } if self.modifiers != rhs.modifiers { return false } if self.genericRequirements != rhs.genericRequirements { return false } if self.genericParameters != rhs.genericParameters { return false } return true } // sourcery:inline:Method.AutoCoding /// :nodoc: required public init?(coder aDecoder: NSCoder) { 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 { 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 { 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 { withVaList(["returnTypeName"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.returnTypeName = returnTypeName self.returnType = aDecoder.decode(forKey: "returnType") self.isAsync = aDecoder.decode(forKey: "isAsync") self.`throws` = aDecoder.decode(forKey: "`throws`") self.throwsTypeName = aDecoder.decode(forKey: "throwsTypeName") self.`rethrows` = aDecoder.decode(forKey: "`rethrows`") guard let accessLevel: String = aDecoder.decode(forKey: "accessLevel") else { withVaList(["accessLevel"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.accessLevel = accessLevel 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 { 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 { withVaList(["documentation"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.documentation = documentation self.definedInTypeName = aDecoder.decode(forKey: "definedInTypeName") self.definedInType = aDecoder.decode(forKey: "definedInType") 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 { 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 { 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 { withVaList(["genericParameters"]) { arguments in NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments) } fatalError() }; self.genericParameters = genericParameters } /// :nodoc: public func encode(with aCoder: NSCoder) { aCoder.encode(self.name, forKey: "name") aCoder.encode(self.selectorName, forKey: "selectorName") aCoder.encode(self.parameters, forKey: "parameters") aCoder.encode(self.returnTypeName, forKey: "returnTypeName") aCoder.encode(self.returnType, forKey: "returnType") aCoder.encode(self.isAsync, forKey: "isAsync") aCoder.encode(self.`throws`, forKey: "`throws`") aCoder.encode(self.throwsTypeName, forKey: "throwsTypeName") aCoder.encode(self.`rethrows`, forKey: "`rethrows`") aCoder.encode(self.accessLevel, forKey: "accessLevel") aCoder.encode(self.isStatic, forKey: "isStatic") aCoder.encode(self.isClass, forKey: "isClass") aCoder.encode(self.isFailableInitializer, forKey: "isFailableInitializer") aCoder.encode(self.annotations, forKey: "annotations") aCoder.encode(self.documentation, forKey: "documentation") aCoder.encode(self.definedInTypeName, forKey: "definedInTypeName") aCoder.encode(self.definedInType, forKey: "definedInType") aCoder.encode(self.attributes, forKey: "attributes") aCoder.encode(self.modifiers, forKey: "modifiers") aCoder.encode(self.genericRequirements, forKey: "genericRequirements") aCoder.encode(self.genericParameters, forKey: "genericParameters") } // sourcery:end } #endif