Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Method/Initializer parameter types now resolve to the local type if it exists #1347

Merged
merged 3 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
Expand Down
32 changes: 27 additions & 5 deletions SourceryFramework/Sources/Parsing/SwiftSyntax/AST/Signature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for leaving NOTE and TODO 👍🏻

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(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏻

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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
32 changes: 32 additions & 0 deletions SourceryTests/Parsing/FileParser_MethodsSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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([
Expand Down
Loading