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)