-
Notifications
You must be signed in to change notification settings - Fork 1.7k
new lint: needless traits in scope #10503
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
Closed
Closed
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
fb4bacb
new lint: needless traits in scope
woshilapin 2e082ba
fix: check if the used path is a trait
woshilapin 02db985
fix: needless_traits_in_scope should be a 'restriction' lint
woshilapin ef7fac2
docs: improve description for needless_traits_in_scope
woshilapin a6e854e
docs: trait are in type namespace (not trait namespace)
woshilapin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 into the type 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 into the type namespace, and can be anonymously imported" | ||
} | ||
declare_lint_pass!(NeedlessTraitsInScope => [NEEDLESS_TRAITS_IN_SCOPE]); | ||
|
||
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 into the type namespace", | ||
"you can import the trait anonymously", | ||
format!("{path} as _"), | ||
Applicability::MachineApplicable, | ||
); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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 aVisitor
to your LintPass that you use oncheck_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.