From bf215ca54d89497975d38957b29159077ed90ab3 Mon Sep 17 00:00:00 2001 From: Iceman Date: Wed, 6 Nov 2024 12:37:01 +0900 Subject: [PATCH 01/10] Cleanup render function arguments --- .../Models/ArgumentsHistoryModel.swift | 14 ++++-- .../Models/ClosureModel.swift | 30 +++++++----- .../Models/IfMacroModel.swift | 12 ++++- .../MockoloFramework/Models/MethodModel.swift | 48 +++++++++---------- Sources/MockoloFramework/Models/Model.swift | 23 +++++---- .../Models/NominalModel.swift | 29 +++-------- .../MockoloFramework/Models/ParamModel.swift | 5 +- .../Models/ParsedEntity.swift | 36 +++++++++----- .../Models/TypeAliasModel.swift | 7 ++- .../Models/VariableModel.swift | 43 ++++++++++------- .../Operations/Generator.swift | 19 ++++---- .../Operations/TemplateRenderer.swift | 13 ++--- .../Operations/UniqueModelGenerator.swift | 13 ++++- .../Parsers/SourceParser.swift | 6 +-- .../Parsers/SwiftSyntaxExtensions.swift | 44 ++++++++--------- .../Templates/ClosureTemplate.swift | 3 +- .../Templates/IfMacroTemplate.swift | 19 +++++--- .../Templates/MethodTemplate.swift | 43 ++++++++--------- .../Templates/NominalTemplate.swift | 44 ++++++++--------- .../Templates/VariableTemplate.swift | 12 +++-- .../Utils/InheritanceResolver.swift | 2 +- .../MockoloFramework/Utils/TypeParser.swift | 4 +- Tests/MockoloTestCase.swift | 6 +-- 23 files changed, 263 insertions(+), 212 deletions(-) diff --git a/Sources/MockoloFramework/Models/ArgumentsHistoryModel.swift b/Sources/MockoloFramework/Models/ArgumentsHistoryModel.swift index f4ee3b82..0e8bc2a2 100644 --- a/Sources/MockoloFramework/Models/ArgumentsHistoryModel.swift +++ b/Sources/MockoloFramework/Models/ArgumentsHistoryModel.swift @@ -33,17 +33,23 @@ final class ArgumentsHistoryModel: Model { return force || isHistoryAnnotated } - func render(with identifier: String, encloser: String, useTemplateFunc: Bool = false, useMockObservable: Bool = false, allowSetCallCount: Bool = false, mockFinal: Bool = false, enableFuncArgsHistory: Bool, disableCombineDefaultValues: Bool = false) -> String? { - guard enable(force: enableFuncArgsHistory) else { + func render( + context: RenderContext, + arguments: GenerationArguments + ) -> String? { + guard enable(force: arguments.enableFuncArgsHistory) else { + return nil + } + guard let overloadingResolvedName = context.overloadingResolvedName else { return nil } switch capturableParamNames.count { case 1: - return "\(identifier)\(String.argsHistorySuffix).append(\(capturableParamNames[0]))" + return "\(overloadingResolvedName)\(String.argsHistorySuffix).append(\(capturableParamNames[0]))" case 2...: let paramNamesStr = capturableParamNames.joined(separator: ", ") - return "\(identifier)\(String.argsHistorySuffix).append((\(paramNamesStr)))" + return "\(overloadingResolvedName)\(String.argsHistorySuffix).append((\(paramNamesStr)))" default: fatalError("paramNames must not be empty.") } diff --git a/Sources/MockoloFramework/Models/ClosureModel.swift b/Sources/MockoloFramework/Models/ClosureModel.swift index 10c6960d..bcd4c418 100644 --- a/Sources/MockoloFramework/Models/ClosureModel.swift +++ b/Sources/MockoloFramework/Models/ClosureModel.swift @@ -17,7 +17,6 @@ import Foundation final class ClosureModel: Model { - var type: SwiftType let name: String = "" // closure type cannot have a name let offset: Int64 = .max @@ -32,28 +31,37 @@ final class ClosureModel: Model { return .closure } - init(genericTypeParams: [ParamModel], paramNames: [String], paramTypes: [SwiftType], isAsync: Bool, throwing: ThrowingKind, returnType: SwiftType, encloser: String) { + init(genericTypeParams: [ParamModel], paramNames: [String], paramTypes: [SwiftType], isAsync: Bool, throwing: ThrowingKind, returnType: SwiftType) { // In the mock's call handler, rethrows is unavailable. let throwing = throwing.coerceRethrowsToThrows self.isAsync = isAsync self.throwing = throwing - let genericTypeNameList = genericTypeParams.map(\.name) - self.genericTypeNames = genericTypeNameList + self.genericTypeNames = genericTypeParams.map(\.name) self.paramNames = paramNames self.paramTypes = paramTypes self.funcReturnType = returnType - self.type = SwiftType.toClosureType( + } + + func type(context: RenderContext) -> SwiftType { + return SwiftType.toClosureType( params: paramTypes, - typeParams: genericTypeNameList, + typeParams: genericTypeNames, isAsync: isAsync, throwing: throwing, - returnType: returnType, - encloser: encloser + returnType: funcReturnType, + encloser: context.enclosingType! ) } - - func render(with identifier: String, encloser: String, useTemplateFunc: Bool = false, useMockObservable: Bool = false, allowSetCallCount: Bool = false, mockFinal: Bool = false, enableFuncArgsHistory: Bool = false, disableCombineDefaultValues: Bool = false) -> String? { - return applyClosureTemplate(name: identifier + .handlerSuffix, + + func render( + context: RenderContext, + arguments: GenerationArguments = .default + ) -> String? { + guard let overloadingResolvedName = context.overloadingResolvedName else { + return nil + } + return applyClosureTemplate(type: type(context: context), + name: overloadingResolvedName + .handlerSuffix, paramVals: paramNames, paramTypes: paramTypes, returnDefaultType: funcReturnType) diff --git a/Sources/MockoloFramework/Models/IfMacroModel.swift b/Sources/MockoloFramework/Models/IfMacroModel.swift index b49ef9bb..75e1e55e 100644 --- a/Sources/MockoloFramework/Models/IfMacroModel.swift +++ b/Sources/MockoloFramework/Models/IfMacroModel.swift @@ -35,7 +35,15 @@ final class IfMacroModel: Model { self.offset = offset } - func render(with identifier: String, encloser: String, useTemplateFunc: Bool, useMockObservable: Bool, allowSetCallCount: Bool = false, mockFinal: Bool = false, enableFuncArgsHistory: Bool = false, disableCombineDefaultValues: Bool = false) -> String? { - return applyMacroTemplate(name: name, useTemplateFunc: useTemplateFunc, useMockObservable: useMockObservable, allowSetCallCount: allowSetCallCount, mockFinal: mockFinal, enableFuncArgsHistory: enableFuncArgsHistory, disableCombineDefaultValues: disableCombineDefaultValues, entities: entities) + func render( + context: RenderContext, + arguments: GenerationArguments + ) -> String? { + return applyMacroTemplate( + name: name, + context: context, + arguments: arguments, + entities: entities + ) } } diff --git a/Sources/MockoloFramework/Models/MethodModel.swift b/Sources/MockoloFramework/Models/MethodModel.swift index 527fad81..9f2a2bc3 100644 --- a/Sources/MockoloFramework/Models/MethodModel.swift +++ b/Sources/MockoloFramework/Models/MethodModel.swift @@ -49,7 +49,7 @@ final class MethodModel: Model { } /// This is used to uniquely identify methods with the same signature and different generic requirements - var genericWhereClauseToSignatureComponent: String { + private var genericWhereClauseToSignatureComponent: String { guard let genericWhereClause else { return "" } @@ -111,7 +111,7 @@ final class MethodModel: Model { let genericTypeNames = self.genericTypeParams.map { $0.name.capitalizeFirstLetter + $0.type.displayName } args.append(contentsOf: genericTypeNames) - if let genericWhereClause { + if genericWhereClause != nil { args.append(genericWhereClauseToSignatureComponent) } args.append(contentsOf: paramTypes.map(\.displayName)) @@ -137,7 +137,7 @@ final class MethodModel: Model { return ret }() - func handler(encloser: String) -> ClosureModel? { + func handler() -> ClosureModel? { if isInitializer { return nil } @@ -147,14 +147,13 @@ final class MethodModel: Model { paramTypes: params.map(\.type), isAsync: isAsync, throwing: throwing, - returnType: returnType, - encloser: encloser) + returnType: returnType) } init(name: String, typeName: String, kind: MethodKind, - encloserType: DeclType, + encloserType: FindTargetDeclType, acl: String, genericTypeParams: [ParamModel], genericWhereClause: String?, @@ -200,7 +199,11 @@ final class MethodModel: Model { return name(by: level - 1) + postfix } - func render(with identifier: String, encloser: String, useTemplateFunc: Bool, useMockObservable: Bool, allowSetCallCount: Bool = false, mockFinal: Bool = false, enableFuncArgsHistory: Bool, disableCombineDefaultValues: Bool = false) -> String? { + func render( + context: RenderContext, + arguments: GenerationArguments + ) -> String? { + let shouldOverride = context.annotatedTypeKind == .class if processed { var prefix = shouldOverride ? "\(String.override) " : "" @@ -216,22 +219,19 @@ final class MethodModel: Model { return nil } - let result = applyMethodTemplate(name: name, - identifier: identifier, - kind: kind, - useTemplateFunc: useTemplateFunc, - allowSetCallCount: allowSetCallCount, - enableFuncArgsHistory: enableFuncArgsHistory, - isStatic: isStatic, - customModifiers: customModifiers, - isOverride: shouldOverride, - genericTypeParams: genericTypeParams, - genericWhereClause: genericWhereClause, - params: params, - returnType: returnType, - accessLevel: accessLevel, - argsHistory: argsHistory, - handler: handler(encloser: encloser)) - return result + return applyMethodTemplate(name: name, + kind: kind, + arguments: arguments, + isStatic: isStatic, + customModifiers: customModifiers, + isOverride: shouldOverride, + genericTypeParams: genericTypeParams, + genericWhereClause: genericWhereClause, + params: params, + returnType: returnType, + accessLevel: accessLevel, + argsHistory: argsHistory, + handler: handler(), + context: context) } } diff --git a/Sources/MockoloFramework/Models/Model.swift b/Sources/MockoloFramework/Models/Model.swift index 9b5c8e13..c5d094bd 100644 --- a/Sources/MockoloFramework/Models/Model.swift +++ b/Sources/MockoloFramework/Models/Model.swift @@ -27,6 +27,18 @@ public enum ModelType { case closure } +enum NominalTypeDeclKind: String { + case `class` + case `actor` + case `protocol` +} + +struct RenderContext { + var overloadingResolvedName: String? + var enclosingType: SwiftType? + var annotatedTypeKind: NominalTypeDeclKind? +} + /// Represents a model for an entity such as var, func, class, etc. protocol Model: AnyObject { /// Identifier @@ -45,14 +57,9 @@ protocol Model: AnyObject { var offset: Int64 { get } /// Applies a corresponding template to this model to output mocks - func render(with identifier: String, - encloser: String, - useTemplateFunc: Bool, - useMockObservable: Bool, - allowSetCallCount: Bool, - mockFinal: Bool, - enableFuncArgsHistory: Bool, - disableCombineDefaultValues: Bool + func render( + context: RenderContext, + arguments: GenerationArguments ) -> String? /// Used to differentiate multiple entities with the same name diff --git a/Sources/MockoloFramework/Models/NominalModel.swift b/Sources/MockoloFramework/Models/NominalModel.swift index 58b0ec3d..b041aaa6 100644 --- a/Sources/MockoloFramework/Models/NominalModel.swift +++ b/Sources/MockoloFramework/Models/NominalModel.swift @@ -15,11 +15,6 @@ // final class NominalModel: Model { - enum NominalTypeDeclKind: String { - case `class` - case `actor` - } - let namespaces: [String] let name: String let offset: Int64 @@ -27,7 +22,7 @@ final class NominalModel: Model { let attribute: String let accessLevel: String let identifier: String - let declTypeOfMockAnnotatedBaseType: DeclType + let declKindOfMockAnnotatedBaseType: NominalTypeDeclKind let inheritedTypes: [String] let entities: [(String, Model)] let initParamCandidates: [VariableModel] @@ -42,7 +37,7 @@ final class NominalModel: Model { init(identifier: String, namespaces: [String], acl: String, - declTypeOfMockAnnotatedBaseType: DeclType, + declKindOfMockAnnotatedBaseType: NominalTypeDeclKind, declKind: NominalTypeDeclKind, inheritedTypes: [String], attributes: [String], @@ -55,7 +50,7 @@ final class NominalModel: Model { self.name = metadata?.nameOverride ?? (identifier + "Mock") self.type = SwiftType(self.name) self.namespaces = namespaces - self.declTypeOfMockAnnotatedBaseType = declTypeOfMockAnnotatedBaseType + self.declKindOfMockAnnotatedBaseType = declKindOfMockAnnotatedBaseType self.declKind = declKind self.inheritedTypes = inheritedTypes self.entities = entities @@ -68,29 +63,17 @@ final class NominalModel: Model { } func render( - with identifier: String, - encloser: String, - useTemplateFunc: Bool, - useMockObservable: Bool, - allowSetCallCount: Bool = false, - mockFinal: Bool = false, - enableFuncArgsHistory: Bool = false, - disableCombineDefaultValues: Bool = false + context: RenderContext, + arguments: GenerationArguments ) -> String? { return applyNominalTemplate( name: name, identifier: self.identifier, accessLevel: accessLevel, attribute: attribute, - declTypeOfMockAnnotatedBaseType: declTypeOfMockAnnotatedBaseType, inheritedTypes: inheritedTypes, metadata: metadata, - useTemplateFunc: useTemplateFunc, - useMockObservable: useMockObservable, - allowSetCallCount: allowSetCallCount, - mockFinal: mockFinal, - enableFuncArgsHistory: enableFuncArgsHistory, - disableCombineDefaultValues: disableCombineDefaultValues, + arguments: arguments, initParamCandidates: initParamCandidates, declaredInits: declaredInits, entities: entities diff --git a/Sources/MockoloFramework/Models/ParamModel.swift b/Sources/MockoloFramework/Models/ParamModel.swift index 51bb6bf8..bb2f5ba1 100644 --- a/Sources/MockoloFramework/Models/ParamModel.swift +++ b/Sources/MockoloFramework/Models/ParamModel.swift @@ -83,7 +83,10 @@ final class ParamModel: Model { return nil } - func render(with identifier: String, encloser: String, useTemplateFunc: Bool = false, useMockObservable: Bool = false, allowSetCallCount: Bool = false, mockFinal: Bool = false, enableFuncArgsHistory: Bool = false, disableCombineDefaultValues: Bool = false) -> String? { + func render( + context: RenderContext = .init(), + arguments: GenerationArguments = .default + ) -> String? { return applyParamTemplate(name: name, label: label, type: type, inInit: inInit) } } diff --git a/Sources/MockoloFramework/Models/ParsedEntity.swift b/Sources/MockoloFramework/Models/ParsedEntity.swift index aee5f429..2156b8ba 100644 --- a/Sources/MockoloFramework/Models/ParsedEntity.swift +++ b/Sources/MockoloFramework/Models/ParsedEntity.swift @@ -61,7 +61,7 @@ struct ResolvedEntity { return NominalModel(identifier: key, namespaces: entity.entityNode.namespaces, acl: entity.entityNode.accessLevel, - declTypeOfMockAnnotatedBaseType: entity.entityNode.declType, + declKindOfMockAnnotatedBaseType: entity.entityNode.declKind, declKind: inheritsActorProtocol ? .actor : .class, inheritedTypes: inheritedTypes, attributes: attributes, @@ -84,22 +84,17 @@ protocol EntityNode { var mayHaveGlobalActor: Bool { get } var accessLevel: String { get } var attributesDescription: String { get } - var declType: DeclType { get } + var declKind: NominalTypeDeclKind { get } var inheritedTypes: [String] { get } var offset: Int64 { get } var hasBlankInit: Bool { get } - func subContainer(metadata: AnnotationMetadata?, declType: DeclType, path: String?, isProcessed: Bool) -> EntityNodeSubContainer + func subContainer(metadata: AnnotationMetadata?, declType: FindTargetDeclType, path: String?, isProcessed: Bool) -> EntityNodeSubContainer } -final class EntityNodeSubContainer { - let attributes: [String] - let members: [Model] - let hasInit: Bool - init(attributes: [String], members: [Model], hasInit: Bool) { - self.attributes = attributes - self.members = members - self.hasInit = hasInit - } +struct EntityNodeSubContainer { + var attributes: [String] + var members: [Model] + var hasInit: Bool } public enum CombineType { @@ -131,6 +126,23 @@ struct AnnotationMetadata { var combineTypes: [String: CombineType]? } +struct GenerationArguments { + var useTemplateFunc: Bool + var useMockObservable: Bool + var allowSetCallCount: Bool + var mockFinal: Bool + var enableFuncArgsHistory: Bool + var disableCombineDefaultValues: Bool + static let `default` = GenerationArguments( + useTemplateFunc: false, + useMockObservable: false, + allowSetCallCount: false, + mockFinal: false, + enableFuncArgsHistory: false, + disableCombineDefaultValues: false + ) +} + public typealias ImportMap = [String: [String: [String]]] /// Metadata for a type being mocked diff --git a/Sources/MockoloFramework/Models/TypeAliasModel.swift b/Sources/MockoloFramework/Models/TypeAliasModel.swift index f55e069e..30965980 100644 --- a/Sources/MockoloFramework/Models/TypeAliasModel.swift +++ b/Sources/MockoloFramework/Models/TypeAliasModel.swift @@ -32,7 +32,7 @@ final class TypeAliasModel: Model { return .typeAlias } - init(name: String, typeName: String, acl: String?, encloserType: DeclType, overrideTypes: [String: String]?, offset: Int64, length: Int64, modelDescription: String?, useDescription: Bool = false, processed: Bool) { + init(name: String, typeName: String, acl: String?, encloserType: FindTargetDeclType, overrideTypes: [String: String]?, offset: Int64, length: Int64, modelDescription: String?, useDescription: Bool = false, processed: Bool) { self.name = name self.accessLevel = acl ?? "" self.offset = offset @@ -58,7 +58,10 @@ final class TypeAliasModel: Model { return fullName } - func render(with identifier: String, encloser: String, useTemplateFunc: Bool = false, useMockObservable: Bool = false, allowSetCallCount: Bool = false, mockFinal: Bool = false, enableFuncArgsHistory: Bool = false, disableCombineDefaultValues: Bool = false) -> String? { + func render( + context: RenderContext, + arguments: GenerationArguments + ) -> String? { if processed || useDescription, let modelDescription = modelDescription?.trimmingCharacters(in: .whitespacesAndNewlines) { if addAcl { return "\(1.tab)\(accessLevel) \(modelDescription)" diff --git a/Sources/MockoloFramework/Models/VariableModel.swift b/Sources/MockoloFramework/Models/VariableModel.swift index 410a111b..fe440b7a 100644 --- a/Sources/MockoloFramework/Models/VariableModel.swift +++ b/Sources/MockoloFramework/Models/VariableModel.swift @@ -17,7 +17,7 @@ final class VariableModel: Model { let offset: Int64 let accessLevel: String let attributes: [String]? - let encloserType: DeclType + let encloserType: FindTargetDeclType /// Indicates whether this model can be used as a parameter to an initializer let canBeInitParam: Bool let processed: Bool @@ -50,7 +50,7 @@ final class VariableModel: Model { init(name: String, type: SwiftType, acl: String?, - encloserType: DeclType, + encloserType: FindTargetDeclType, isStatic: Bool, storageKind: MockStorageKind, canBeInitParam: Bool, @@ -77,7 +77,13 @@ final class VariableModel: Model { self.combineType = combineType } - func render(with identifier: String, encloser: String, useTemplateFunc: Bool = false, useMockObservable: Bool = false, allowSetCallCount: Bool = false, mockFinal: Bool = false, enableFuncArgsHistory: Bool = false, disableCombineDefaultValues: Bool = false) -> String? { + func render( + context: RenderContext, + arguments: GenerationArguments + ) -> String? { + guard let enclosingType = context.enclosingType else { + return nil + } if processed { guard let modelDescription = modelDescription?.trimmingCharacters(in: .newlines), !modelDescription.isEmpty else { return nil @@ -94,36 +100,37 @@ final class VariableModel: Model { return prefix + modelDescription } - if !disableCombineDefaultValues { - if let combineVar = applyCombineVariableTemplate(name: identifier, - type: type, - encloser: encloser, - shouldOverride: shouldOverride, - isStatic: isStatic, - accessLevel: accessLevel) { + if !arguments.disableCombineDefaultValues { + if let combineVar = applyCombineVariableTemplate(name: name, + type: type, + encloser: enclosingType.typeName, + shouldOverride: shouldOverride, + isStatic: isStatic, + accessLevel: accessLevel) { return combineVar } } - if let rxVar = applyRxVariableTemplate(name: identifier, + if let rxVar = applyRxVariableTemplate(name: name, type: type, - encloser: encloser, + encloser: enclosingType.typeName, rxTypes: rxTypes, shouldOverride: shouldOverride, - useMockObservable: useMockObservable, - allowSetCallCount: allowSetCallCount, + useMockObservable: arguments.useMockObservable, + allowSetCallCount: arguments.allowSetCallCount, isStatic: isStatic, accessLevel: accessLevel) { return rxVar } - return applyVariableTemplate(name: identifier, + return applyVariableTemplate(name: name, type: type, - encloser: encloser, + encloser: enclosingType.typeName, isStatic: isStatic, customModifiers: customModifiers, - allowSetCallCount: allowSetCallCount, + allowSetCallCount: arguments.allowSetCallCount, shouldOverride: shouldOverride, - accessLevel: accessLevel) + accessLevel: accessLevel, + context: context) } } diff --git a/Sources/MockoloFramework/Operations/Generator.swift b/Sources/MockoloFramework/Operations/Generator.swift index fa4c67b3..fb7d35d0 100644 --- a/Sources/MockoloFramework/Operations/Generator.swift +++ b/Sources/MockoloFramework/Operations/Generator.swift @@ -31,7 +31,7 @@ public func generate(sourceDirs: [String], annotation: String, header: String?, macro: String?, - declType: DeclType, + declType: FindTargetDeclType, useTemplateFunc: Bool, useMockObservable: Bool, allowSetCallCount: Bool, @@ -137,13 +137,16 @@ public func generate(sourceDirs: [String], signpost_begin(name: "Render models") log("Render models with templates...", level: .info) - renderTemplates(entities: resolvedEntities, - useTemplateFunc: useTemplateFunc, - useMockObservable: useMockObservable, - allowSetCallCount: allowSetCallCount, - mockFinal: mockFinal, - enableFuncArgsHistory: enableFuncArgsHistory, - disableCombineDefaultValues: disableCombineDefaultValues + renderTemplates( + entities: resolvedEntities, + arguments: .init( + useTemplateFunc: useTemplateFunc, + useMockObservable: useMockObservable, + allowSetCallCount: allowSetCallCount, + mockFinal: mockFinal, + enableFuncArgsHistory: enableFuncArgsHistory, + disableCombineDefaultValues: disableCombineDefaultValues + ) ) { (mockString: String, offset: Int64) in candidates.append((mockString, offset)) } diff --git a/Sources/MockoloFramework/Operations/TemplateRenderer.swift b/Sources/MockoloFramework/Operations/TemplateRenderer.swift index 61642425..9791981e 100644 --- a/Sources/MockoloFramework/Operations/TemplateRenderer.swift +++ b/Sources/MockoloFramework/Operations/TemplateRenderer.swift @@ -19,20 +19,17 @@ import Foundation /// Renders models with templates for output func renderTemplates(entities: [ResolvedEntity], - useTemplateFunc: Bool, - useMockObservable: Bool, - allowSetCallCount: Bool, - mockFinal: Bool, - enableFuncArgsHistory: Bool, - disableCombineDefaultValues: Bool, + arguments: GenerationArguments, completion: @escaping (String, Int64) -> ()) { scan(entities) { (resolvedEntity, lock) in let mockModel = resolvedEntity.model() - if let mockString = mockModel.render(with: resolvedEntity.key, encloser: mockModel.name, useTemplateFunc: useTemplateFunc, useMockObservable: useMockObservable, allowSetCallCount: allowSetCallCount, mockFinal: mockFinal, enableFuncArgsHistory: enableFuncArgsHistory, disableCombineDefaultValues: disableCombineDefaultValues), !mockString.isEmpty { + if let mockString = mockModel.render( + context: .init(), + arguments: arguments + ), !mockString.isEmpty { lock?.lock() completion(mockString, mockModel.offset) lock?.unlock() } } } - diff --git a/Sources/MockoloFramework/Operations/UniqueModelGenerator.swift b/Sources/MockoloFramework/Operations/UniqueModelGenerator.swift index 78a53ca6..d423c679 100644 --- a/Sources/MockoloFramework/Operations/UniqueModelGenerator.swift +++ b/Sources/MockoloFramework/Operations/UniqueModelGenerator.swift @@ -34,7 +34,17 @@ private func generateUniqueModels(key: String, entity: Entity, protocolMap: [String: Entity], inheritanceMap: [String: Entity]) -> ResolvedEntityContainer { - let (models, processedModels, attributes, inheritedTypes, paths) = lookupEntities(key: key, declType: entity.entityNode.declType, protocolMap: protocolMap, inheritanceMap: inheritanceMap) + let declType: FindTargetDeclType = { + switch entity.entityNode.declKind { + case .class: + return .classType + case .actor: + return .other + case .protocol: + return .protocolType + } + }() + let (models, processedModels, attributes, inheritedTypes, paths) = lookupEntities(key: key, declType: declType, protocolMap: protocolMap, inheritanceMap: inheritanceMap) let processedFullNames = processedModels.compactMap {$0.fullName} @@ -66,6 +76,7 @@ private func generateUniqueModels(key: String, let mockedUniqueEntities = Dictionary(uniqueKeysWithValues: processedElementsMap) let uniqueModels = [mockedUniqueEntities, unmockedUniqueEntities].flatMap {$0} + .sorted(path: \.value.offset, fallback: \.key) var mockInheritedTypes = [String]() if inheritedTypes.contains(.sendable) { diff --git a/Sources/MockoloFramework/Parsers/SourceParser.swift b/Sources/MockoloFramework/Parsers/SourceParser.swift index de3b2c59..87246387 100644 --- a/Sources/MockoloFramework/Parsers/SourceParser.swift +++ b/Sources/MockoloFramework/Parsers/SourceParser.swift @@ -18,7 +18,7 @@ import Foundation import SwiftSyntax import SwiftParser -public enum DeclType { +public enum FindTargetDeclType { case protocolType, classType, other, all } @@ -48,7 +48,7 @@ public class SourceParser { exclusionSuffixes: [String], annotation: String, fileMacro: String?, - declType: DeclType, + declType: FindTargetDeclType, completion: @escaping ([Entity], ImportMap?) -> ()) { guard !paths.isEmpty else { return } @@ -67,7 +67,7 @@ public class SourceParser { exclusionSuffixes: [String] = [], annotation: String, fileMacro: String?, - declType: DeclType, + declType: FindTargetDeclType, lock: NSLock?, completion: @escaping ([Entity], ImportMap?) -> ()) { diff --git a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift index e1f7e928..21c04460 100644 --- a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift +++ b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift @@ -123,7 +123,7 @@ extension InheritanceClauseSyntax { } extension MemberBlockItemSyntax { - private func validateMember(_ modifiers: DeclModifierListSyntax?, _ declType: DeclType, processed: Bool) -> Bool { + private func validateMember(_ modifiers: DeclModifierListSyntax?, _ declType: FindTargetDeclType, processed: Bool) -> Bool { if let mods = modifiers { if !processed && mods.isPrivate || mods.isStatic && declType == .classType { return false @@ -132,7 +132,7 @@ extension MemberBlockItemSyntax { return true } - private func validateInit(_ initDecl: InitializerDeclSyntax, _ declType: DeclType, processed: Bool) -> Bool { + private func validateInit(_ initDecl: InitializerDeclSyntax, _ declType: FindTargetDeclType, processed: Bool) -> Bool { let modifiers = initDecl.modifiers let isRequired = modifiers.isRequired if processed { @@ -147,14 +147,14 @@ extension MemberBlockItemSyntax { return true } - private func memberAcl(_ modifiers: DeclModifierListSyntax?, _ encloserAcl: String, _ declType: DeclType) -> String { + private func memberAcl(_ modifiers: DeclModifierListSyntax?, _ encloserAcl: String, _ declType: FindTargetDeclType) -> String { if declType == .protocolType { return encloserAcl } return modifiers?.acl ?? "" } - func transformToModel(with encloserAcl: String, declType: DeclType, metadata: AnnotationMetadata?, processed: Bool) -> (Model, String?, Bool)? { + func transformToModel(with encloserAcl: String, declType: FindTargetDeclType, metadata: AnnotationMetadata?, processed: Bool) -> (Model, String?, Bool)? { if let varMember = self.decl.as(VariableDeclSyntax.self) { if validateMember(varMember.modifiers, declType, processed: processed) { let acl = memberAcl(varMember.modifiers, encloserAcl, declType) @@ -213,7 +213,7 @@ extension MemberBlockItemListSyntax { return false } - func memberData(with encloserAcl: String, declType: DeclType, metadata: AnnotationMetadata?, processed: Bool) -> EntityNodeSubContainer { + func memberData(with encloserAcl: String, declType: FindTargetDeclType, metadata: AnnotationMetadata?, processed: Bool) -> EntityNodeSubContainer { var attributeList = [String]() var memberList = [Model]() var hasInit = false @@ -232,7 +232,7 @@ extension MemberBlockItemListSyntax { } extension IfConfigDeclSyntax { - func model(with encloserAcl: String, declType: DeclType, metadata: AnnotationMetadata?, processed: Bool) -> (Model, String?, Bool) { + func model(with encloserAcl: String, declType: FindTargetDeclType, metadata: AnnotationMetadata?, processed: Bool) -> (Model, String?, Bool) { var subModels = [Model]() var attrDesc: String? var hasInit = false @@ -277,8 +277,8 @@ extension ProtocolDeclSyntax: EntityNode { return self.modifiers.acl } - var declType: DeclType { - return .protocolType + var declKind: NominalTypeDeclKind { + return .protocol } var isPrivate: Bool { @@ -301,7 +301,7 @@ extension ProtocolDeclSyntax: EntityNode { return false } - func subContainer(metadata: AnnotationMetadata?, declType: DeclType, path: String?, isProcessed: Bool) -> EntityNodeSubContainer { + func subContainer(metadata: AnnotationMetadata?, declType: FindTargetDeclType, path: String?, isProcessed: Bool) -> EntityNodeSubContainer { return self.memberBlock.members.memberData(with: accessLevel, declType: declType, metadata: metadata, processed: isProcessed) } } @@ -323,8 +323,8 @@ extension ClassDeclSyntax: EntityNode { return self.modifiers.acl } - var declType: DeclType { - return .classType + var declKind: NominalTypeDeclKind { + return .class } var inheritedTypes: [String] { @@ -355,7 +355,7 @@ extension ClassDeclSyntax: EntityNode { return leadingTrivia.annotationMetadata(with: annotation) } - func subContainer(metadata: AnnotationMetadata?, declType: DeclType, path: String?, isProcessed: Bool) -> EntityNodeSubContainer { + func subContainer(metadata: AnnotationMetadata?, declType: FindTargetDeclType, path: String?, isProcessed: Bool) -> EntityNodeSubContainer { return self.memberBlock.members.memberData(with: accessLevel, declType: declType, metadata: nil, processed: isProcessed) } } @@ -403,7 +403,7 @@ extension AttributeListSyntax { } extension VariableDeclSyntax { - func models(with acl: String, declType: DeclType, metadata: AnnotationMetadata?, processed: Bool) -> [Model] { + func models(with acl: String, declType: FindTargetDeclType, metadata: AnnotationMetadata?, processed: Bool) -> [Model] { // Detect whether it's static let isStatic = self.modifiers.isStatic @@ -470,7 +470,7 @@ extension VariableDeclSyntax { } extension SubscriptDeclSyntax { - func model(with acl: String, declType: DeclType, processed: Bool) -> Model { + func model(with acl: String, declType: FindTargetDeclType, processed: Bool) -> Model { let isStatic = self.modifiers.isStatic let params = self.parameterClause.parameters.compactMap { $0.model(inInit: false, declType: declType) } @@ -500,7 +500,7 @@ extension SubscriptDeclSyntax { extension FunctionDeclSyntax { - func model(with acl: String, declType: DeclType, funcsWithArgsHistory: [String]?, customModifiers: [String : Modifier]?, processed: Bool) -> Model { + func model(with acl: String, declType: FindTargetDeclType, funcsWithArgsHistory: [String]?, customModifiers: [String : Modifier]?, processed: Bool) -> Model { let isStatic = self.modifiers.isStatic let params = self.signature.parameterClause.parameters.compactMap { $0.model(inInit: false, declType: declType) } @@ -529,7 +529,7 @@ extension FunctionDeclSyntax { } extension InitializerDeclSyntax { - func isRequired(with declType: DeclType) -> Bool { + func isRequired(with declType: FindTargetDeclType) -> Bool { if declType == .protocolType { return true } else if declType == .classType { @@ -541,7 +541,7 @@ extension InitializerDeclSyntax { return false } - func model(with acl: String, declType: DeclType, processed: Bool) -> Model { + func model(with acl: String, declType: FindTargetDeclType, processed: Bool) -> Model { let requiredInit = isRequired(with: declType) let params = self.signature.parameterClause.parameters.compactMap { $0.model(inInit: true, declType: declType) } @@ -584,7 +584,7 @@ extension GenericParameterSyntax { } extension FunctionParameterSyntax { - func model(inInit: Bool, declType: DeclType) -> ParamModel { + func model(inInit: Bool, declType: FindTargetDeclType) -> ParamModel { var label = "" var name = "" // Get label and name of args @@ -619,7 +619,7 @@ extension FunctionParameterSyntax { } extension AssociatedTypeDeclSyntax { - func model(with acl: String, declType: DeclType, overrides: [String: String]?, processed: Bool) -> Model { + func model(with acl: String, declType: FindTargetDeclType, overrides: [String: String]?, processed: Bool) -> Model { // Get the inhertied type for an associated type if any var t = self.inheritanceClause?.typesDescription ?? "" t.append(self.genericWhereClause?.description ?? "") @@ -637,7 +637,7 @@ extension AssociatedTypeDeclSyntax { } extension TypeAliasDeclSyntax { - func model(with acl: String, declType: DeclType, overrides: [String: String]?, processed: Bool) -> Model { + func model(with acl: String, declType: FindTargetDeclType, overrides: [String: String]?, processed: Bool) -> Model { return TypeAliasModel(name: self.name.text, typeName: self.initializer.value.description, acl: acl, @@ -657,8 +657,8 @@ final class EntityVisitor: SyntaxVisitor { let annotation: String let fileMacro: String let path: String - let declType: DeclType - init(_ path: String, annotation: String = "", fileMacro: String?, declType: DeclType) { + let declType: FindTargetDeclType + init(_ path: String, annotation: String = "", fileMacro: String?, declType: FindTargetDeclType) { self.annotation = annotation self.fileMacro = fileMacro ?? "" self.path = path diff --git a/Sources/MockoloFramework/Templates/ClosureTemplate.swift b/Sources/MockoloFramework/Templates/ClosureTemplate.swift index 820e8152..019fc861 100644 --- a/Sources/MockoloFramework/Templates/ClosureTemplate.swift +++ b/Sources/MockoloFramework/Templates/ClosureTemplate.swift @@ -17,7 +17,8 @@ import Foundation extension ClosureModel { - func applyClosureTemplate(name: String, + func applyClosureTemplate(type: SwiftType, + name: String, paramVals: [String]?, paramTypes: [SwiftType]?, returnDefaultType: SwiftType) -> String { diff --git a/Sources/MockoloFramework/Templates/IfMacroTemplate.swift b/Sources/MockoloFramework/Templates/IfMacroTemplate.swift index ccb18908..728beef5 100644 --- a/Sources/MockoloFramework/Templates/IfMacroTemplate.swift +++ b/Sources/MockoloFramework/Templates/IfMacroTemplate.swift @@ -18,15 +18,20 @@ import Foundation extension IfMacroModel { func applyMacroTemplate(name: String, - useTemplateFunc: Bool, - useMockObservable: Bool, - allowSetCallCount: Bool, - mockFinal: Bool, - enableFuncArgsHistory: Bool, - disableCombineDefaultValues: Bool, + context: RenderContext, + arguments: GenerationArguments, entities: [Model]) -> String { let rendered = entities - .compactMap {$0.render(with: $0.name, encloser: "", useTemplateFunc: useTemplateFunc, useMockObservable: useMockObservable, allowSetCallCount: allowSetCallCount, mockFinal: mockFinal, enableFuncArgsHistory: enableFuncArgsHistory, disableCombineDefaultValues: disableCombineDefaultValues) } + .compactMap { model in + model.render( + context: .init( + overloadingResolvedName: model.name, // FIXME: the name is not resolving overload + enclosingType: context.enclosingType, + annotatedTypeKind: context.annotatedTypeKind + ), + arguments: arguments + ) + } .joined(separator: "\n") let template = """ diff --git a/Sources/MockoloFramework/Templates/MethodTemplate.swift b/Sources/MockoloFramework/Templates/MethodTemplate.swift index 8b628877..05c512e3 100644 --- a/Sources/MockoloFramework/Templates/MethodTemplate.swift +++ b/Sources/MockoloFramework/Templates/MethodTemplate.swift @@ -18,11 +18,8 @@ import Foundation extension MethodModel { func applyMethodTemplate(name: String, - identifier: String, kind: MethodKind, - useTemplateFunc: Bool, - allowSetCallCount: Bool, - enableFuncArgsHistory: Bool, + arguments: GenerationArguments, isStatic: Bool, customModifiers: [String: Modifier]?, isOverride: Bool, @@ -32,28 +29,32 @@ extension MethodModel { returnType: SwiftType, accessLevel: String, argsHistory: ArgumentsHistoryModel?, - handler: ClosureModel?) -> String { + handler: ClosureModel?, + context: RenderContext) -> String { + guard let overloadingResolvedName = context.overloadingResolvedName else { + preconditionFailure("context broken") + } var template = "" let returnTypeName = returnType.isUnknown ? "" : returnType.typeName let acl = accessLevel.isEmpty ? "" : accessLevel+" " - let genericTypeDeclsStr = genericTypeParams.compactMap {$0.render(with: "", encloser: "")}.joined(separator: ", ") + let genericTypeDeclsStr = genericTypeParams.compactMap {$0.render()}.joined(separator: ", ") let genericTypesStr = genericTypeDeclsStr.isEmpty ? "" : "<\(genericTypeDeclsStr)>" let genericWhereStr = genericWhereClause.map { "\($0) " } ?? "" - let paramDeclsStr = params.compactMap{$0.render(with: "", encloser: "")}.joined(separator: ", ") + let paramDeclsStr = params.compactMap{$0.render()}.joined(separator: ", ") switch kind { case .initKind(_, _): // ClassTemplate needs to handle this as it needs a context of all the vars return "" default: - guard let handler = handler else { return "" } + guard let handler else { return "" } - let callCount = "\(identifier)\(String.callCountSuffix)" - let handlerVarName = "\(identifier)\(String.handlerSuffix)" - let handlerVarType = handler.type.typeName // ?? "Any" - let handlerReturn = handler.render(with: identifier, encloser: "") ?? "" + let callCount = "\(overloadingResolvedName)\(String.callCountSuffix)" + let handlerVarName = "\(overloadingResolvedName)\(String.handlerSuffix)" + let handlerVarType = handler.type(context: context).typeName // ?? "Any" + let handlerReturn = handler.render(context: context) ?? "" let suffixStr = applyFunctionSuffixTemplate( isAsync: isAsync, @@ -64,8 +65,8 @@ extension MethodModel { let keyword = isSubscript ? "" : "func " var body = "" - if useTemplateFunc { - let callMockFunc = !throwing.hasError && (handler.type.cast?.isEmpty ?? false) + if arguments.useTemplateFunc { + let callMockFunc = !throwing.hasError && (handler.type(context: context).cast?.isEmpty ?? false) if callMockFunc { let handlerParamValsStr = params.map { (arg) -> String in if arg.type.typeName.hasPrefix(String.autoclosure) { @@ -94,8 +95,8 @@ extension MethodModel { \(2.tab)\(callCount) += 1 """ - if let argsHistory = argsHistory, argsHistory.enable(force: enableFuncArgsHistory) { - let argsHistoryCapture = argsHistory.render(with: identifier, encloser: "", enableFuncArgsHistory: enableFuncArgsHistory) ?? "" + if let argsHistory, argsHistory.enable(force: arguments.enableFuncArgsHistory) { + let argsHistoryCapture = argsHistory.render(context: context, arguments: arguments) ?? "" body = """ \(body) @@ -127,15 +128,15 @@ extension MethodModel { } else { modifierTypeStr = "" } - let privateSetSpace = allowSetCallCount ? "" : "\(String.privateSet) " + let privateSetSpace = arguments.allowSetCallCount ? "" : "\(String.privateSet) " template = """ \(1.tab)\(acl)\(staticStr)\(privateSetSpace)var \(callCount) = 0 """ - if let argsHistory = argsHistory, argsHistory.enable(force: enableFuncArgsHistory) { - let argsHistoryVarName = "\(identifier)\(String.argsHistorySuffix)" + if let argsHistory = argsHistory, argsHistory.enable(force: arguments.enableFuncArgsHistory) { + let argsHistoryVarName = "\(overloadingResolvedName)\(String.argsHistorySuffix)" let argsHistoryVarType = argsHistory.type.typeName template = """ @@ -144,7 +145,7 @@ extension MethodModel { """ } - template = """ + return """ \(template) \(1.tab)\(acl)\(staticStr)var \(handlerVarName): \(handlerVarType) \(1.tab)\(acl)\(staticStr)\(overrideStr)\(modifierTypeStr)\(keyword)\(name)\(genericTypesStr)(\(paramDeclsStr)) \(suffixStr)\(returnStr)\(genericWhereStr){ @@ -152,7 +153,5 @@ extension MethodModel { \(1.tab)} """ } - - return template } } diff --git a/Sources/MockoloFramework/Templates/NominalTemplate.swift b/Sources/MockoloFramework/Templates/NominalTemplate.swift index b9e874da..4cddf268 100644 --- a/Sources/MockoloFramework/Templates/NominalTemplate.swift +++ b/Sources/MockoloFramework/Templates/NominalTemplate.swift @@ -21,15 +21,9 @@ extension NominalModel { identifier: String, accessLevel: String, attribute: String, - declTypeOfMockAnnotatedBaseType: DeclType, inheritedTypes: [String], metadata: AnnotationMetadata?, - useTemplateFunc: Bool, - useMockObservable: Bool, - allowSetCallCount: Bool, - mockFinal: Bool, - enableFuncArgsHistory: Bool, - disableCombineDefaultValues: Bool, + arguments: GenerationArguments, initParamCandidates: [VariableModel], declaredInits: [MethodModel], entities: [(String, Model)]) -> String { @@ -39,7 +33,7 @@ extension NominalModel { let acl = accessLevel.isEmpty ? "" : accessLevel + " " let typealiases = typealiasWhitelist(in: entities) let renderedEntities = entities - .compactMap { (uniqueId: String, model: Model) -> (String, Int64)? in + .compactMap { (uniqueId: String, model: Model) -> String? in if model.modelType == .typeAlias, let _ = typealiases?[model.name] { // this case will be handlded by typealiasWhitelist look up later return nil @@ -50,22 +44,22 @@ extension NominalModel { if model.modelType == .method, let model = model as? MethodModel, model.isInitializer, !model.processed { return nil } - if let ret = model.render(with: uniqueId, encloser: name, useTemplateFunc: useTemplateFunc, useMockObservable: useMockObservable, allowSetCallCount: allowSetCallCount, mockFinal: mockFinal, enableFuncArgsHistory: enableFuncArgsHistory, disableCombineDefaultValues: disableCombineDefaultValues) { - return (ret, model.offset) + if let ret = model.render( + context: .init( + overloadingResolvedName: uniqueId, + enclosingType: type, + annotatedTypeKind: declKindOfMockAnnotatedBaseType + ), + arguments: arguments + ) { + return ret } return nil - } - .sorted { (left: (String, Int64), right: (String, Int64)) -> Bool in - if left.1 == right.1 { - return left.0 < right.0 } - return left.1 < right.1 - } - .map {$0.0} - .joined(separator: "\n") + .joined(separator: "\n") var typealiasTemplate = "" - let addAcl = declTypeOfMockAnnotatedBaseType == .protocolType ? acl : "" + let addAcl = declKindOfMockAnnotatedBaseType == .protocol ? acl : "" if let typealiasWhitelist = typealiases { typealiasTemplate = typealiasWhitelist.map { (arg: (key: String, value: [String])) -> String in let joinedType = arg.value.sorted().joined(separator: " & ") @@ -78,7 +72,7 @@ extension NominalModel { moduleDot = moduleName + "." } - let extraInits = extraInitsIfNeeded(initParamCandidates: initParamCandidates, declaredInits: declaredInits, acl: acl, declTypeOfMockAnnotatedBaseType: declTypeOfMockAnnotatedBaseType, overrides: metadata?.varTypes) + let extraInits = extraInitsIfNeeded(initParamCandidates: initParamCandidates, declaredInits: declaredInits, acl: acl, declKindOfMockAnnotatedBaseType: declKindOfMockAnnotatedBaseType, overrides: metadata?.varTypes) var inheritedTypes = inheritedTypes inheritedTypes.insert("\(moduleDot)\(identifier)", at: 0) @@ -94,7 +88,7 @@ extension NominalModel { body += "\(renderedEntities)" } - let finalStr = mockFinal ? "\(String.final) " : "" + let finalStr = arguments.mockFinal ? "\(String.final) " : "" let template = """ \(attribute) \(acl)\(finalStr)\(declKind.rawValue) \(name): \(inheritedTypes.joined(separator: ", ")) { @@ -117,7 +111,7 @@ extension NominalModel { initParamCandidates: [VariableModel], declaredInits: [MethodModel], acl: String, - declTypeOfMockAnnotatedBaseType: DeclType, + declKindOfMockAnnotatedBaseType: NominalTypeDeclKind, overrides: [String: String]? ) -> String { @@ -130,7 +124,7 @@ extension NominalModel { needBlankInit = true needParamedInit = false } else { - if declTypeOfMockAnnotatedBaseType == .protocolType { + if declKindOfMockAnnotatedBaseType == .protocol { needParamedInit = !initParamCandidates.isEmpty needBlankInit = true @@ -203,9 +197,9 @@ extension NominalModel { if case let .initKind(required, override) = m.kind, !m.processed { let modifier = required ? "\(String.required) " : (override ? "\(String.override) " : "") let mAcl = m.accessLevel.isEmpty ? "" : "\(m.accessLevel) " - let genericTypeDeclsStr = m.genericTypeParams.compactMap {$0.render(with: "", encloser: "")}.joined(separator: ", ") + let genericTypeDeclsStr = m.genericTypeParams.compactMap {$0.render()}.joined(separator: ", ") let genericTypesStr = genericTypeDeclsStr.isEmpty ? "" : "<\(genericTypeDeclsStr)>" - let paramDeclsStr = m.params.compactMap{$0.render(with: "", encloser: "")}.joined(separator: ", ") + let paramDeclsStr = m.params.compactMap{$0.render()}.joined(separator: ", ") let suffixStr = applyFunctionSuffixTemplate( isAsync: m.isAsync, throwing: m.throwing diff --git a/Sources/MockoloFramework/Templates/VariableTemplate.swift b/Sources/MockoloFramework/Templates/VariableTemplate.swift index 4ab33225..fce353d3 100644 --- a/Sources/MockoloFramework/Templates/VariableTemplate.swift +++ b/Sources/MockoloFramework/Templates/VariableTemplate.swift @@ -25,7 +25,8 @@ extension VariableModel { customModifiers: [String: Modifier]?, allowSetCallCount: Bool, shouldOverride: Bool, - accessLevel: String) -> String { + accessLevel: String, + context: RenderContext) -> String { let underlyingSetCallCount = "\(name)\(String.setCallCountSuffix)" let underlyingVarDefaultVal = type.defaultVal() @@ -112,9 +113,12 @@ extension VariableModel { paramTypes: [], isAsync: effects.isAsync, throwing: effects.throwing, - returnType: type, - encloser: "" - ).render(with: name, encloser: "") ?? "") + returnType: type + ).render(context: .init( + overloadingResolvedName: name, // var cannot overload. this is ok + enclosingType: context.enclosingType, + annotatedTypeKind: context.annotatedTypeKind + )) ?? "") .addingIndent(1) return """ diff --git a/Sources/MockoloFramework/Utils/InheritanceResolver.swift b/Sources/MockoloFramework/Utils/InheritanceResolver.swift index 0692495e..febcf6fe 100644 --- a/Sources/MockoloFramework/Utils/InheritanceResolver.swift +++ b/Sources/MockoloFramework/Utils/InheritanceResolver.swift @@ -25,7 +25,7 @@ import Algorithms /// @returns a list of models representing sub-entities of the current entity, a list of models processed in dependent mock files if exists, /// cumulated attributes, cumulated inherited types, and a map of filepaths and file contents (used for import lines lookup later). func lookupEntities(key: String, - declType: DeclType, + declType: FindTargetDeclType, protocolMap: [String: Entity], inheritanceMap: [String: Entity]) -> ([Model], [Model], [String], Set, [String]) { diff --git a/Sources/MockoloFramework/Utils/TypeParser.swift b/Sources/MockoloFramework/Utils/TypeParser.swift index 61277529..279ad3d7 100644 --- a/Sources/MockoloFramework/Utils/TypeParser.swift +++ b/Sources/MockoloFramework/Utils/TypeParser.swift @@ -518,7 +518,7 @@ public final class SwiftType { isAsync: Bool, throwing: ThrowingKind, returnType: SwiftType, - encloser: String + encloser: SwiftType ) -> SwiftType { let displayableParamTypes = params.map { (subtype: SwiftType) -> String in return subtype.processTypeParams(with: typeParams) @@ -553,7 +553,7 @@ public final class SwiftType { } if returnType.isSelf { - displayableReturnType = encloser + displayableReturnType = encloser.typeName returnTypeCast = " as! " + String.`Self` } diff --git a/Tests/MockoloTestCase.swift b/Tests/MockoloTestCase.swift index 1b2b69d1..4eafbad8 100644 --- a/Tests/MockoloTestCase.swift +++ b/Tests/MockoloTestCase.swift @@ -54,7 +54,7 @@ class MockoloTestCase: XCTestCase { } } - func verify(srcContent: String, mockContent: String? = nil, dstContent: String, header: String = "", declType: DeclType = .protocolType, useTemplateFunc: Bool = false, useMockObservable: Bool = false, testableImports: [String] = [], allowSetCallCount: Bool = false, mockFinal: Bool = false, enableFuncArgsHistory: Bool = false, dstFilePath: String? = nil, concurrencyLimit: Int? = 1, disableCombineDefaultValues: Bool = false) { + func verify(srcContent: String, mockContent: String? = nil, dstContent: String, header: String = "", declType: FindTargetDeclType = .protocolType, useTemplateFunc: Bool = false, useMockObservable: Bool = false, testableImports: [String] = [], allowSetCallCount: Bool = false, mockFinal: Bool = false, enableFuncArgsHistory: Bool = false, dstFilePath: String? = nil, concurrencyLimit: Int? = 1, disableCombineDefaultValues: Bool = false) { let dstFilePath = dstFilePath ?? defaultDstFilePath var mockList: [String]? if let mock = mockContent { @@ -66,7 +66,7 @@ class MockoloTestCase: XCTestCase { try? verify(srcContents: [srcContent], mockContents: mockList, dstContent: dstContent, header: header, declType: declType, useTemplateFunc: useTemplateFunc, useMockObservable: useMockObservable, testableImports: testableImports, allowSetCallCount: allowSetCallCount, mockFinal: mockFinal, enableFuncArgsHistory: enableFuncArgsHistory, dstFilePath: dstFilePath, concurrencyLimit: concurrencyLimit, disableCombineDefaultValues: disableCombineDefaultValues) } - func verifyThrows(srcContent: String, mockContent: String? = nil, dstContent: String, header: String = "", declType: DeclType = .protocolType, useTemplateFunc: Bool = false, useMockObservable: Bool = false, testableImports: [String] = [], allowSetCallCount: Bool = false, mockFinal: Bool = false, enableFuncArgsHistory: Bool = false, dstFilePath: String? = nil, concurrencyLimit: Int? = 1, disableCombineDefaultValues: Bool = false, errorHandler: (Error) -> Void = { _ in }) { + func verifyThrows(srcContent: String, mockContent: String? = nil, dstContent: String, header: String = "", declType: FindTargetDeclType = .protocolType, useTemplateFunc: Bool = false, useMockObservable: Bool = false, testableImports: [String] = [], allowSetCallCount: Bool = false, mockFinal: Bool = false, enableFuncArgsHistory: Bool = false, dstFilePath: String? = nil, concurrencyLimit: Int? = 1, disableCombineDefaultValues: Bool = false, errorHandler: (Error) -> Void = { _ in }) { let dstFilePath = dstFilePath ?? defaultDstFilePath var mockList: [String]? if let mock = mockContent { @@ -82,7 +82,7 @@ class MockoloTestCase: XCTestCase { ) } - func verify(srcContents: [String], mockContents: [String]?, dstContent: String, header: String, declType: DeclType, useTemplateFunc: Bool, useMockObservable: Bool, testableImports: [String] = [], allowSetCallCount: Bool, mockFinal: Bool, enableFuncArgsHistory: Bool, dstFilePath: String, concurrencyLimit: Int?, disableCombineDefaultValues: Bool) throws { + func verify(srcContents: [String], mockContents: [String]?, dstContent: String, header: String, declType: FindTargetDeclType, useTemplateFunc: Bool, useMockObservable: Bool, testableImports: [String] = [], allowSetCallCount: Bool, mockFinal: Bool, enableFuncArgsHistory: Bool, dstFilePath: String, concurrencyLimit: Int?, disableCombineDefaultValues: Bool) throws { var index = 0 srcFilePathsCount = srcContents.count mockFilePathsCount = mockContents?.count ?? 0 From 5bdc155570a026c3a22b73a12e742c0ffa9f0ebd Mon Sep 17 00:00:00 2001 From: Iceman Date: Wed, 6 Nov 2024 12:49:08 +0900 Subject: [PATCH 02/10] Use Algorithms --- .../Models/ParsedEntity.swift | 19 ++++++++--------- .../Operations/ImportsHandler.swift | 21 +++++++++++++------ .../Templates/NominalTemplate.swift | 4 ++-- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/Sources/MockoloFramework/Models/ParsedEntity.swift b/Sources/MockoloFramework/Models/ParsedEntity.swift index 2156b8ba..c372665d 100644 --- a/Sources/MockoloFramework/Models/ParsedEntity.swift +++ b/Sources/MockoloFramework/Models/ParsedEntity.swift @@ -14,15 +14,15 @@ // limitations under the License. // -import Foundation +import Algorithms /// Metadata containing unique models and potential init params ready to be rendered for output struct ResolvedEntity { - let key: String - let entity: Entity - let uniqueModels: [(String, Model)] - let attributes: [String] - let inheritedTypes: [String] + var key: String + var entity: Entity + var uniqueModels: [(String, Model)] + var attributes: [String] + var inheritedTypes: [String] var inheritsActorProtocol: Bool var declaredInits: [MethodModel] { @@ -44,8 +44,7 @@ struct ResolvedEntity { /// processed (already mocked by a previous run if any) models. /// @returns A list of init parameter models private func sortedInitVars(`in` models: [VariableModel]) -> [VariableModel] { - let processed = models.filter {$0.processed && $0.canBeInitParam} - let unprocessed = models.filter {!$0.processed && $0.canBeInitParam} + let (unprocessed, processed) = models.filter(\.canBeInitParam).partitioned(by: \.processed) // Named params in init should be unique. Add a duplicate param check to ensure it. let curVarsSorted = unprocessed.sorted(path: \.offset, fallback: \.name) @@ -74,8 +73,8 @@ struct ResolvedEntity { } struct ResolvedEntityContainer { - let entity: ResolvedEntity - let paths: [String] + var entity: ResolvedEntity + var paths: [String] } protocol EntityNode { diff --git a/Sources/MockoloFramework/Operations/ImportsHandler.swift b/Sources/MockoloFramework/Operations/ImportsHandler.swift index d927dd37..3b44f133 100644 --- a/Sources/MockoloFramework/Operations/ImportsHandler.swift +++ b/Sources/MockoloFramework/Operations/ImportsHandler.swift @@ -1,11 +1,20 @@ // -// ImportsHandler.swift -// MockoloFramework +// Copyright (c) 2018. Uber Technologies // -// Created by Ellie on 4/8/20. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // -import Foundation +import Algorithms func handleImports(pathToImportsMap: ImportMap, customImports: [String]?, @@ -46,8 +55,8 @@ func handleImports(pathToImportsMap: ImportMap, if let existingSet = sortedImports[defaultKey] { if let testableImports = testableImports { - let nonTestableInList = existingSet.filter { !testableImports.contains($0.moduleNameInImport) }.map{$0} - let testableInList = existingSet.filter { testableImports.contains($0.moduleNameInImport) }.map{ "@testable " + $0 } + let (nonTestableInList, rawTestableInList) = existingSet.partitioned(by: { testableImports.contains($0.moduleNameInImport) }) + let testableInList = rawTestableInList.map{ "@testable " + $0 } let remainingTestable = testableImports.filter { !testableInList.contains($0) }.map {$0.asTestableImport} let testable = Set([testableInList, remainingTestable].flatMap{$0}).sorted() sortedImports[defaultKey] = [nonTestableInList, testable].flatMap{$0} diff --git a/Sources/MockoloFramework/Templates/NominalTemplate.swift b/Sources/MockoloFramework/Templates/NominalTemplate.swift index 4cddf268..d0eff8c8 100644 --- a/Sources/MockoloFramework/Templates/NominalTemplate.swift +++ b/Sources/MockoloFramework/Templates/NominalTemplate.swift @@ -135,8 +135,8 @@ extension NominalModel { } else { let list = paramList.sorted(path: \.fullName, fallback: \.name) if list.count > 0, list.count == buffer.count { - let dups = zip(list, buffer).filter {$0.0.fullName == $0.1.fullName} - if !dups.isEmpty { + let hasDuplicates = zip(list, buffer).contains(where: { $0.fullName == $1.fullName }) + if hasDuplicates { needParamedInit = false } } From 64f57fae39e09e9e28eac20ca468310fbcb175f6 Mon Sep 17 00:00:00 2001 From: Iceman Date: Wed, 6 Nov 2024 12:51:27 +0900 Subject: [PATCH 03/10] Remove unnecessary default value --- .../MockoloFramework/Models/ParsedEntity.swift | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Sources/MockoloFramework/Models/ParsedEntity.swift b/Sources/MockoloFramework/Models/ParsedEntity.swift index c372665d..d9a7c2e1 100644 --- a/Sources/MockoloFramework/Models/ParsedEntity.swift +++ b/Sources/MockoloFramework/Models/ParsedEntity.swift @@ -146,10 +146,10 @@ public typealias ImportMap = [String: [String: [String]]] /// Metadata for a type being mocked public final class Entity { - var filepath: String = "" let entityNode: EntityNode - let isProcessed: Bool + let filepath: String let metadata: AnnotationMetadata? + let isProcessed: Bool var isAnnotated: Bool { return metadata != nil @@ -164,16 +164,14 @@ public final class Entity { guard !isPrivate, !isFinal else {return nil} - let node = Entity(entityNode: entityNode, - filepath: filepath, - metadata: metadata, - isProcessed: processed) - - return node + return Entity(entityNode: entityNode, + filepath: filepath, + metadata: metadata, + isProcessed: processed) } init(entityNode: EntityNode, - filepath: String = "", + filepath: String, metadata: AnnotationMetadata?, isProcessed: Bool) { self.entityNode = entityNode From de68c4c1c62616de9f36b0cbbe210476207e6d52 Mon Sep 17 00:00:00 2001 From: Iceman Date: Wed, 6 Nov 2024 14:41:34 +0900 Subject: [PATCH 04/10] Add test case about known issue --- Tests/TestMacros/FixtureMacro.swift | 36 ++++++++++++++++++++++++++ Tests/TestMacros/MacroTests.swift | 39 +++++++++++++++++------------ 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/Tests/TestMacros/FixtureMacro.swift b/Tests/TestMacros/FixtureMacro.swift index 843469ec..5a119ea9 100644 --- a/Tests/TestMacros/FixtureMacro.swift +++ b/Tests/TestMacros/FixtureMacro.swift @@ -270,3 +270,39 @@ class PresentableListenerMock: PresentableListener { } """ + +let macroInFuncWithOverload = """ +/// \(String.mockAnnotation) +protocol PresentableListener: AnyObject { + #if DEBUG + func run(value: Int) + func run(value: String) + #endif +} +""" + +let macroInFuncWithOverloadMock = """ +class PresentableListenerMock: PresentableListener { + init() { } + #if DEBUG + private(set) var runCallCount = 0 + var runHandler: ((Int) -> ())? + func run(value: Int) { + runCallCount += 1 + if let runHandler = runHandler { + runHandler(value) + } + + } + private(set) var runValueCallCount = 0 + var runValueHandler: ((String) -> ())? + func run(value: String) { + runValueCallCount += 1 + if let runValueHandler = runValueHandler { + runValueHandler(value) + } + + } + #endif +} +""" diff --git a/Tests/TestMacros/MacroTests.swift b/Tests/TestMacros/MacroTests.swift index 2f21706c..cc054fc4 100644 --- a/Tests/TestMacros/MacroTests.swift +++ b/Tests/TestMacros/MacroTests.swift @@ -1,35 +1,42 @@ -import Foundation +import XCTest -class MacroTests: MockoloTestCase { - func testMacroInFunc() { +final class MacroTests: MockoloTestCase { + func testMacroInFunc() { verify(srcContent: macroInFunc, dstContent: macroInFuncMock) } + func testMacroInFuncWithOverload() { + XCTExpectFailure("Resolving overloading in #if is broken.") { + verify(srcContent: macroInFuncWithOverload, + dstContent: macroInFuncWithOverloadMock) + } + } + func testMacroImports() { - verify(srcContent: macroImports, - dstContent: macroImportsMock) + verify(srcContent: macroImports, + dstContent: macroImportsMock) } - + func testMacroImportsWithOtherMacro() { - verify(srcContent: macroImports, - mockContent: parentMock, - dstContent: macroImportsWithParentMock) + verify(srcContent: macroImports, + mockContent: parentMock, + dstContent: macroImportsWithParentMock) } func testInheritedMacroImports() { - verify(srcContent: macroImports, - mockContent: parentWithMacroMock, - dstContent: inheritedMacroImportsMock) + verify(srcContent: macroImports, + mockContent: parentWithMacroMock, + dstContent: inheritedMacroImportsMock) } func testIfElseMacroImports() { - verify(srcContent: ifElseMacroImports, - dstContent: ifElseMacroImportsMock) + verify(srcContent: ifElseMacroImports, + dstContent: ifElseMacroImportsMock) } func testNestedMacroImports() { - verify(srcContent: nestedMacroImports, - dstContent: nestedMacroImportsMock) + verify(srcContent: nestedMacroImports, + dstContent: nestedMacroImportsMock) } } From 76762961742a3e35631459d1752a13f1f10ac64c Mon Sep 17 00:00:00 2001 From: Iceman Date: Wed, 6 Nov 2024 14:47:07 +0900 Subject: [PATCH 05/10] Fix consistency when context state is not correct --- .../MockoloFramework/Models/MethodModel.swift | 15 +++++---------- .../Templates/MethodTemplate.swift | 17 ++--------------- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/Sources/MockoloFramework/Models/MethodModel.swift b/Sources/MockoloFramework/Models/MethodModel.swift index 9f2a2bc3..9547a57b 100644 --- a/Sources/MockoloFramework/Models/MethodModel.swift +++ b/Sources/MockoloFramework/Models/MethodModel.swift @@ -219,18 +219,13 @@ final class MethodModel: Model { return nil } - return applyMethodTemplate(name: name, - kind: kind, + guard let overloadingResolvedName = context.overloadingResolvedName else { + return nil + } + + return applyMethodTemplate(overloadingResolvedName: overloadingResolvedName, arguments: arguments, - isStatic: isStatic, - customModifiers: customModifiers, isOverride: shouldOverride, - genericTypeParams: genericTypeParams, - genericWhereClause: genericWhereClause, - params: params, - returnType: returnType, - accessLevel: accessLevel, - argsHistory: argsHistory, handler: handler(), context: context) } diff --git a/Sources/MockoloFramework/Templates/MethodTemplate.swift b/Sources/MockoloFramework/Templates/MethodTemplate.swift index 05c512e3..78dcbde5 100644 --- a/Sources/MockoloFramework/Templates/MethodTemplate.swift +++ b/Sources/MockoloFramework/Templates/MethodTemplate.swift @@ -17,23 +17,11 @@ import Foundation extension MethodModel { - func applyMethodTemplate(name: String, - kind: MethodKind, + func applyMethodTemplate(overloadingResolvedName: String, arguments: GenerationArguments, - isStatic: Bool, - customModifiers: [String: Modifier]?, isOverride: Bool, - genericTypeParams: [ParamModel], - genericWhereClause: String?, - params: [ParamModel], - returnType: SwiftType, - accessLevel: String, - argsHistory: ArgumentsHistoryModel?, handler: ClosureModel?, context: RenderContext) -> String { - guard let overloadingResolvedName = context.overloadingResolvedName else { - preconditionFailure("context broken") - } var template = "" let returnTypeName = returnType.isUnknown ? "" : returnType.typeName @@ -122,8 +110,7 @@ extension MethodModel { let overrideStr = isOverride ? "\(String.override) " : "" let modifierTypeStr: String - if let customModifiers = customModifiers, - let customModifier: Modifier = customModifiers[name] { + if let customModifier: Modifier = customModifiers[name] { modifierTypeStr = customModifier.rawValue + " " } else { modifierTypeStr = "" From 7f3bc87d8385a2d04e394659676abadb3d657511 Mon Sep 17 00:00:00 2001 From: Iceman Date: Wed, 6 Nov 2024 15:12:16 +0900 Subject: [PATCH 06/10] remove unnecessary init argument --- Sources/MockoloFramework/Models/MethodModel.swift | 3 --- Sources/MockoloFramework/Models/VariableModel.swift | 6 +----- .../MockoloFramework/Parsers/SwiftSyntaxExtensions.swift | 8 ++------ 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/Sources/MockoloFramework/Models/MethodModel.swift b/Sources/MockoloFramework/Models/MethodModel.swift index 9547a57b..895f411c 100644 --- a/Sources/MockoloFramework/Models/MethodModel.swift +++ b/Sources/MockoloFramework/Models/MethodModel.swift @@ -35,7 +35,6 @@ final class MethodModel: Model { let processed: Bool let modelDescription: String? let isStatic: Bool - let shouldOverride: Bool let isAsync: Bool let throwing: ThrowingKind let funcsWithArgsHistory: [String] @@ -153,7 +152,6 @@ final class MethodModel: Model { init(name: String, typeName: String, kind: MethodKind, - encloserType: FindTargetDeclType, acl: String, genericTypeParams: [ParamModel], genericWhereClause: String?, @@ -175,7 +173,6 @@ final class MethodModel: Model { self.length = length self.kind = kind self.isStatic = isStatic - self.shouldOverride = encloserType == .classType self.params = params self.genericTypeParams = genericTypeParams self.genericWhereClause = genericWhereClause diff --git a/Sources/MockoloFramework/Models/VariableModel.swift b/Sources/MockoloFramework/Models/VariableModel.swift index fe440b7a..47c80e2b 100644 --- a/Sources/MockoloFramework/Models/VariableModel.swift +++ b/Sources/MockoloFramework/Models/VariableModel.swift @@ -17,12 +17,10 @@ final class VariableModel: Model { let offset: Int64 let accessLevel: String let attributes: [String]? - let encloserType: FindTargetDeclType /// Indicates whether this model can be used as a parameter to an initializer let canBeInitParam: Bool let processed: Bool let isStatic: Bool - let shouldOverride: Bool let storageKind: MockStorageKind let rxTypes: [String: String]? let customModifiers: [String: Modifier]? @@ -50,7 +48,6 @@ final class VariableModel: Model { init(name: String, type: SwiftType, acl: String?, - encloserType: FindTargetDeclType, isStatic: Bool, storageKind: MockStorageKind, canBeInitParam: Bool, @@ -65,14 +62,12 @@ final class VariableModel: Model { self.offset = offset self.isStatic = isStatic self.storageKind = storageKind - self.shouldOverride = encloserType == .classType self.canBeInitParam = canBeInitParam self.processed = processed self.rxTypes = rxTypes self.customModifiers = customModifiers self.accessLevel = acl ?? "" self.attributes = nil - self.encloserType = encloserType self.modelDescription = modelDescription self.combineType = combineType } @@ -84,6 +79,7 @@ final class VariableModel: Model { guard let enclosingType = context.enclosingType else { return nil } + let shouldOverride = context.annotatedTypeKind == .class if processed { guard let modelDescription = modelDescription?.trimmingCharacters(in: .newlines), !modelDescription.isEmpty else { return nil diff --git a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift index 21c04460..d52070b9 100644 --- a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift +++ b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift @@ -158,7 +158,7 @@ extension MemberBlockItemSyntax { if let varMember = self.decl.as(VariableDeclSyntax.self) { if validateMember(varMember.modifiers, declType, processed: processed) { let acl = memberAcl(varMember.modifiers, encloserAcl, declType) - if let item = varMember.models(with: acl, declType: declType, metadata: metadata, processed: processed).first { + if let item = varMember.models(with: acl, metadata: metadata, processed: processed).first { return (item, varMember.attributes.trimmedDescription, false) } } @@ -403,7 +403,7 @@ extension AttributeListSyntax { } extension VariableDeclSyntax { - func models(with acl: String, declType: FindTargetDeclType, metadata: AnnotationMetadata?, processed: Bool) -> [Model] { + func models(with acl: String, metadata: AnnotationMetadata?, processed: Bool) -> [Model] { // Detect whether it's static let isStatic = self.modifiers.isStatic @@ -454,7 +454,6 @@ extension VariableDeclSyntax { return VariableModel(name: name, type: SwiftType(typeName), acl: acl, - encloserType: declType, isStatic: isStatic, storageKind: storageKind, canBeInitParam: potentialInitParam, @@ -480,7 +479,6 @@ extension SubscriptDeclSyntax { let subscriptModel = MethodModel(name: self.subscriptKeyword.text, typeName: self.returnClause.type.description, kind: .subscriptKind, - encloserType: declType, acl: acl, genericTypeParams: genericTypeParams, genericWhereClause: genericWhereClause, @@ -510,7 +508,6 @@ extension FunctionDeclSyntax { let funcmodel = MethodModel(name: self.name.description, typeName: self.signature.returnClause?.type.description ?? "", kind: .funcKind, - encloserType: declType, acl: acl, genericTypeParams: genericTypeParams, genericWhereClause: genericWhereClause, @@ -551,7 +548,6 @@ extension InitializerDeclSyntax { return MethodModel(name: "init", typeName: "", kind: .initKind(required: requiredInit, override: declType == .classType), - encloserType: declType, acl: acl, genericTypeParams: genericTypeParams, genericWhereClause: genericWhereClause, From a24f9f6a3f0bb75e9786e143c0ae62eeaa7c877f Mon Sep 17 00:00:00 2001 From: Iceman Date: Wed, 6 Nov 2024 15:41:20 +0900 Subject: [PATCH 07/10] Use NominalTypeDeclKind instead of FindTargetDeclType in most places --- .../Models/ParsedEntity.swift | 2 +- .../Models/TypeAliasModel.swift | 9 +- .../Operations/UniqueModelGenerator.swift | 12 +-- .../Parsers/SwiftSyntaxExtensions.swift | 98 +++++++++---------- .../Utils/InheritanceResolver.swift | 12 +-- 5 files changed, 61 insertions(+), 72 deletions(-) diff --git a/Sources/MockoloFramework/Models/ParsedEntity.swift b/Sources/MockoloFramework/Models/ParsedEntity.swift index d9a7c2e1..e75e08db 100644 --- a/Sources/MockoloFramework/Models/ParsedEntity.swift +++ b/Sources/MockoloFramework/Models/ParsedEntity.swift @@ -87,7 +87,7 @@ protocol EntityNode { var inheritedTypes: [String] { get } var offset: Int64 { get } var hasBlankInit: Bool { get } - func subContainer(metadata: AnnotationMetadata?, declType: FindTargetDeclType, path: String?, isProcessed: Bool) -> EntityNodeSubContainer + func subContainer(metadata: AnnotationMetadata?, declKind: NominalTypeDeclKind, path: String?, isProcessed: Bool) -> EntityNodeSubContainer } struct EntityNodeSubContainer { diff --git a/Sources/MockoloFramework/Models/TypeAliasModel.swift b/Sources/MockoloFramework/Models/TypeAliasModel.swift index 30965980..146dd445 100644 --- a/Sources/MockoloFramework/Models/TypeAliasModel.swift +++ b/Sources/MockoloFramework/Models/TypeAliasModel.swift @@ -26,13 +26,12 @@ final class TypeAliasModel: Model { let useDescription: Bool let modelDescription: String? let overrideTypes: [String: String]? - let addAcl: Bool var modelType: ModelType { return .typeAlias } - init(name: String, typeName: String, acl: String?, encloserType: FindTargetDeclType, overrideTypes: [String: String]?, offset: Int64, length: Int64, modelDescription: String?, useDescription: Bool = false, processed: Bool) { + init(name: String, typeName: String, acl: String?, overrideTypes: [String: String]?, offset: Int64, length: Int64, modelDescription: String?, useDescription: Bool = false, processed: Bool) { self.name = name self.accessLevel = acl ?? "" self.offset = offset @@ -41,7 +40,6 @@ final class TypeAliasModel: Model { self.modelDescription = modelDescription self.overrideTypes = overrideTypes self.useDescription = useDescription - self.addAcl = encloserType == .protocolType && !processed // If there's an override typealias value, set it to type if let val = overrideTypes?[self.name] { self.type = SwiftType(val) @@ -53,15 +51,16 @@ final class TypeAliasModel: Model { var fullName: String { return self.name + self.type.displayName } - + func name(by level: Int) -> String { return fullName } - + func render( context: RenderContext, arguments: GenerationArguments ) -> String? { + let addAcl = context.annotatedTypeKind == .protocol && !processed if processed || useDescription, let modelDescription = modelDescription?.trimmingCharacters(in: .whitespacesAndNewlines) { if addAcl { return "\(1.tab)\(accessLevel) \(modelDescription)" diff --git a/Sources/MockoloFramework/Operations/UniqueModelGenerator.swift b/Sources/MockoloFramework/Operations/UniqueModelGenerator.swift index d423c679..7e29e485 100644 --- a/Sources/MockoloFramework/Operations/UniqueModelGenerator.swift +++ b/Sources/MockoloFramework/Operations/UniqueModelGenerator.swift @@ -34,17 +34,7 @@ private func generateUniqueModels(key: String, entity: Entity, protocolMap: [String: Entity], inheritanceMap: [String: Entity]) -> ResolvedEntityContainer { - let declType: FindTargetDeclType = { - switch entity.entityNode.declKind { - case .class: - return .classType - case .actor: - return .other - case .protocol: - return .protocolType - } - }() - let (models, processedModels, attributes, inheritedTypes, paths) = lookupEntities(key: key, declType: declType, protocolMap: protocolMap, inheritanceMap: inheritanceMap) + let (models, processedModels, attributes, inheritedTypes, paths) = lookupEntities(key: key, declKind: entity.entityNode.declKind, protocolMap: protocolMap, inheritanceMap: inheritanceMap) let processedFullNames = processedModels.compactMap {$0.fullName} diff --git a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift index d52070b9..18e8d3e8 100644 --- a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift +++ b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift @@ -123,16 +123,16 @@ extension InheritanceClauseSyntax { } extension MemberBlockItemSyntax { - private func validateMember(_ modifiers: DeclModifierListSyntax?, _ declType: FindTargetDeclType, processed: Bool) -> Bool { + private func validateMember(_ modifiers: DeclModifierListSyntax?, _ declKind: NominalTypeDeclKind, processed: Bool) -> Bool { if let mods = modifiers { - if !processed && mods.isPrivate || mods.isStatic && declType == .classType { + if !processed && mods.isPrivate || mods.isStatic && declKind == .class { return false } } return true } - private func validateInit(_ initDecl: InitializerDeclSyntax, _ declType: FindTargetDeclType, processed: Bool) -> Bool { + private func validateInit(_ initDecl: InitializerDeclSyntax, _ declKind: NominalTypeDeclKind, processed: Bool) -> Bool { let modifiers = initDecl.modifiers let isRequired = modifiers.isRequired if processed { @@ -147,49 +147,49 @@ extension MemberBlockItemSyntax { return true } - private func memberAcl(_ modifiers: DeclModifierListSyntax?, _ encloserAcl: String, _ declType: FindTargetDeclType) -> String { - if declType == .protocolType { + private func memberAcl(_ modifiers: DeclModifierListSyntax?, _ encloserAcl: String, _ declKind: NominalTypeDeclKind) -> String { + if declKind == .protocol { return encloserAcl } return modifiers?.acl ?? "" } - func transformToModel(with encloserAcl: String, declType: FindTargetDeclType, metadata: AnnotationMetadata?, processed: Bool) -> (Model, String?, Bool)? { + func transformToModel(with encloserAcl: String, declKind: NominalTypeDeclKind, metadata: AnnotationMetadata?, processed: Bool) -> (Model, String?, Bool)? { if let varMember = self.decl.as(VariableDeclSyntax.self) { - if validateMember(varMember.modifiers, declType, processed: processed) { - let acl = memberAcl(varMember.modifiers, encloserAcl, declType) + if validateMember(varMember.modifiers, declKind, processed: processed) { + let acl = memberAcl(varMember.modifiers, encloserAcl, declKind) if let item = varMember.models(with: acl, metadata: metadata, processed: processed).first { return (item, varMember.attributes.trimmedDescription, false) } } } else if let funcMember = self.decl.as(FunctionDeclSyntax.self) { - if validateMember(funcMember.modifiers, declType, processed: processed) { - let acl = memberAcl(funcMember.modifiers, encloserAcl, declType) - let item = funcMember.model(with: acl, declType: declType, funcsWithArgsHistory: metadata?.funcsWithArgsHistory, customModifiers: metadata?.modifiers, processed: processed) + if validateMember(funcMember.modifiers, declKind, processed: processed) { + let acl = memberAcl(funcMember.modifiers, encloserAcl, declKind) + let item = funcMember.model(with: acl, declKind: declKind, funcsWithArgsHistory: metadata?.funcsWithArgsHistory, customModifiers: metadata?.modifiers, processed: processed) return (item, funcMember.attributes.trimmedDescription, false) } } else if let subscriptMember = self.decl.as(SubscriptDeclSyntax.self) { - if validateMember(subscriptMember.modifiers, declType, processed: processed) { - let acl = memberAcl(subscriptMember.modifiers, encloserAcl, declType) - let item = subscriptMember.model(with: acl, declType: declType, processed: processed) + if validateMember(subscriptMember.modifiers, declKind, processed: processed) { + let acl = memberAcl(subscriptMember.modifiers, encloserAcl, declKind) + let item = subscriptMember.model(with: acl, declKind: declKind, processed: processed) return (item, subscriptMember.attributes.trimmedDescription, false) } } else if let initMember = self.decl.as(InitializerDeclSyntax.self) { - if validateInit(initMember, declType, processed: processed) { - let acl = memberAcl(initMember.modifiers, encloserAcl, declType) - let item = initMember.model(with: acl, declType: declType, processed: processed) + if validateInit(initMember, declKind, processed: processed) { + let acl = memberAcl(initMember.modifiers, encloserAcl, declKind) + let item = initMember.model(with: acl, declKind: declKind, processed: processed) return (item, initMember.attributes.trimmedDescription, true) } } else if let patMember = self.decl.as(AssociatedTypeDeclSyntax.self) { - let acl = memberAcl(patMember.modifiers, encloserAcl, declType) - let item = patMember.model(with: acl, declType: declType, overrides: metadata?.typeAliases, processed: processed) + let acl = memberAcl(patMember.modifiers, encloserAcl, declKind) + let item = patMember.model(with: acl, declKind: declKind, overrides: metadata?.typeAliases, processed: processed) return (item, patMember.attributes.trimmedDescription, false) } else if let taMember = self.decl.as(TypeAliasDeclSyntax.self) { - let acl = memberAcl(taMember.modifiers, encloserAcl, declType) - let item = taMember.model(with: acl, declType: declType, overrides: metadata?.typeAliases, processed: processed) + let acl = memberAcl(taMember.modifiers, encloserAcl, declKind) + let item = taMember.model(with: acl, declKind: declKind, overrides: metadata?.typeAliases, processed: processed) return (item, taMember.attributes.trimmedDescription, false) } else if let ifMacroMember = self.decl.as(IfConfigDeclSyntax.self) { - let (item, attr, initFlag) = ifMacroMember.model(with: encloserAcl, declType: declType, metadata: metadata, processed: processed) + let (item, attr, initFlag) = ifMacroMember.model(with: encloserAcl, declKind: declKind, metadata: metadata, processed: processed) return (item, attr, initFlag) } @@ -213,13 +213,13 @@ extension MemberBlockItemListSyntax { return false } - func memberData(with encloserAcl: String, declType: FindTargetDeclType, metadata: AnnotationMetadata?, processed: Bool) -> EntityNodeSubContainer { + func memberData(with encloserAcl: String, declKind: NominalTypeDeclKind, metadata: AnnotationMetadata?, processed: Bool) -> EntityNodeSubContainer { var attributeList = [String]() var memberList = [Model]() var hasInit = false for m in self { - if let (item, attr, initFlag) = m.transformToModel(with: encloserAcl, declType: declType, metadata: metadata, processed: processed) { + if let (item, attr, initFlag) = m.transformToModel(with: encloserAcl, declKind: declKind, metadata: metadata, processed: processed) { memberList.append(item) if let attrDesc = attr { attributeList.append(attrDesc) @@ -232,7 +232,7 @@ extension MemberBlockItemListSyntax { } extension IfConfigDeclSyntax { - func model(with encloserAcl: String, declType: FindTargetDeclType, metadata: AnnotationMetadata?, processed: Bool) -> (Model, String?, Bool) { + func model(with encloserAcl: String, declKind: NominalTypeDeclKind, metadata: AnnotationMetadata?, processed: Bool) -> (Model, String?, Bool) { var subModels = [Model]() var attrDesc: String? var hasInit = false @@ -243,7 +243,7 @@ extension IfConfigDeclSyntax { if let list = cl.elements?.as(MemberBlockItemListSyntax.self) { name = desc for element in list { - if let (item, attr, initFlag) = element.transformToModel(with: encloserAcl, declType: declType, metadata: metadata, processed: processed) { + if let (item, attr, initFlag) = element.transformToModel(with: encloserAcl, declKind: declKind, metadata: metadata, processed: processed) { subModels.append(item) if let attr = attr, attr.contains(String.available) { attrDesc = attr @@ -301,8 +301,8 @@ extension ProtocolDeclSyntax: EntityNode { return false } - func subContainer(metadata: AnnotationMetadata?, declType: FindTargetDeclType, path: String?, isProcessed: Bool) -> EntityNodeSubContainer { - return self.memberBlock.members.memberData(with: accessLevel, declType: declType, metadata: metadata, processed: isProcessed) + func subContainer(metadata: AnnotationMetadata?, declKind: NominalTypeDeclKind, path: String?, isProcessed: Bool) -> EntityNodeSubContainer { + return self.memberBlock.members.memberData(with: accessLevel, declKind: declKind, metadata: metadata, processed: isProcessed) } } @@ -355,8 +355,8 @@ extension ClassDeclSyntax: EntityNode { return leadingTrivia.annotationMetadata(with: annotation) } - func subContainer(metadata: AnnotationMetadata?, declType: FindTargetDeclType, path: String?, isProcessed: Bool) -> EntityNodeSubContainer { - return self.memberBlock.members.memberData(with: accessLevel, declType: declType, metadata: nil, processed: isProcessed) + func subContainer(metadata: AnnotationMetadata?, declKind: NominalTypeDeclKind, path: String?, isProcessed: Bool) -> EntityNodeSubContainer { + return self.memberBlock.members.memberData(with: accessLevel, declKind: declKind, metadata: nil, processed: isProcessed) } } @@ -469,10 +469,10 @@ extension VariableDeclSyntax { } extension SubscriptDeclSyntax { - func model(with acl: String, declType: FindTargetDeclType, processed: Bool) -> Model { + func model(with acl: String, declKind: NominalTypeDeclKind, processed: Bool) -> Model { let isStatic = self.modifiers.isStatic - let params = self.parameterClause.parameters.compactMap { $0.model(inInit: false, declType: declType) } + let params = self.parameterClause.parameters.compactMap { $0.model(inInit: false, declKind: declKind) } let genericTypeParams = self.genericParameterClause?.parameters.compactMap { $0.model(inInit: false) } ?? [] let genericWhereClause = self.genericWhereClause?.description @@ -498,10 +498,10 @@ extension SubscriptDeclSyntax { extension FunctionDeclSyntax { - func model(with acl: String, declType: FindTargetDeclType, funcsWithArgsHistory: [String]?, customModifiers: [String : Modifier]?, processed: Bool) -> Model { + func model(with acl: String, declKind: NominalTypeDeclKind, funcsWithArgsHistory: [String]?, customModifiers: [String : Modifier]?, processed: Bool) -> Model { let isStatic = self.modifiers.isStatic - let params = self.signature.parameterClause.parameters.compactMap { $0.model(inInit: false, declType: declType) } + let params = self.signature.parameterClause.parameters.compactMap { $0.model(inInit: false, declKind: declKind) } let genericTypeParams = self.genericParameterClause?.parameters.compactMap { $0.model(inInit: false) } ?? [] let genericWhereClause = self.genericWhereClause?.description @@ -526,28 +526,30 @@ extension FunctionDeclSyntax { } extension InitializerDeclSyntax { - func isRequired(with declType: FindTargetDeclType) -> Bool { - if declType == .protocolType { - return true - } else if declType == .classType { + func isRequired(with declKind: NominalTypeDeclKind) -> Bool { + switch declKind { + case .class: if modifiers.isConvenience { return false } return modifiers.isRequired + case .protocol: + return true + default: + return false // Other types do not support inheritance } - return false } - func model(with acl: String, declType: FindTargetDeclType, processed: Bool) -> Model { - let requiredInit = isRequired(with: declType) + func model(with acl: String, declKind: NominalTypeDeclKind, processed: Bool) -> Model { + let requiredInit = isRequired(with: declKind) - let params = self.signature.parameterClause.parameters.compactMap { $0.model(inInit: true, declType: declType) } + let params = self.signature.parameterClause.parameters.compactMap { $0.model(inInit: true, declKind: declKind) } let genericTypeParams = self.genericParameterClause?.parameters.compactMap { $0.model(inInit: true) } ?? [] let genericWhereClause = self.genericWhereClause?.description return MethodModel(name: "init", typeName: "", - kind: .initKind(required: requiredInit, override: declType == .classType), + kind: .initKind(required: requiredInit, override: declKind == .class), acl: acl, genericTypeParams: genericTypeParams, genericWhereClause: genericWhereClause, @@ -580,7 +582,7 @@ extension GenericParameterSyntax { } extension FunctionParameterSyntax { - func model(inInit: Bool, declType: FindTargetDeclType) -> ParamModel { + func model(inInit: Bool, declKind: NominalTypeDeclKind) -> ParamModel { var label = "" var name = "" // Get label and name of args @@ -607,7 +609,7 @@ extension FunctionParameterSyntax { type: SwiftType(type), isGeneric: false, inInit: inInit, - needsVarDecl: declType == .protocolType, + needsVarDecl: declKind == .protocol, offset: self.offset, length: self.length) } @@ -615,7 +617,7 @@ extension FunctionParameterSyntax { } extension AssociatedTypeDeclSyntax { - func model(with acl: String, declType: FindTargetDeclType, overrides: [String: String]?, processed: Bool) -> Model { + func model(with acl: String, declKind: NominalTypeDeclKind, overrides: [String: String]?, processed: Bool) -> Model { // Get the inhertied type for an associated type if any var t = self.inheritanceClause?.typesDescription ?? "" t.append(self.genericWhereClause?.description ?? "") @@ -623,7 +625,6 @@ extension AssociatedTypeDeclSyntax { return TypeAliasModel(name: self.name.text, typeName: t, acl: acl, - encloserType: declType, overrideTypes: overrides, offset: self.offset, length: self.length, @@ -633,11 +634,10 @@ extension AssociatedTypeDeclSyntax { } extension TypeAliasDeclSyntax { - func model(with acl: String, declType: FindTargetDeclType, overrides: [String: String]?, processed: Bool) -> Model { + func model(with acl: String, declKind: NominalTypeDeclKind, overrides: [String: String]?, processed: Bool) -> Model { return TypeAliasModel(name: self.name.text, typeName: self.initializer.value.description, acl: acl, - encloserType: declType, overrideTypes: overrides, offset: self.offset, length: self.length, diff --git a/Sources/MockoloFramework/Utils/InheritanceResolver.swift b/Sources/MockoloFramework/Utils/InheritanceResolver.swift index febcf6fe..4fe827b2 100644 --- a/Sources/MockoloFramework/Utils/InheritanceResolver.swift +++ b/Sources/MockoloFramework/Utils/InheritanceResolver.swift @@ -25,7 +25,7 @@ import Algorithms /// @returns a list of models representing sub-entities of the current entity, a list of models processed in dependent mock files if exists, /// cumulated attributes, cumulated inherited types, and a map of filepaths and file contents (used for import lines lookup later). func lookupEntities(key: String, - declType: FindTargetDeclType, + declKind: NominalTypeDeclKind, protocolMap: [String: Entity], inheritanceMap: [String: Entity]) -> ([Model], [Model], [String], Set, [String]) { @@ -42,7 +42,7 @@ func lookupEntities(key: String, // Look up the mock entities of a protocol specified by the name. if let current = protocolMap[key] { - let sub = current.entityNode.subContainer(metadata: current.metadata, declType: declType, path: current.filepath, isProcessed: current.isProcessed) + let sub = current.entityNode.subContainer(metadata: current.metadata, declKind: declKind, path: current.filepath, isProcessed: current.isProcessed) models.append(contentsOf: sub.members) if !current.isProcessed { attributes.append(contentsOf: sub.attributes) @@ -51,11 +51,11 @@ func lookupEntities(key: String, paths.append(current.filepath) - if declType == .protocolType { // TODO: remove this once parent protocol (current decl = classtype) handling is resolved. + if declKind == .protocol { // TODO: remove this once parent protocol (current decl = classtype) handling is resolved. // If the protocol inherits other protocols, look up their entities as well. for parent in current.entityNode.inheritedTypes { if parent != .class, parent != .anyType, parent != .anyObject { - let (parentModels, parentProcessedModels, parentAttributes, parentInheritedTypes, parentPaths) = lookupEntities(key: parent, declType: declType, protocolMap: protocolMap, inheritanceMap: inheritanceMap) + let (parentModels, parentProcessedModels, parentAttributes, parentInheritedTypes, parentPaths) = lookupEntities(key: parent, declKind: declKind, protocolMap: protocolMap, inheritanceMap: inheritanceMap) models.append(contentsOf: parentModels) processedModels.append(contentsOf: parentProcessedModels) attributes.append(contentsOf: parentAttributes) @@ -64,9 +64,9 @@ func lookupEntities(key: String, } } } - } else if let parentMock = inheritanceMap["\(key)Mock"], declType == .protocolType { + } else if let parentMock = inheritanceMap["\(key)Mock"], declKind == .protocol { // If the parent protocol is not in the protocol map, look it up in the input parent mocks map. - let sub = parentMock.entityNode.subContainer(metadata: parentMock.metadata, declType: declType, path: parentMock.filepath, isProcessed: parentMock.isProcessed) + let sub = parentMock.entityNode.subContainer(metadata: parentMock.metadata, declKind: declKind, path: parentMock.filepath, isProcessed: parentMock.isProcessed) processedModels.append(contentsOf: sub.members) if !parentMock.isProcessed { attributes.append(contentsOf: sub.attributes) From 6afc54433d5685b7829b8cd8d9b02945e8fbb89a Mon Sep 17 00:00:00 2001 From: Iceman Date: Wed, 6 Nov 2024 15:56:29 +0900 Subject: [PATCH 08/10] Use XCTExpectFailure in macOS --- Tests/TestMacros/MacroTests.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/TestMacros/MacroTests.swift b/Tests/TestMacros/MacroTests.swift index cc054fc4..33b101fb 100644 --- a/Tests/TestMacros/MacroTests.swift +++ b/Tests/TestMacros/MacroTests.swift @@ -6,12 +6,14 @@ final class MacroTests: MockoloTestCase { dstContent: macroInFuncMock) } +#if os(macOS) func testMacroInFuncWithOverload() { XCTExpectFailure("Resolving overloading in #if is broken.") { verify(srcContent: macroInFuncWithOverload, dstContent: macroInFuncWithOverloadMock) } } +#endif func testMacroImports() { verify(srcContent: macroImports, From f051257b7081001e7f79e0db4b6f55ed73ca499b Mon Sep 17 00:00:00 2001 From: Iceman Date: Wed, 6 Nov 2024 16:03:00 +0900 Subject: [PATCH 09/10] Avoid force unwrapping and keep consistency --- Sources/MockoloFramework/Models/ClosureModel.swift | 9 +++++---- Sources/MockoloFramework/Templates/MethodTemplate.swift | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Sources/MockoloFramework/Models/ClosureModel.swift b/Sources/MockoloFramework/Models/ClosureModel.swift index bcd4c418..8204ab39 100644 --- a/Sources/MockoloFramework/Models/ClosureModel.swift +++ b/Sources/MockoloFramework/Models/ClosureModel.swift @@ -42,14 +42,14 @@ final class ClosureModel: Model { self.funcReturnType = returnType } - func type(context: RenderContext) -> SwiftType { + func type(enclosingType: SwiftType) -> SwiftType { return SwiftType.toClosureType( params: paramTypes, typeParams: genericTypeNames, isAsync: isAsync, throwing: throwing, returnType: funcReturnType, - encloser: context.enclosingType! + encloser: enclosingType ) } @@ -57,10 +57,11 @@ final class ClosureModel: Model { context: RenderContext, arguments: GenerationArguments = .default ) -> String? { - guard let overloadingResolvedName = context.overloadingResolvedName else { + guard let overloadingResolvedName = context.overloadingResolvedName, + let enclosingType = context.enclosingType else { return nil } - return applyClosureTemplate(type: type(context: context), + return applyClosureTemplate(type: type(enclosingType: enclosingType), name: overloadingResolvedName + .handlerSuffix, paramVals: paramNames, paramTypes: paramTypes, diff --git a/Sources/MockoloFramework/Templates/MethodTemplate.swift b/Sources/MockoloFramework/Templates/MethodTemplate.swift index 78dcbde5..0413d58e 100644 --- a/Sources/MockoloFramework/Templates/MethodTemplate.swift +++ b/Sources/MockoloFramework/Templates/MethodTemplate.swift @@ -37,11 +37,11 @@ extension MethodModel { return "" default: - guard let handler else { return "" } + guard let handler, let enclosingType = context.enclosingType else { return "" } let callCount = "\(overloadingResolvedName)\(String.callCountSuffix)" let handlerVarName = "\(overloadingResolvedName)\(String.handlerSuffix)" - let handlerVarType = handler.type(context: context).typeName // ?? "Any" + let handlerVarType = handler.type(enclosingType: enclosingType).typeName // ?? "Any" let handlerReturn = handler.render(context: context) ?? "" let suffixStr = applyFunctionSuffixTemplate( @@ -54,7 +54,7 @@ extension MethodModel { var body = "" if arguments.useTemplateFunc { - let callMockFunc = !throwing.hasError && (handler.type(context: context).cast?.isEmpty ?? false) + let callMockFunc = !throwing.hasError && (handler.type(enclosingType: enclosingType).cast?.isEmpty ?? false) if callMockFunc { let handlerParamValsStr = params.map { (arg) -> String in if arg.type.typeName.hasPrefix(String.autoclosure) { From e399b0e4b5b12e9289ab0e3e123192334112b197 Mon Sep 17 00:00:00 2001 From: Iceman Date: Mon, 11 Nov 2024 09:41:34 +0900 Subject: [PATCH 10/10] Update Sources/MockoloFramework/Models/TypeAliasModel.swift Co-authored-by: Fumiya Tanaka --- Sources/MockoloFramework/Models/TypeAliasModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/MockoloFramework/Models/TypeAliasModel.swift b/Sources/MockoloFramework/Models/TypeAliasModel.swift index 146dd445..13ca0acc 100644 --- a/Sources/MockoloFramework/Models/TypeAliasModel.swift +++ b/Sources/MockoloFramework/Models/TypeAliasModel.swift @@ -58,7 +58,7 @@ final class TypeAliasModel: Model { func render( context: RenderContext, - arguments: GenerationArguments + arguments: GenerationArguments = .default ) -> String? { let addAcl = context.annotatedTypeKind == .protocol && !processed if processed || useDescription, let modelDescription = modelDescription?.trimmingCharacters(in: .whitespacesAndNewlines) {