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

Add new lint: match with a single binding statement #5061

Merged
merged 5 commits into from
Feb 4, 2020

Conversation

ThibsG
Copy link
Contributor

@ThibsG ThibsG commented Jan 18, 2020

This lint catches match statements that binds to only one block and could be rewritten using a simple let statement.

Lint name: MATCH_SINGLE_BINDING

fixes: #3664

changelog: add lint for match with single binding statement

@ThibsG ThibsG changed the title Add new lint: match with a single binding statement [WIP] Add new lint: match with a single binding statement Jan 18, 2020
@flip1995
Copy link
Member

IMO suggesting

let x = y;
{ 
    // match body using `x`
} 

Is the best thing we could do here. Detecting if the let binding is necessary after rewriting the match expression is to hard to do. And only suggesting the match body breaks the code, when auto fixed

@flip1995
Copy link
Member

You can also use 2 different spans for the lint and the suggestion with span_lint_and_then. The first span is for the faulty code, the second for the code that will be replaced when applying the suggestion

@ThibsG
Copy link
Contributor Author

ThibsG commented Jan 19, 2020

Thanks a lot !
Indeed it's better now, thought I can do better about the auto fix it provides:

    let x = a;
{
    println!("{}", x);
}

I still need to fix let assignment based for this kind of match (infallible_destructuring_match lint colliding)

Copy link
Member

@flip1995 flip1995 left a comment

Choose a reason for hiding this comment

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

Suggestion is fine as it is. Adding indentation to the suggestion is a bit out off scope for Clippy currently. This has to be handled by rustfmt afterwards.

I still need to fix let assignment based for this kind of match (infallible_destructuring_match lint colliding)

What you can do to fix is this is:

  1. Move infallible_destructuring_match into the Matches lint pass, by copying the check_local method incl. lint declaration, ... to the matches.rs module.
  2. Use impl_lint_pass! macro, instead of declare_lint_pass and define
    #[derive(Default)]
    pub struct Matches {
        infallible_destructuring_match_linted: bool // or a better name
    }
  3. When the infallible_destructuring_match lint triggers, set self.infallible_destructuring_match_linted = true
  4. Condition the check_match_single_binding(cx, ex, arms, expr); on self.infallible_destructuring_match_linted:
    if self.infallible_destructuring_match_linted {
        self.infallible_destructuring_match_linted = false;
    } else {
        check_match_single_binding(cx, ex, arms, expr);
    }

clippy_lints/src/matches.rs Outdated Show resolved Hide resolved
clippy_lints/src/matches.rs Outdated Show resolved Hide resolved
@ThibsG ThibsG changed the title [WIP] Add new lint: match with a single binding statement Add new lint: match with a single binding statement Jan 19, 2020
Copy link
Member

@flip1995 flip1995 left a comment

Choose a reason for hiding this comment

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

With my suggestion below, you should be able to revert commit 6f7e035 without failing the dogfood test.

clippy_lints/src/matches.rs Show resolved Hide resolved
clippy_lints/src/matches.rs Show resolved Hide resolved
clippy_lints/src/matches.rs Outdated Show resolved Hide resolved
@bors
Copy link
Collaborator

bors commented Jan 23, 2020

☔ The latest upstream changes (presumably #4945) made this pull request unmergeable. Please resolve the merge conflicts.

@flip1995 flip1995 added the S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) label Jan 23, 2020
@ThibsG ThibsG force-pushed the UselessMatch3664 branch 2 times, most recently from b93c3f6 to 81c5cd6 Compare January 26, 2020 18:28
@ThibsG
Copy link
Contributor Author

ThibsG commented Jan 26, 2020

Is there a way to make a clean distinction between:

match x {
    _ => println!("..."),
}

and

match x {
    _ => {
        println!("...");
    }
}

I don't like very much my solution to add semi-colon to body expression if needed (first println! in my case).

@flip1995
Copy link
Member

flip1995 commented Jan 26, 2020

You could just check if the match_body expression is of ExprKind::Block. If it is, you do not have to add a semicolon. If it is not, you have to add a semicolon, iff expr_ty(match_body) == ().

Let's go through the cases:

  1. match _ { ... }; match with ; (fallback case): You just replace the match _ {}, so the ; is already there => all good
  2. match _ { a => {} }:
    2a. match _ { a => { x; } }: match_body = "{ x; }" => all good
    2b. match _ { a => { x } }:
    2b(i). match_body = "x" && expr_ty(x) == (): Add a ; to the expression
    2b(ii). match_body = "x" && expr_ty(x) != (): The match expr either returns x or has a ; after it (1.) => all good
    2c. match _ { a => { x; ... y } }: match_body = "{ x; ... y }", either the match returns or (1.) => all good
  3. match _ { a => x, }: Same as (2b.)

See cx.tables.expr_ty

clippy_lints/src/matches.rs Outdated Show resolved Hide resolved
@bors
Copy link
Collaborator

bors commented Jan 27, 2020

☔ The latest upstream changes (presumably #5098) made this pull request unmergeable. Please resolve the merge conflicts.

 - Lint name: MATCH_SINGLE_BINDING
clippy_lints/src/matches.rs Outdated Show resolved Hide resolved
clippy_lints/src/matches.rs Outdated Show resolved Hide resolved
Copy link
Member

@flip1995 flip1995 left a comment

Choose a reason for hiding this comment

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

Thanks! Can you squash some commits? After that, this should be ready to merge.

@ThibsG
Copy link
Contributor Author

ThibsG commented Feb 4, 2020

Here you go !

Thanks a lot for hints and patience 😆

@flip1995
Copy link
Member

flip1995 commented Feb 4, 2020

@bors r+

Thanks for the contribution!

@bors
Copy link
Collaborator

bors commented Feb 4, 2020

📌 Commit 00904cb has been approved by flip1995

@bors
Copy link
Collaborator

bors commented Feb 4, 2020

⌛ Testing commit 00904cb with merge 298df70...

bors added a commit that referenced this pull request Feb 4, 2020
Add new lint: match with a single binding statement

This lint catches `match` statements that binds to only one block and could be rewritten using a simple `let` statement.

Lint name: MATCH_SINGLE_BINDING

fixes: #3664

changelog: add lint for match with single binding statement
@bors
Copy link
Collaborator

bors commented Feb 4, 2020

☀️ Test successful - checks-travis, status-appveyor
Approved by: flip1995
Pushing 298df70 to master...

@bors bors merged commit 00904cb into rust-lang:master Feb 4, 2020
@ThibsG ThibsG deleted the UselessMatch3664 branch February 5, 2020 08:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Warn about useless matches
5 participants