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

New lint: Have a semicolon on the last block statement if it returns nothing #6467

Closed
xFrednet opened this issue Dec 18, 2020 · 18 comments · Fixed by #6681
Closed

New lint: Have a semicolon on the last block statement if it returns nothing #6467

xFrednet opened this issue Dec 18, 2020 · 18 comments · Fixed by #6681
Labels
A-lint Area: New lints good-first-issue These issues are a good way to get started with Clippy L-style Lint: Belongs in the style lint group T-middle Type: Probably requires verifiying types

Comments

@xFrednet
Copy link
Member

xFrednet commented Dec 18, 2020

What it does

Validates that the last block statement ends with a semicolon if it returns nothing.

Categories (optional)

  • Kind: clippy::style

Advantages

  • It leads to consistent block formatting.

  • Extending the block with new code doesn't require a change in previous last line

    Example:
    // Valid code
    {
        println!("Hello")
    }
    
    // Extending it would cause a change to the old `println!("Hello")` line
    {
        println!("Hello"); // <-- here
        println!("World")
    } 
  • It makes block linting easier for us

    • This is of course not the main reason but this causes some edge cases in a lint I'm currently working on.

Drawbacks

None.

Example

{
    println!("Hello world")
}

Could be written as:

{
    println!("Hello world");
}
@xFrednet xFrednet added the A-lint Area: New lints label Dec 18, 2020
@rustbot rustbot added L-style Lint: Belongs in the style lint group T-middle Type: Probably requires verifiying types labels Dec 18, 2020
@xFrednet
Copy link
Member Author

xFrednet commented Dec 18, 2020

I believe that this could be a good first issue. I'm not sure in which file it would be implemented by you could roughly do the following to implement this lint:

  1. Filter out any rustc_hir::Block from the ast. (Maybe with check_block)
  2. Check if the expr field is Some. (This means it has a statement without a semicolon at the end)
  3. Get the type of expr from a LateContext instance
  4. Check if the type is () with .is_unit() on the type.

@rustbot label +good first issue

@rustbot

This comment has been minimized.

@rustbot

This comment has been minimized.

@flip1995

This comment has been minimized.

@rustbot

This comment has been minimized.

@flip1995

This comment has been minimized.

@flip1995
Copy link
Member

@rustbot label +good-first-issue

@rustbot rustbot added the good-first-issue These issues are a good way to get started with Clippy label Dec 18, 2020
@flip1995
Copy link
Member

Regarding the lint level: This should probably be pedantic, since it doesn't really matter. Great explanation how to implement this @xFrednet!

@camsteffen
Copy link
Contributor

camsteffen commented Dec 18, 2020

I can't get an example for this lint to compile. Am I missing something? (playground)

@xFrednet
Copy link
Member Author

You're right @camsteffen the expression has to return the unit type () I've missed that. Thank you! I've updated the description. (playground)

@camsteffen
Copy link
Contributor

Cool. I guess the difference is that let x = ... is not an expression - it's a statement.

@xFrednet xFrednet changed the title New lint: Have a semicoln on the last block statement if it returns nothing New lint: Have a semicolon on the last block statement if it returns nothing Dec 18, 2020
@camsteffen
Copy link
Contributor

camsteffen commented Dec 18, 2020

Two questions.

  1. What if the expression does not return (), but the value is unused?
    fn test() {
        let mut set = HashSet::new();
        {
            set.insert("hi")
        }
        println!("hi");
    }
  2. Is this a job for rustfmt?

@flip1995
Copy link
Member

  1. Your example will produce a mismatched type error. You can only leave out the semicolon if the last expression in the block returns ()
  2. No idea if rustfmt does type analysis.

@camsteffen
Copy link
Contributor

Ah nevermind. I thought this might not require type checking.

@1c3t3a
Copy link
Contributor

1c3t3a commented Dec 21, 2020

I've started to implement this on my own fork but ran into an issue while testing. I first tested the lint on the println!() macro where it worked alright. Looking at assert_eq!(), my lint fired even with a ; at the end of the line. As I assumed the assert_eq!() macro implementation doesn't end with a semicolon, but the println!() macro does. I know this might be a beginner question, but is there a way to check for a semicolon after the macro invocation? I've already experimented with in_macro but it didn't quite help.

@camsteffen
Copy link
Contributor

Is the lint firing on the block that is part of the macro expansion?

macro_rules! assert_eq {
    ($left:expr, $right:expr) => ({ // <- don't lint on the block that starts here

You could do dbg!(block.span) and look at the line/column numbers to find out.

@1c3t3a
Copy link
Contributor

1c3t3a commented Dec 21, 2020

Is the lint firing on the block that is part of the macro expansion?

macro_rules! assert_eq {
    ($left:expr, $right:expr) => ({ // <- don't lint on the block that starts here

You could do dbg!(block.span) and look at the line/column numbers to find out.

Actually yes, it's exactly that line.

@camsteffen
Copy link
Contributor

If you need more help, head over to zulip.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lint Area: New lints good-first-issue These issues are a good way to get started with Clippy L-style Lint: Belongs in the style lint group T-middle Type: Probably requires verifiying types
Projects
None yet
5 participants