]>
Commit | Line | Data |
---|---|---|
cdc7bbd5 XL |
1 | use clippy_utils::diagnostics::span_lint_and_then; |
2 | use if_chain::if_chain; | |
3 | use rustc_ast::{Item, ItemKind, UseTreeKind}; | |
4 | use rustc_errors::Applicability; | |
5 | use rustc_lint::{EarlyContext, EarlyLintPass}; | |
6 | use rustc_session::{declare_lint_pass, declare_tool_lint}; | |
7 | use rustc_span::symbol::kw; | |
8 | ||
9 | declare_clippy_lint! { | |
94222f64 XL |
10 | /// ### What it does |
11 | /// Checks for imports ending in `::{self}`. | |
cdc7bbd5 | 12 | /// |
94222f64 XL |
13 | /// ### Why is this bad? |
14 | /// In most cases, this can be written much more cleanly by omitting `::{self}`. | |
cdc7bbd5 | 15 | /// |
94222f64 XL |
16 | /// ### Known problems |
17 | /// Removing `::{self}` will cause any non-module items at the same path to also be imported. | |
cdc7bbd5 XL |
18 | /// This might cause a naming conflict (https://github.com/rust-lang/rustfmt/issues/3568). This lint makes no attempt |
19 | /// to detect this scenario and that is why it is a restriction lint. | |
20 | /// | |
94222f64 | 21 | /// ### Example |
ed00b5ec | 22 | /// ```no_run |
cdc7bbd5 XL |
23 | /// use std::io::{self}; |
24 | /// ``` | |
25 | /// Use instead: | |
ed00b5ec | 26 | /// ```no_run |
cdc7bbd5 XL |
27 | /// use std::io; |
28 | /// ``` | |
a2a8927a | 29 | #[clippy::version = "1.53.0"] |
cdc7bbd5 XL |
30 | pub UNNECESSARY_SELF_IMPORTS, |
31 | restriction, | |
32 | "imports ending in `::{self}`, which can be omitted" | |
33 | } | |
34 | ||
35 | declare_lint_pass!(UnnecessarySelfImports => [UNNECESSARY_SELF_IMPORTS]); | |
36 | ||
37 | impl EarlyLintPass for UnnecessarySelfImports { | |
38 | fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { | |
39 | if_chain! { | |
40 | if let ItemKind::Use(use_tree) = &item.kind; | |
41 | if let UseTreeKind::Nested(nodes) = &use_tree.kind; | |
42 | if let [(self_tree, _)] = &**nodes; | |
43 | if let [self_seg] = &*self_tree.prefix.segments; | |
44 | if self_seg.ident.name == kw::SelfLower; | |
45 | if let Some(last_segment) = use_tree.prefix.segments.last(); | |
46 | ||
47 | then { | |
48 | span_lint_and_then( | |
49 | cx, | |
50 | UNNECESSARY_SELF_IMPORTS, | |
51 | item.span, | |
52 | "import ending with `::{self}`", | |
53 | |diag| { | |
54 | diag.span_suggestion( | |
55 | last_segment.span().with_hi(item.span.hi()), | |
56 | "consider omitting `::{self}`", | |
57 | format!( | |
58 | "{}{};", | |
59 | last_segment.ident, | |
487cf647 | 60 | if let UseTreeKind::Simple(Some(alias)) = self_tree.kind { format!(" as {alias}") } else { String::new() }, |
cdc7bbd5 XL |
61 | ), |
62 | Applicability::MaybeIncorrect, | |
63 | ); | |
64 | diag.note("this will slightly change semantics; any non-module items at the same path will also be imported"); | |
65 | }, | |
66 | ); | |
67 | } | |
68 | } | |
69 | } | |
70 | } |