Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4759,6 +4759,7 @@ Released 2018-09-13
[`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop
[`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
[`needless_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_splitn
[`needless_traits_in_scope`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_traits_in_scope
[`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update
[`neg_cmp_op_on_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_cmp_op_on_partial_ord
[`neg_multiply`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_multiply
Expand Down
1 change: 1 addition & 0 deletions clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO,
crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO,
crate::needless_question_mark::NEEDLESS_QUESTION_MARK_INFO,
crate::needless_traits_in_scope::NEEDLESS_TRAITS_IN_SCOPE_INFO,
crate::needless_update::NEEDLESS_UPDATE_INFO,
crate::neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD_INFO,
crate::neg_multiply::NEG_MULTIPLY_INFO,
Expand Down
2 changes: 2 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ mod needless_late_init;
mod needless_parens_on_range_literals;
mod needless_pass_by_value;
mod needless_question_mark;
mod needless_traits_in_scope;
mod needless_update;
mod neg_cmp_op_on_partial_ord;
mod neg_multiply;
Expand Down Expand Up @@ -934,6 +935,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(missing_assert_message::MissingAssertMessage));
store.register_early_pass(|| Box::new(redundant_async_block::RedundantAsyncBlock));
store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped));
store.register_late_pass(|_| Box::new(needless_traits_in_scope::NeedlessTraitsInScope));
// add lints here, do not remove this comment, it's used in `new_lint`
}

Expand Down
86 changes: 86 additions & 0 deletions clippy_lints/src/needless_traits_in_scope.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use rustc_errors::Applicability;
use rustc_hir::*;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
/// ### What it does
/// Find traits that are not explicitely used in scope (like `AsRef::as_ref()`)
/// but directly with the trait method (like `opt.as_ref()`).
///
/// These traits can be imported anonymously with `use crate::Trait as _`.
/// This avoids name collision with other traits (possibly with the same name).
/// It also helps identify the traits in `use` statements.
///
/// ### Why is this bad?
/// This needlessly brings a trait in trait's namespace, where it could
/// shadow other things. This is not really a problem, this lint is just
/// for those who like to keep things tidy.
///
/// ### Example
/// ```rust
/// use std::io::Read;
/// fn main() {
/// let mut b = "I'm your father!".as_bytes();
/// let mut buffer = [0; 10];
/// b.read(&mut buffer)
/// }
/// ```
/// Use instead:
/// ```rust
/// use std::io::Read as _;
/// fn main() {
/// let mut b = "I'm your father!".as_bytes();
/// let mut buffer = [0; 10];
/// b.read(&mut buffer)
/// }
/// ```
#[clippy::version = "1.69.0"]
pub NEEDLESS_TRAITS_IN_SCOPE,
restriction,
"trait is needlessly imported in trait's namespace, and can be anonymously imported"
}
declare_lint_pass!(NeedlessTraitsInScope => [NEEDLESS_TRAITS_IN_SCOPE]);
Copy link
Contributor

Choose a reason for hiding this comment

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

You'll want to write your own struct so you can impl_lint_pass! here instead. Then you can add a Visitor to your LintPass that you use on check_crate to run through the code and collect any trait use. Please leave a comment or ping me on zulip if you need help with that.


impl<'tcx> LateLintPass<'tcx> for NeedlessTraitsInScope {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
// Only process `use` statements, ignore `UseKind::Glob`
let ItemKind::Use(use_path, UseKind::Single) = item.kind else {
return
};
// Check if it's a trait
if !use_path
.res
.iter()
.any(|res| matches!(res, def::Res::Def(def::DefKind::Trait, _)))
{
return;
}
// Check if the `use` is aliased with ` as `.
// If aliased, then do not process, it's probably for a good reason
if item.ident != use_path.segments.last().unwrap().ident {
return;
}
let path = use_path
.segments
.iter()
.map(|segment| segment.ident)
.fold(String::new(), |mut acc, ident| {
if !acc.is_empty() {
acc += "::";
}
acc += ident.as_str();
acc
});
span_lint_and_sugg(
cx,
NEEDLESS_TRAITS_IN_SCOPE,
use_path.span,
"trait is needlessly imported in trait's namespace",
"you can import the trait anonymously",
format!("{path} as _"),
Applicability::MachineApplicable,
);
}
}
52 changes: 52 additions & 0 deletions tests/ui/needless_traits_in_scope.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// run-rustfix
#![allow(unused)]
#![warn(clippy::needless_traits_in_scope)]

pub mod useless_trait_in_scope {
use std::io::Read as _;

pub fn warn() -> std::io::Result<usize> {
let mut b = "The trait is not used explicitely -> 'use std::io::Read' doesn't need to be in scope".as_bytes();
let mut buffer = [0; 10];
b.read(&mut buffer)
}
}

pub mod trait_not_in_scope {
use std::io::Read as _;

pub fn ok() -> std::io::Result<usize> {
let mut b = "The trait is not used explicitely, but 'use std::io::Read' is already not in scope".as_bytes();
let mut buffer = [0; 10];
b.read(&mut buffer)
}
}

pub mod is_not_a_trait {
mod inner {
pub struct Read;
}
use inner::Read;

pub fn ok() {
let _ = Read;
}
}

// FIXME: when the trait is explicitely used, the lint should not trigger
// pub mod useful_trait_in_scope {
// use std::io::Read;

// pub fn ok() -> std::io::Result<usize> {
// let mut b = "Trait is used explicitely -> 'use std::io::Read' is OK".as_bytes();
// let mut buffer = [0; 10];
// Read::read(&mut b, &mut buffer)
// }
// }

fn main() {
useless_trait_in_scope::warn();
trait_not_in_scope::ok();
is_not_a_trait::ok();
// useful_trait_in_scope::ok();
}
52 changes: 52 additions & 0 deletions tests/ui/needless_traits_in_scope.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// run-rustfix
#![allow(unused)]
#![warn(clippy::needless_traits_in_scope)]

pub mod useless_trait_in_scope {
use std::io::Read;

pub fn warn() -> std::io::Result<usize> {
let mut b = "The trait is not used explicitely -> 'use std::io::Read' doesn't need to be in scope".as_bytes();
let mut buffer = [0; 10];
b.read(&mut buffer)
}
}

pub mod trait_not_in_scope {
use std::io::Read as _;

pub fn ok() -> std::io::Result<usize> {
let mut b = "The trait is not used explicitely, but 'use std::io::Read' is already not in scope".as_bytes();
let mut buffer = [0; 10];
b.read(&mut buffer)
}
}

pub mod is_not_a_trait {
mod inner {
pub struct Read;
}
use inner::Read;

pub fn ok() {
let _ = Read;
}
}

// FIXME: when the trait is explicitely used, the lint should not trigger
// pub mod useful_trait_in_scope {
// use std::io::Read;

// pub fn ok() -> std::io::Result<usize> {
// let mut b = "Trait is used explicitely -> 'use std::io::Read' is OK".as_bytes();
// let mut buffer = [0; 10];
// Read::read(&mut b, &mut buffer)
// }
// }

fn main() {
useless_trait_in_scope::warn();
trait_not_in_scope::ok();
is_not_a_trait::ok();
// useful_trait_in_scope::ok();
}
10 changes: 10 additions & 0 deletions tests/ui/needless_traits_in_scope.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: trait is needlessly imported in trait's namespace
--> $DIR/needless_traits_in_scope.rs:6:9
|
LL | use std::io::Read;
| ^^^^^^^^^^^^^ help: you can import the trait anonymously: `std::io::Read as _`
|
= note: `-D clippy::needless-traits-in-scope` implied by `-D warnings`

error: aborting due to previous error