Skip to content

Commit

Permalink
add lint: could_be_assoc_type_bounds
Browse files Browse the repository at this point in the history
  • Loading branch information
y21 committed Nov 26, 2024
1 parent d49501c commit 10ed145
Show file tree
Hide file tree
Showing 20 changed files with 1,046 additions and 26 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5410,6 +5410,7 @@ Released 2018-09-13
[`const_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_is_empty
[`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime
[`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
[`could_be_assoc_type_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#could_be_assoc_type_bounds
[`crate_in_macro_def`]: https://rust-lang.github.io/rust-clippy/master/index.html#crate_in_macro_def
[`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir
[`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute
Expand Down
674 changes: 674 additions & 0 deletions clippy_lints/src/could_be_assoc_type_bounds.rs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
crate::copies::IF_SAME_THEN_ELSE_INFO,
crate::copies::SAME_FUNCTIONS_IN_IF_CONDITION_INFO,
crate::copy_iterator::COPY_ITERATOR_INFO,
crate::could_be_assoc_type_bounds::COULD_BE_ASSOC_TYPE_BOUNDS_INFO,
crate::crate_in_macro_def::CRATE_IN_MACRO_DEF_INFO,
crate::create_dir::CREATE_DIR_INFO,
crate::dbg_macro::DBG_MACRO_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 @@ -100,6 +100,7 @@ mod collection_is_never_read;
mod comparison_chain;
mod copies;
mod copy_iterator;
mod could_be_assoc_type_bounds;
mod crate_in_macro_def;
mod create_dir;
mod dbg_macro;
Expand Down Expand Up @@ -963,5 +964,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_late_pass(|_| Box::new(manual_ignore_case_cmp::ManualIgnoreCaseCmp));
store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound));
store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf)));
store.register_late_pass(move |_| Box::new(could_be_assoc_type_bounds::ManualAssocTypeBounds::new(conf)));
// add lints here, do not remove this comment, it's used in `new_lint`
}
2 changes: 1 addition & 1 deletion clippy_utils/src/hir_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ impl HirEqInterExpr<'_, '_, '_> {
left.ident.name == right.ident.name && self.eq_expr(left.expr, right.expr)
}

fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool {
pub fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool {
match (left, right) {
(GenericArg::Const(l), GenericArg::Const(r)) => self.eq_const_arg(l, r),
(GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt),
Expand Down
2 changes: 1 addition & 1 deletion clippy_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ pub mod usage;
pub mod visitors;

pub use self::attrs::*;
pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match};
pub use self::check_proc_macro::{WithSearchPat, is_from_proc_macro, is_span_if, is_span_match};
pub use self::hir_utils::{
HirEqInterExpr, SpanlessEq, SpanlessHash, both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over,
};
Expand Down
3 changes: 2 additions & 1 deletion clippy_utils/src/msrvs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ msrv_aliases! {
1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY }
1,82,0 { IS_NONE_OR, REPEAT_N }
1,81,0 { LINT_REASONS_STABILIZATION }
1,80,0 { BOX_INTO_ITER}
1,80,0 { BOX_INTO_ITER }
1,79,0 { ASSOCIATED_TYPE_BOUNDS }
1,77,0 { C_STR_LITERALS }
1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT }
1,73,0 { MANUAL_DIV_CEIL }
Expand Down
8 changes: 4 additions & 4 deletions clippy_utils/src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
ty: Ty<'tcx>,
trait_id: DefId,
callee_id: Option<DefId>,
args: impl IntoIterator<Item = impl Into<Option<GenericArg<'tcx>>>>,
args: impl IntoIterator<Item: Into<Option<GenericArg<'tcx>>>>,
) -> bool {
// Clippy shouldn't have infer types
assert!(!ty.has_infer());
Expand Down Expand Up @@ -1073,7 +1073,7 @@ pub fn make_projection<'tcx>(
tcx: TyCtxt<'tcx>,
container_id: DefId,
assoc_ty: Symbol,
args: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
) -> Option<AliasTy<'tcx>> {
fn helper<'tcx>(
tcx: TyCtxt<'tcx>,
Expand Down Expand Up @@ -1114,7 +1114,7 @@ pub fn make_normalized_projection<'tcx>(
param_env: ParamEnv<'tcx>,
container_id: DefId,
assoc_ty: Symbol,
args: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
) -> Option<Ty<'tcx>> {
fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
#[cfg(debug_assertions)]
Expand Down Expand Up @@ -1241,7 +1241,7 @@ pub fn make_normalized_projection_with_regions<'tcx>(
param_env: ParamEnv<'tcx>,
container_id: DefId,
assoc_ty: Symbol,
args: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
) -> Option<Ty<'tcx>> {
fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
#[cfg(debug_assertions)]
Expand Down
95 changes: 95 additions & 0 deletions tests/ui/could_be_assoc_type_bounds.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//@aux-build:proc_macros.rs
#![allow(clippy::extra_unused_type_parameters)]

extern crate proc_macros;

fn projection_with_existing_assoc_bounds<T>()
where
T: Iterator<Item: Clone + Copy + Sized>,

//~^ could_be_assoc_type_bounds
{
}

fn projection_with_existing_bounds<T: Iterator<Item: Clone + Copy + Sized>>()
//~^ could_be_assoc_type_bounds
{
}

fn no_fully_qualified_path<T: Iterator<Item: Clone>>()
where
// False negative for now: `T::Item` has a `Res::Err` resolution
T::Item: Copy + Sized,
{
}

fn ty_param<T: Iterator<Item: Clone>, >() {}

fn multiple_projections<T>()
where
T: Iterator<Item: Sized + Clone>,

{
}

fn ty_param_used_in_body<T: Iterator<Item = P>, P: Clone + Default>() {
P::default();
}

fn nested_impl_trait(_: impl Iterator<Item = impl Sized>) {}

fn impl_trait_generic(_: impl Iterator<Item: Copy>) {}

fn single_impl_trait(_: impl Iterator<Item = ()>) {}

fn parenthesized<T: Iterator<Item: Fn()>, >() {} //~ could_be_assoc_type_bounds

// Make sure implicit generic lifetime parameters for delim doesn't mess up spans
pub fn elided_lifetime<I, >(iter: I, delim: &str)
where
I: IntoIterator<Item: std::fmt::Display>,
//~ could_be_assoc_type_bounds
{
}

fn parenthesized2<F: Fn()>()
where
F::Output: Copy,
{
}
fn many_ty_params<T, X>()
//~^ could_be_assoc_type_bounds
where
T: Iterator<Item: Copy>,
{
}

#[clippy::msrv = "1.78.0"]
fn low_msrv<T: Iterator<Item = P>, P: Copy + Default>() {
#[clippy::msrv = "1.79.0"]
P::default();
}

// More involved test case with multiple associated types and generic parameters
trait Trait1<G1, G2>: Default {
type A2;
type A3;
type A4;
}

fn complex<T, G1, G2>()
where
(T, T): Trait1<G1, G2, A2 = u32, A3: Clone, A4: Clone>,

{
}

proc_macros::external! {
fn external<T: Iterator<Item = I>, I: Copy>() {}
}
proc_macros::with_span! {
span
fn external2<T: Iterator<Item = I>, I: Copy>() {}
}

fn main() {}
101 changes: 101 additions & 0 deletions tests/ui/could_be_assoc_type_bounds.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//@aux-build:proc_macros.rs
#![allow(clippy::extra_unused_type_parameters)]

extern crate proc_macros;

fn projection_with_existing_assoc_bounds<T>()
where
T: Iterator<Item: Clone>,
<T as Iterator>::Item: Copy + Sized,
//~^ could_be_assoc_type_bounds
{
}

fn projection_with_existing_bounds<T: Iterator<Item: Clone>>()
where
<T as Iterator>::Item: Copy + Sized,
//~^ could_be_assoc_type_bounds
{
}

fn no_fully_qualified_path<T: Iterator<Item: Clone>>()
where
// False negative for now: `T::Item` has a `Res::Err` resolution
T::Item: Copy + Sized,
{
}

fn ty_param<T: Iterator<Item = P>, P: Clone>() {}

fn multiple_projections<T>()
where
T: Iterator,
<T as Iterator>::Item: Sized,
//~^ could_be_assoc_type_bounds
<T as Iterator>::Item: Clone,
{
}

fn ty_param_used_in_body<T: Iterator<Item = P>, P: Clone + Default>() {
P::default();
}

fn nested_impl_trait(_: impl Iterator<Item = impl Sized>) {}

fn impl_trait_generic<T: Copy>(_: impl Iterator<Item = T>) {}

fn single_impl_trait(_: impl Iterator<Item = ()>) {}

fn parenthesized<T: Iterator<Item = F>, F: Fn()>() {} //~ could_be_assoc_type_bounds

// Make sure implicit generic lifetime parameters for delim doesn't mess up spans
pub fn elided_lifetime<I, T>(iter: I, delim: &str)
where
I: IntoIterator<Item = T>,
T: std::fmt::Display, //~ could_be_assoc_type_bounds
{
}

fn parenthesized2<F: Fn()>()
where
F::Output: Copy,
{
}
fn many_ty_params<T, U: Copy, X>()
//~^ could_be_assoc_type_bounds
where
T: Iterator<Item = U>,
{
}

#[clippy::msrv = "1.78.0"]
fn low_msrv<T: Iterator<Item = P>, P: Copy + Default>() {
#[clippy::msrv = "1.79.0"]
P::default();
}

// More involved test case with multiple associated types and generic parameters
trait Trait1<G1, G2>: Default {
type A2;
type A3;
type A4;
}

fn complex<T, U, G1, G2>()
where
(T, T): Trait1<G1, G2, A2 = u32, A3 = U>,
<(T, T) as Trait1<G1, G2>>::A4: Clone,
//~^ could_be_assoc_type_bounds
U: Clone,
{
}

proc_macros::external! {
fn external<T: Iterator<Item = I>, I: Copy>() {}
}
proc_macros::with_span! {
span
fn external2<T: Iterator<Item = I>, I: Copy>() {}
}

fn main() {}
Loading

0 comments on commit 10ed145

Please sign in to comment.