diff --git a/SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Method+SwiftSyntax.swift b/SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Method+SwiftSyntax.swift index 79857275f..03a6feec5 100644 --- a/SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Method+SwiftSyntax.swift +++ b/SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Method+SwiftSyntax.swift @@ -9,7 +9,7 @@ extension SourceryMethod { parent: parent, identifier: node.name.text.trimmed, typeName: typeName, - signature: Signature(node.signature, annotationsParser: annotationsParser), + signature: Signature(node.signature, annotationsParser: annotationsParser, parent: parent), modifiers: node.modifiers, attributes: node.attributes, genericParameterClause: node.genericParameterClause, @@ -30,7 +30,8 @@ extension SourceryMethod { output: nil, asyncKeyword: nil, throwsOrRethrowsKeyword: signature.effectSpecifiers?.throwsSpecifier?.description.trimmed, - annotationsParser: annotationsParser + annotationsParser: annotationsParser, + parent: parent ), modifiers: node.modifiers, attributes: node.attributes, @@ -46,7 +47,7 @@ extension SourceryMethod { parent: parent, identifier: "deinit", typeName: typeName, - signature: Signature(parameters: nil, output: nil, asyncKeyword: nil, throwsOrRethrowsKeyword: nil, annotationsParser: annotationsParser), + signature: Signature(parameters: nil, output: nil, asyncKeyword: nil, throwsOrRethrowsKeyword: nil, annotationsParser: annotationsParser, parent: parent), modifiers: node.modifiers, attributes: node.attributes, genericParameterClause: nil, diff --git a/SourceryFramework/Sources/Parsing/SwiftSyntax/AST/MethodParameter+SwiftSyntax.swift b/SourceryFramework/Sources/Parsing/SwiftSyntax/AST/MethodParameter+SwiftSyntax.swift index 6980619f3..c369cc2e6 100644 --- a/SourceryFramework/Sources/Parsing/SwiftSyntax/AST/MethodParameter+SwiftSyntax.swift +++ b/SourceryFramework/Sources/Parsing/SwiftSyntax/AST/MethodParameter+SwiftSyntax.swift @@ -2,12 +2,24 @@ import SwiftSyntax import SourceryRuntime extension MethodParameter { - convenience init(_ node: FunctionParameterSyntax, index: Int, annotationsParser: AnnotationsParser) { + convenience init(_ node: FunctionParameterSyntax, index: Int, annotationsParser: AnnotationsParser, parent: Type?) { let firstName = node.firstName.text.trimmed.nilIfNotValidParameterName - let typeName = TypeName(node.type) + let isVisitingTypeSourceryProtocol = parent is SourceryProtocol let specifiers = TypeName.specifiers(from: node.type) - + + // NOTE: This matches implementation in Variable+SwiftSyntax.swift + // TODO: Walk up the `parent` in the event that there are multiple levels of nested types + var typeName = TypeName(node.type) + if !isVisitingTypeSourceryProtocol { + // we are in a custom type, which may contain other types + // in order to assign correct type to the variable, we need to match + // all of the contained types against the variable type + if let matchingContainedType = parent?.containedTypes.first(where: { $0.localName == typeName.name }) { + typeName = TypeName(matchingContainedType.name) + } + } + if specifiers.isInOut { // TODO: TBR typeName.name = "inout \(typeName.name)" diff --git a/SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Signature.swift b/SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Signature.swift index f015cbc16..e932e67ba 100644 --- a/SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Signature.swift +++ b/SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Signature.swift @@ -14,20 +14,42 @@ public struct Signature { /// The `throws` or `rethrows` keyword, if any. public let throwsOrRethrowsKeyword: String? - public init(_ node: FunctionSignatureSyntax, annotationsParser: AnnotationsParser) { + public init(_ node: FunctionSignatureSyntax, annotationsParser: AnnotationsParser, parent: Type?) { + let isVisitingTypeSourceryProtocol = parent is SourceryProtocol + + // NOTE: This matches implementation in Variable+SwiftSyntax.swift + // TODO: Walk up the `parent` in the event that there are multiple levels of nested types + var returnTypeName = node.returnClause.map { TypeName($0.type) } + if !isVisitingTypeSourceryProtocol { + // we are in a custom type, which may contain other types + // in order to assign correct type to the variable, we need to match + // all of the contained types against the variable type + if let matchingContainedType = parent?.containedTypes.first(where: { $0.localName == returnTypeName?.name }) { + returnTypeName = TypeName(matchingContainedType.name) + } + } + self.init(parameters: node.parameterClause.parameters, - output: node.returnClause.map { TypeName($0.type) }, + output: returnTypeName, asyncKeyword: node.effectSpecifiers?.asyncSpecifier?.text, throwsOrRethrowsKeyword: node.effectSpecifiers?.throwsSpecifier?.description.trimmed, - annotationsParser: annotationsParser + annotationsParser: annotationsParser, + parent: parent ) } - public init(parameters: FunctionParameterListSyntax?, output: TypeName?, asyncKeyword: String?, throwsOrRethrowsKeyword: String?, annotationsParser: AnnotationsParser) { + public init( + parameters: FunctionParameterListSyntax?, + output: TypeName?, + asyncKeyword: String?, + throwsOrRethrowsKeyword: String?, + annotationsParser: AnnotationsParser, + parent: Type? + ) { var methodParameters: [MethodParameter] = [] if let parameters { for (idx, param) in parameters.enumerated() { - methodParameters.append(MethodParameter(param, index: idx, annotationsParser: annotationsParser)) + methodParameters.append(MethodParameter(param, index: idx, annotationsParser: annotationsParser, parent: parent)) } } input = methodParameters diff --git a/SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Subscript+SwiftSyntax.swift b/SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Subscript+SwiftSyntax.swift index e1e555821..f55dbbda9 100644 --- a/SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Subscript+SwiftSyntax.swift +++ b/SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Subscript+SwiftSyntax.swift @@ -85,7 +85,7 @@ extension Subscript { var parameters: [MethodParameter] = [] for (idx, param) in node.parameterClause.parameters.enumerated() { - parameters.append(MethodParameter(param, index: idx, annotationsParser: annotationsParser)) + parameters.append(MethodParameter(param, index: idx, annotationsParser: annotationsParser, parent: parent)) } self.init( parameters: parameters, diff --git a/SourceryTests/Parsing/FileParser_MethodsSpec.swift b/SourceryTests/Parsing/FileParser_MethodsSpec.swift index 4ba9fa5e2..06df1329a 100644 --- a/SourceryTests/Parsing/FileParser_MethodsSpec.swift +++ b/SourceryTests/Parsing/FileParser_MethodsSpec.swift @@ -284,6 +284,38 @@ class FileParserMethodsSpec: QuickSpec { ])) } + it("extracts correct typeName when a nested type shadows a global type") { + let code = """ + protocol Foo { + } + + class Bar { + struct Foo { + } + + func doSomething(with foo: Foo) -> Foo { + } + } + """ + + let fooProtocol = Protocol(name: "Foo") + let fooStruct = Struct(name: "Foo") + let barClass = Class( + name: "Bar", + methods: [ + Method(name: "doSomething(with foo: Bar.Foo)", selectorName: "doSomething(with:)", parameters: [ + MethodParameter(argumentLabel: "with", name: "foo", index: 0, typeName: TypeName("Bar.Foo"), type: fooStruct) + ], returnTypeName: TypeName("Bar.Foo"), definedInTypeName: TypeName("Bar")) + ], + containedTypes: [ + fooStruct + ] + ) + + let result = parse(code) + expect(result).to(equal([fooProtocol, barClass, fooStruct])) + } + context("given parameter default value") { it("extracts simple default value") { expect(parse("class Foo { func foo(a: Int? = nil) {} }")).to(equal([