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

Conversation

liamnichols
Copy link
Collaborator

Background

In the latest 2.2.5 release, our templates seemed to have hit a regression where an associated type within an unrelated protocol would show up as the type for a MethodParameter of an unrelated type. This led me to discover a subtle inconsistency between how types of method parameters are resolved compared to variables.

When resolving a variable type from the syntax tree, it will be sure to check for the type name within the containedTypes because this type should take priority over any global 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 = visitingType?.containedTypes.first(where: {
$0.localName == typeName?.name
}) {
typeName = TypeName(matchingContainedType.name)
}
}

This handling was missing for MethodParameter which means that the typeName (and later type) would always be Foo instead of Bar.Foo.

Changes

This change addresses the immediate issue of Method Parameter types not being correct by passing the parent Type into the FunctionParameterSyntax initialiser which is used when walking the syntax tree.

This however isn't quite a complete fix. While looking at the code, I spotted a few other gotchas:

  1. Return types also aren't resolved with local nested types in mind
    • I fixed this.. But the same consideration will need to be made for typed throws later on
  2. It only works for the immediate parent type and doesn't account for multiple levels of nesting - this flaw also exists with the variable type resolution

But I think that it's a beneficial one for now until some further work can be done to align type resolution. Anyway.. Feedback is welcome 🙏

@liamnichols liamnichols self-assigned this Jul 15, 2024
@liamnichols liamnichols marked this pull request as ready for review July 15, 2024 20:38
@liamnichols liamnichols requested a review from art-divin July 15, 2024 20:38
)
}

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.

👍🏻

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 👍🏻

@art-divin art-divin merged commit 9062519 into master Jul 15, 2024
2 checks passed
@art-divin art-divin deleted the ln/method-types branch July 15, 2024 20:45
@art-divin
Copy link
Collaborator

I'll try to release sooner than later, thank you for your contribution 🤝

@liamnichols
Copy link
Collaborator Author

Thanks @art-divin! No rush from my side, we’re fine on 2.2.4 for the time being.

I just felt like I needed to solve the issue for some closure from my debugging session today 😂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants