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

Unnecessary return as last statement in void method #388

Merged
merged 21 commits into from
Nov 25, 2024

Conversation

mccartney
Copy link
Contributor

@mccartney mccartney commented Nov 17, 2024

What's changed?

Adding a new recipe to remove return if it's the last statement of a void method.

What's your motivation?

Checklist

  • I've added unit tests to cover both positive and negative cases
  • I've read and applied the recipe conventions and best practices
  • I've used the IntelliJ IDEA auto-formatter on affected files

mccartney and others added 2 commits November 17, 2024 17:01
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Statement lastStatement = statements.get(statements.size() - 1);
List<Statement> allButLast = statements.subList(0, statements.size() - 1);
if (lastStatement instanceof J.Return) {
return b.withStatements(allButLast);
Copy link
Contributor

Choose a reason for hiding this comment

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

One thing I am missing here is the check if the return has an expression or not.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right. There's no check for void return type.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In bcc951a adding two lines of defense:

  • the whole method being a void method
  • the return expression having an empty expression

Not fully sure if you prefer to have both (I've checked both work alone).

Copy link
Contributor

@knutwannheden knutwannheden left a comment

Choose a reason for hiding this comment

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

I think some more tests would be good. For example removing the return here would be correct:

        Consumer<Integer> c = i -> {
            return;
        };

while removing the return here would not be correct:

        while (true) {
            return;
        }

Although it could also be argued that changing the first is incorrect, as it is a return from a lambda rather than a method and that isn't how the recipe is documented.

@timtebeek timtebeek marked this pull request as draft November 18, 2024 10:49
@mccartney
Copy link
Contributor Author

I think some more tests would be good.

Added some in 3325148.

Kindly requesting another review.

@mccartney
Copy link
Contributor Author

BTW, is there some easy way to run the Code Suggester locally to avoid the noise in the pull request itself?

@mccartney mccartney marked this pull request as ready for review November 19, 2024 19:36
@timtebeek
Copy link
Contributor

BTW, is there some easy way to run the Code Suggester locally to avoid the noise in the pull request itself?

Yes sure! What I've done is take this file and put it in scratch, then run it through the IntelliJ Ultimate bundled support for OpenRewrite.

@timtebeek
Copy link
Contributor

Had another look; thanks so far @mccartney ; Since I think you'll enjoy the puzzle I've added a new unit test that fails. Let me know if you can't or won't enjoy working it out. :)

@mccartney mccartney marked this pull request as draft November 19, 2024 21:39
@mccartney
Copy link
Contributor Author

Since I think you'll enjoy the puzzle I've added a new unit test that fails.

b48dd6a

@timtebeek timtebeek force-pushed the return-as-last-statement branch from 55a093c to 6ba0e18 Compare November 20, 2024 23:42
Copy link
Contributor

@timtebeek timtebeek left a comment

Choose a reason for hiding this comment

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

Approved from my side already; thanks for the thorough tests!

I've replaced the three methods you had with the same name but different arguments with a single recursive method, as the flow was harder to follow across those individual methods.

@timtebeek timtebeek marked this pull request as ready for review November 20, 2024 23:48
@timtebeek
Copy link
Contributor

Saving others a click: unrelated test failure now in:

RemoveRedundantTypeCastTest > changeTypeCastInReturn() FAILED
    org.opentest4j.AssertionFailedError: [Expected recipe to complete in 0 cycles, but took at least one more cycle. Between the last two executed cycles there were changes to "Test.java"] 

@knutwannheden
Copy link
Contributor

Saving others a click: unrelated test failure now in:

RemoveRedundantTypeCastTest > changeTypeCastInReturn() FAILED
    org.opentest4j.AssertionFailedError: [Expected recipe to complete in 0 cycles, but took at least one more cycle. Between the last two executed cycles there were changes to "Test.java"] 

Indeed. I've been struggling for a while with that TypeUtils#isAssignableTo(), where I've so far neglected the fact that we also need to consider the "direction" of the assignability. While we can assign a List<String> type to <T extends Collection<String>> when passing in a parameter, the same doesn't work when assigning a local variable. I will add an overload with an additional direction parameter, so that we stay backwards compatible.

@knutwannheden
Copy link
Contributor

knutwannheden commented Nov 21, 2024

The type assignability check in Java is tricky. I think we might even have some cases where we can't do it correctly, as we don't have all the information we need in our type attribution. In any case I think this PR should now fix the test failure we have here:

@timtebeek timtebeek self-requested a review November 21, 2024 14:35
@mccartney
Copy link
Contributor Author

If I read the GHA output correctly, the failure is with:

InstanceOfPatternMatchTest > If > typeParameters_3() FAILED
    org.opentest4j.AssertionFailedError: [Expected recipe to complete in 0 cycles, but took at least one more cycle. Between the last two executed cycles there were changes to "A.java"] 
    expected: 

now.

@knutwannheden
Copy link
Contributor

That was resolved on main. I just merged in the main branch.

@timtebeek
Copy link
Contributor

@knutwannheden any last thoughts before we merge?

Copy link
Contributor

@knutwannheden knutwannheden left a comment

Choose a reason for hiding this comment

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

LGTM.

@timtebeek timtebeek merged commit b6df08d into openrewrite:main Nov 25, 2024
2 checks passed
@timtebeek
Copy link
Contributor

Thanks both! As a quick check I'm running this recipe against all Apache projects: https://app.moderne.io/results/5TXPCrrF0
Welcome to use the platform to explore the results, or even push the recipe suggested improvements to other projects! :)

@knutwannheden
Copy link
Contributor

All the changes in that recipe run look good to me.

@mccartney
Copy link
Contributor Author

As a quick check I'm running this recipe against all Apache projects: https://app.moderne.io/results/5TXPCrrF0
Welcome to use the platform to explore the results, or even push the recipe suggested improvements to other projects!

I am hesitant to do this as the Moderne app requires kind of generous permissions (read/write code to all my private repos) to even see the changes.

@mccartney mccartney deleted the return-as-last-statement branch November 25, 2024 17:10
@timtebeek
Copy link
Contributor

Rest assured we're not after your private projects at all; we merely need access to your email address to identify you, and then access to your projects if you choose to fork any OSS projects. I do see how the dialog could come across differently; we're exploring options on our side for that in parallel, but there should be no reason not to use the platform.

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

Successfully merging this pull request may close these issues.

Recipe: return is unnecessary as the last statement in a void method
3 participants