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

[Lint/Format] Add a rule to omit return from functions, closures, subscripts, and variables #596

Merged
merged 9 commits into from
Aug 25, 2023

Conversation

xedin
Copy link
Contributor

@xedin xedin commented Aug 21, 2023

This is an opt-in rule that would warn about a possible refactoring in lint mode and drop returns from single-expression bodies of functions, closures, subscripts and computed variables/properties.

@xedin xedin requested a review from allevato August 21, 2023 19:13
Copy link
Member

@allevato allevato left a comment

Choose a reason for hiding this comment

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

Thanks! Mainly style comments, to try to align with other changes I've been making in the code base.

let decl = super.visit(node)

// func <name>() -> <Type> { return ... }
if var funcDecl = decl.as(FunctionDeclSyntax.self),
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Here and elsewhere, can you make these kinds of conditions guards instead so that the "interesting" part of the function is at the bottom and unnested?

// func <name>() -> <Type> { return ... }
if var funcDecl = decl.as(FunctionDeclSyntax.self),
let body = funcDecl.body,
let `return` = containsSingleReturn(body.statements) {
Copy link
Member

Choose a reason for hiding this comment

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

I think it reads a little better if these variables were named returnStmt, subscriptDecl, instead of escaping just the keyword. `return` is a little ambiguous because it's not clear if it's referring to the statement or the keyword token.


diagnose(.omitReturnStatement, on: `return`, severity: .refactoring)

return .init(
Copy link
Member

Choose a reason for hiding this comment

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

At some point soon I'll be working on a modernization pass of the code base that starts doing regular mutation on nodes. Can you change this to just mutate a copy of the node and return that? For example,

var newBlock = accessorBlock
accessorBlock.accessors = .accessors(accessors.with(\.[getterAt], getter)
return newBlock

Likewise for the other branch below. This makes it easier to scan quickly and see what part of the node is being changed and what parts are staying the same.

/// Format: `func <name>() { return ... }` constructs will be replaced with
/// equivalent `func <name>() { ... }` constructs.
@_spi(Rules)
public final class OmitReturns: SyntaxFormatRule {
Copy link
Member

Choose a reason for hiding this comment

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

Can we use OmitSingleExpressionReturns as the rule name instead, so it's a little more self-descriptive?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is more confusing to me, maybe OmitExplicitReturns? Verbose version is OmitExplicitReturnsFromSingleExpressionBodies

Copy link
Member

Choose a reason for hiding this comment

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

OmitExplicitReturns sounds good to me!


extension Finding.Message {
public static let omitReturnStatement: Finding.Message =
"`return` can be omitted because body consists of a single expression"
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"`return` can be omitted because body consists of a single expression"
"remove 'return' because the body is a single expression"

Copy link
Member

Choose a reason for hiding this comment

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

(As a style choice, we use single quotes instead of backticks, since that matched Swift compiler error messages at the time. However, it also looks like diagnostics have been introduced since then that use backticks...)

return nil
}

private func unwrapReturnStmt(_ `return`: ReturnStmtSyntax) -> CodeBlockItemListSyntax {
Copy link
Member

Choose a reason for hiding this comment

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

Maybe rewrapReturnedExpression for the name of this method? It's doing more than just unwrapping it, it's also wrapping it back up in a code block item list.

@xedin
Copy link
Contributor Author

xedin commented Aug 23, 2023

Thank you, I'll try to address this today!

@xedin xedin requested a review from allevato August 24, 2023 16:43
@xedin
Copy link
Contributor Author

xedin commented Aug 24, 2023

@allevato I think I addressed all of the style/naming comments, please let me know if I missed something.

Copy link
Member

@allevato allevato left a comment

Choose a reason for hiding this comment

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

Looks great, thanks!

@allevato allevato merged commit eb6d75b into swiftlang:main Aug 25, 2023
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.

None yet

2 participants