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 unnecessary_self_imports lint #7072

Merged
merged 1 commit into from
Apr 21, 2021

Conversation

ebobrow
Copy link
Contributor

@ebobrow ebobrow commented Apr 13, 2021

fixes #6552

changelog: add unnecessary_self_imports lint

@rust-highfive
Copy link

r? @camsteffen

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Apr 13, 2021
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.

The functions you implement to check if something is in scope seem really resource intensive to me. Have you looked in rustc if there is a query to determine if a item is in scope?

clippy_lints/src/unnecessary_self_imports.rs Outdated Show resolved Hide resolved
clippy_lints/src/unnecessary_self_imports.rs Outdated Show resolved Hide resolved
clippy_lints/src/unnecessary_self_imports.rs Outdated Show resolved Hide resolved
clippy_lints/src/unnecessary_self_imports.rs Outdated Show resolved Hide resolved
clippy_lints/src/unnecessary_self_imports.rs Outdated Show resolved Hide resolved
clippy_lints/src/unnecessary_self_imports.rs Outdated Show resolved Hide resolved
@flip1995
Copy link
Member

TL;DR: Implement this lint on the AST, not the HIR. It'll be way easier.

I just noticed that you can't really implement this lint on the HIR, since the information if a self was involved in an import isn't available there anymore. It just gets lowered to

use path::to::module::{}; 
use path::to::module;

However on the AST you should be able to determine if it is an import of just self and if it has a as something pretty easily

AST `use` expansion
        Item {
            attrs: [],
            id: NodeId(4294967040),
            span: main.rs:5:1: 5:15 (#0),
            vis: Visibility {
                kind: Inherited,
                span: main.rs:5:1: 5:1 (#0),
                tokens: None,
            },
            ident: #0,
            kind: Use(
                UseTree {
                    prefix: Path {
                        span: main.rs:5:5: 5:6 (#0),
                        segments: [
                            PathSegment {
                                ident: a#0,
                                id: NodeId(4294967040),
                                args: None,
                            },
                        ],
                        tokens: None,
                    },
                    kind: Nested(
                        [
                            (
                                UseTree {
                                    prefix: Path {
                                        span: main.rs:5:9: 5:13 (#0),
                                        segments: [
                                            PathSegment {
                                                ident: self#0,
                                                id: NodeId(4294967040),
                                                args: None,
                                            },
                                        ],
                                        tokens: None,
                                    },
                                    kind: Simple(
                                        None,
                                        NodeId(4294967040),
                                        NodeId(4294967040),
                                    ),
                                    span: main.rs:5:9: 5:13 (#0),
                                },
                                NodeId(4294967040),
                            ),
                        ],
                    ),
                    span: main.rs:5:5: 5:14 (#0),
                },
            ),
            tokens: None,
        },

UseTree Documentation

You'll then have the problem to determine if the imported module is already there in form of another item (at least I think that is what you try to do with the other 2 functions?). But this isn't really a problem. rustc will already error if it is. And if you have an alias, you can just remove the self and use use path::to::module as alias directly.

@camsteffen
Copy link
Contributor

camsteffen commented Apr 14, 2021

It's a bit more complicated.

  • use a::b::{self} -> import the module a::b
  • use a::b; -> import the module and/or item a::b

So changing to the latter may cause "b is defined multiple times". (playground)

I think a late pass will be necessary to detect this. And UseKind::ListStem can maybe be used to detect ::{self}? Not sure. Seems hacky.

@flip1995
Copy link
Member

flip1995 commented Apr 14, 2021

* `use a::b;` -> import the module and/or item `a::b`

Checking another case which shouldn't be a concern for this lint: Playground

So you only have to check which items are loaded in the current module. So instead of checking every use item you can just check on module level and walk over all items and lint on use items iff they aren't in scope in another form.

(That is on the AST. I really don't think we can implement this lint on the HIR reliably)

@ebobrow
Copy link
Contributor Author

ebobrow commented Apr 15, 2021

Couldn't self still be removed if an item with the same name exists in scope but not in the module? I'm not sure how to check modules in the AST.

@flip1995
Copy link
Member

Oh yeah, your right. The item could still be in scope from the surrounding scope... I'm starting to think that there is no feasible way to implement this. Your method works, but I hope that you agree that going over all defined items multiple times is too performance heavy.

Determining what would happen if we change code without recompiling is just really hard in general.

I see two ways going forward:

  1. Not adding this lint. I'm not sure how helpful this lint is in the first place. When someone uses ::{self} it is either intentional or just a refactor artifact. It doesn't hurt to have it. An expensive lint for code style isn't justified IMO.
  2. Ignore that the item could already be in scope and implement it as a restriction lint with a statement in the documentation that this lint isn't meant to be permanently enabled, but only to quickly check, e.g. after refactoring, if there are artifacts like this in the code.

@camsteffen
Copy link
Contributor

if an item with the same name exists in scope but not in the module

I'm not following...

@ebobrow
Copy link
Contributor Author

ebobrow commented Apr 16, 2021

Playground

I think @flip1995 is right. On the HIR, this lint is too resource intensive and it might not be possible on the AST. I don't know if it's worthwhile to have.

@camsteffen
Copy link
Contributor

Hrrrmmm. Yeeahh. mrr

@flip1995
Copy link
Member

if an item with the same name exists in scope but not in the module

I'm not following...

Or maybe not... Playground

Anyway, this is way too scuffed to figure out what works and what doesn't when the ::{self} might get removed to make it FP free.

@camsteffen
Copy link
Contributor

Yes too scuffed! I can imagine the restriction lint begin useful as in "if removing ::{self} breaks something, you're doing it wrong."

@ebobrow
Copy link
Contributor Author

ebobrow commented Apr 16, 2021

Good point. I'll change this to a restriction lint and put a warning in the documentation.

@ebobrow ebobrow force-pushed the imports-ending-with-self branch 2 times, most recently from cf4223e to cf2b2b9 Compare April 16, 2021 21:14
@camsteffen
Copy link
Contributor

camsteffen commented Apr 16, 2021

I think we should also

diag.span_note("this will slightly change semantics; any non-module items at the same path will also be imported");

/// **Why is this bad?** In most cases, this can be written much more cleanly by omitting `self`.
///
/// **Known problems:** Sometimes removing `::{self}` will break code (https:/rust-lang/rustfmt/issues/3568).
/// This lint should not be permanently enabled.
Copy link
Contributor

Choose a reason for hiding this comment

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

It's not necessarily wrong to enable the lint for a project.

Copy link
Contributor

@camsteffen camsteffen left a comment

Choose a reason for hiding this comment

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

Just some nits.

clippy_lints/src/unnecessary_self_imports.rs Outdated Show resolved Hide resolved
clippy_lints/src/unnecessary_self_imports.rs Outdated Show resolved Hide resolved
clippy_lints/src/unnecessary_self_imports.rs Outdated Show resolved Hide resolved
clippy_lints/src/unnecessary_self_imports.rs Outdated Show resolved Hide resolved
clippy_lints/src/unnecessary_self_imports.rs Outdated Show resolved Hide resolved
clippy_lints/src/unnecessary_self_imports.rs Outdated Show resolved Hide resolved
clippy_lints/src/unnecessary_self_imports.rs Outdated Show resolved Hide resolved
clippy_lints/src/unnecessary_self_imports.rs Outdated Show resolved Hide resolved
clippy_lints/src/unnecessary_self_imports.rs Outdated Show resolved Hide resolved
tests/ui/unnecessary_self_imports.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@camsteffen camsteffen left a comment

Choose a reason for hiding this comment

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

One more minor suggestion that you can take or leave. Otherwise looks good!

clippy_lints/src/unnecessary_self_imports.rs Outdated Show resolved Hide resolved
@ebobrow
Copy link
Contributor Author

ebobrow commented Apr 21, 2021

Thanks! I like that.

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.

LGTM now. @camsteffen if you're also ok with this PR, please go ahead and merge it.

@ebobrow Thanks for all your work on it, even though you had to delete most of it again. But now we learned what information about imports are available where, which will help us advising on issues about imports in the future,, which is definitely a win.

@camsteffen
Copy link
Contributor

@bors r+

@bors
Copy link
Collaborator

bors commented Apr 21, 2021

📌 Commit 224881b has been approved by camsteffen

@bors
Copy link
Collaborator

bors commented Apr 21, 2021

⌛ Testing commit 224881b with merge 79b9eb5...

@bors
Copy link
Collaborator

bors commented Apr 21, 2021

☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test
Approved by: camsteffen
Pushing 79b9eb5 to master...

@bors bors merged commit 79b9eb5 into rust-lang:master Apr 21, 2021
@ebobrow ebobrow deleted the imports-ending-with-self branch April 21, 2021 15:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties
Projects
None yet
Development

Successfully merging this pull request may close these issues.

A new lint for imports ending in ::{self};
5 participants