diff --git a/CHANGELOG.md b/CHANGELOG.md index 7885bdfb12c2..d9a198f8243a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2519,6 +2519,7 @@ Released 2018-09-13 [`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation +[`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports [`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap [`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 78a95b004034..7e12e9be4aa3 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -356,6 +356,7 @@ mod unicode; mod unit_return_expecting_ord; mod unit_types; mod unnamed_address; +mod unnecessary_self_imports; mod unnecessary_sort_by; mod unnecessary_wraps; mod unnested_or_patterns; @@ -963,6 +964,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: unit_types::UNIT_CMP, unnamed_address::FN_ADDRESS_COMPARISONS, unnamed_address::VTABLE_ADDRESS_COMPARISONS, + unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS, unnecessary_sort_by::UNNECESSARY_SORT_BY, unnecessary_wraps::UNNECESSARY_WRAPS, unnested_or_patterns::UNNESTED_OR_PATTERNS, @@ -1048,6 +1050,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box default_numeric_fallback::DefaultNumericFallback); store.register_late_pass(|| box inconsistent_struct_constructor::InconsistentStructConstructor); store.register_late_pass(|| box non_octal_unix_permissions::NonOctalUnixPermissions); + store.register_early_pass(|| box unnecessary_self_imports::UnnecessarySelfImports); let msrv = conf.msrv.as_ref().and_then(|s| { parse_msrv(s, None, None).or_else(|| { @@ -1320,6 +1323,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(strings::STRING_TO_STRING), LintId::of(strings::STR_TO_STRING), LintId::of(types::RC_BUFFER), + LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS), LintId::of(unwrap_in_result::UNWRAP_IN_RESULT), LintId::of(verbose_file_reads::VERBOSE_FILE_READS), LintId::of(write::PRINT_STDERR), diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs index 6a52de4f7136..64e9dc85466e 100644 --- a/clippy_lints/src/modulo_arithmetic.rs +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -4,7 +4,7 @@ use clippy_utils::sext; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::fmt::Display; diff --git a/clippy_lints/src/unnecessary_self_imports.rs b/clippy_lints/src/unnecessary_self_imports.rs new file mode 100644 index 000000000000..48c54d79cf11 --- /dev/null +++ b/clippy_lints/src/unnecessary_self_imports.rs @@ -0,0 +1,67 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use if_chain::if_chain; +use rustc_ast::{Item, ItemKind, UseTreeKind}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::kw; + +declare_clippy_lint! { + /// **What it does:** Checks for imports ending in `::{self}`. + /// + /// **Why is this bad?** In most cases, this can be written much more cleanly by omitting `::{self}`. + /// + /// **Known problems:** Removing `::{self}` will cause any non-module items at the same path to also be imported. + /// This might cause a naming conflict (https://github.com/rust-lang/rustfmt/issues/3568). This lint makes no attempt + /// to detect this scenario and that is why it is a restriction lint. + /// + /// **Example:** + /// + /// ```rust + /// use std::io::{self}; + /// ``` + /// Use instead: + /// ```rust + /// use std::io; + /// ``` + pub UNNECESSARY_SELF_IMPORTS, + restriction, + "imports ending in `::{self}`, which can be omitted" +} + +declare_lint_pass!(UnnecessarySelfImports => [UNNECESSARY_SELF_IMPORTS]); + +impl EarlyLintPass for UnnecessarySelfImports { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + if_chain! { + if let ItemKind::Use(use_tree) = &item.kind; + if let UseTreeKind::Nested(nodes) = &use_tree.kind; + if let [(self_tree, _)] = &**nodes; + if let [self_seg] = &*self_tree.prefix.segments; + if self_seg.ident.name == kw::SelfLower; + if let Some(last_segment) = use_tree.prefix.segments.last(); + + then { + span_lint_and_then( + cx, + UNNECESSARY_SELF_IMPORTS, + item.span, + "import ending with `::{self}`", + |diag| { + diag.span_suggestion( + last_segment.span().with_hi(item.span.hi()), + "consider omitting `::{self}`", + format!( + "{}{};", + last_segment.ident, + if let UseTreeKind::Simple(Some(alias), ..) = self_tree.kind { format!(" as {}", alias) } else { String::new() }, + ), + Applicability::MaybeIncorrect, + ); + diag.note("this will slightly change semantics; any non-module items at the same path will also be imported"); + }, + ); + } + } + } +} diff --git a/tests/ui/unnecessary_self_imports.fixed b/tests/ui/unnecessary_self_imports.fixed new file mode 100644 index 000000000000..1185eaa1d552 --- /dev/null +++ b/tests/ui/unnecessary_self_imports.fixed @@ -0,0 +1,10 @@ +// run-rustfix +#![warn(clippy::unnecessary_self_imports)] +#![allow(unused_imports, dead_code)] + +use std::collections::hash_map::{self, *}; +use std::fs as alias; +use std::io::{self, Read}; +use std::rc; + +fn main() {} diff --git a/tests/ui/unnecessary_self_imports.rs b/tests/ui/unnecessary_self_imports.rs new file mode 100644 index 000000000000..56bfbc09402a --- /dev/null +++ b/tests/ui/unnecessary_self_imports.rs @@ -0,0 +1,10 @@ +// run-rustfix +#![warn(clippy::unnecessary_self_imports)] +#![allow(unused_imports, dead_code)] + +use std::collections::hash_map::{self, *}; +use std::fs::{self as alias}; +use std::io::{self, Read}; +use std::rc::{self}; + +fn main() {} diff --git a/tests/ui/unnecessary_self_imports.stderr b/tests/ui/unnecessary_self_imports.stderr new file mode 100644 index 000000000000..83a5618c983d --- /dev/null +++ b/tests/ui/unnecessary_self_imports.stderr @@ -0,0 +1,23 @@ +error: import ending with `::{self}` + --> $DIR/unnecessary_self_imports.rs:6:1 + | +LL | use std::fs::{self as alias}; + | ^^^^^^^^^-------------------- + | | + | help: consider omitting `::{self}`: `fs as alias;` + | + = note: `-D clippy::unnecessary-self-imports` implied by `-D warnings` + = note: this will slightly change semantics; any non-module items at the same path will also be imported + +error: import ending with `::{self}` + --> $DIR/unnecessary_self_imports.rs:8:1 + | +LL | use std::rc::{self}; + | ^^^^^^^^^----------- + | | + | help: consider omitting `::{self}`: `rc;` + | + = note: this will slightly change semantics; any non-module items at the same path will also be imported + +error: aborting due to 2 previous errors +