Skip to content

Commit 10ed145

Browse files
committed
add lint: could_be_assoc_type_bounds
1 parent d49501c commit 10ed145

20 files changed

+1046
-26
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5410,6 +5410,7 @@ Released 2018-09-13
54105410
[`const_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_is_empty
54115411
[`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime
54125412
[`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
5413+
[`could_be_assoc_type_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#could_be_assoc_type_bounds
54135414
[`crate_in_macro_def`]: https://rust-lang.github.io/rust-clippy/master/index.html#crate_in_macro_def
54145415
[`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir
54155416
[`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute

clippy_lints/src/could_be_assoc_type_bounds.rs

Lines changed: 674 additions & 0 deletions
Large diffs are not rendered by default.

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
111111
crate::copies::IF_SAME_THEN_ELSE_INFO,
112112
crate::copies::SAME_FUNCTIONS_IN_IF_CONDITION_INFO,
113113
crate::copy_iterator::COPY_ITERATOR_INFO,
114+
crate::could_be_assoc_type_bounds::COULD_BE_ASSOC_TYPE_BOUNDS_INFO,
114115
crate::crate_in_macro_def::CRATE_IN_MACRO_DEF_INFO,
115116
crate::create_dir::CREATE_DIR_INFO,
116117
crate::dbg_macro::DBG_MACRO_INFO,

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ mod collection_is_never_read;
100100
mod comparison_chain;
101101
mod copies;
102102
mod copy_iterator;
103+
mod could_be_assoc_type_bounds;
103104
mod crate_in_macro_def;
104105
mod create_dir;
105106
mod dbg_macro;
@@ -963,5 +964,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
963964
store.register_late_pass(|_| Box::new(manual_ignore_case_cmp::ManualIgnoreCaseCmp));
964965
store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound));
965966
store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf)));
967+
store.register_late_pass(move |_| Box::new(could_be_assoc_type_bounds::ManualAssocTypeBounds::new(conf)));
966968
// add lints here, do not remove this comment, it's used in `new_lint`
967969
}

clippy_utils/src/hir_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ impl HirEqInterExpr<'_, '_, '_> {
455455
left.ident.name == right.ident.name && self.eq_expr(left.expr, right.expr)
456456
}
457457

458-
fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool {
458+
pub fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool {
459459
match (left, right) {
460460
(GenericArg::Const(l), GenericArg::Const(r)) => self.eq_const_arg(l, r),
461461
(GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt),

clippy_utils/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ pub mod usage;
7979
pub mod visitors;
8080

8181
pub use self::attrs::*;
82-
pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match};
82+
pub use self::check_proc_macro::{WithSearchPat, is_from_proc_macro, is_span_if, is_span_match};
8383
pub use self::hir_utils::{
8484
HirEqInterExpr, SpanlessEq, SpanlessHash, both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over,
8585
};

clippy_utils/src/msrvs.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ msrv_aliases! {
2121
1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY }
2222
1,82,0 { IS_NONE_OR, REPEAT_N }
2323
1,81,0 { LINT_REASONS_STABILIZATION }
24-
1,80,0 { BOX_INTO_ITER}
24+
1,80,0 { BOX_INTO_ITER }
25+
1,79,0 { ASSOCIATED_TYPE_BOUNDS }
2526
1,77,0 { C_STR_LITERALS }
2627
1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT }
2728
1,73,0 { MANUAL_DIV_CEIL }

clippy_utils/src/ty.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
251251
ty: Ty<'tcx>,
252252
trait_id: DefId,
253253
callee_id: Option<DefId>,
254-
args: impl IntoIterator<Item = impl Into<Option<GenericArg<'tcx>>>>,
254+
args: impl IntoIterator<Item: Into<Option<GenericArg<'tcx>>>>,
255255
) -> bool {
256256
// Clippy shouldn't have infer types
257257
assert!(!ty.has_infer());
@@ -1073,7 +1073,7 @@ pub fn make_projection<'tcx>(
10731073
tcx: TyCtxt<'tcx>,
10741074
container_id: DefId,
10751075
assoc_ty: Symbol,
1076-
args: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
1076+
args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
10771077
) -> Option<AliasTy<'tcx>> {
10781078
fn helper<'tcx>(
10791079
tcx: TyCtxt<'tcx>,
@@ -1114,7 +1114,7 @@ pub fn make_normalized_projection<'tcx>(
11141114
param_env: ParamEnv<'tcx>,
11151115
container_id: DefId,
11161116
assoc_ty: Symbol,
1117-
args: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
1117+
args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
11181118
) -> Option<Ty<'tcx>> {
11191119
fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
11201120
#[cfg(debug_assertions)]
@@ -1241,7 +1241,7 @@ pub fn make_normalized_projection_with_regions<'tcx>(
12411241
param_env: ParamEnv<'tcx>,
12421242
container_id: DefId,
12431243
assoc_ty: Symbol,
1244-
args: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
1244+
args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
12451245
) -> Option<Ty<'tcx>> {
12461246
fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
12471247
#[cfg(debug_assertions)]
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//@aux-build:proc_macros.rs
2+
#![allow(clippy::extra_unused_type_parameters)]
3+
4+
extern crate proc_macros;
5+
6+
fn projection_with_existing_assoc_bounds<T>()
7+
where
8+
T: Iterator<Item: Clone + Copy + Sized>,
9+
10+
//~^ could_be_assoc_type_bounds
11+
{
12+
}
13+
14+
fn projection_with_existing_bounds<T: Iterator<Item: Clone + Copy + Sized>>()
15+
//~^ could_be_assoc_type_bounds
16+
{
17+
}
18+
19+
fn no_fully_qualified_path<T: Iterator<Item: Clone>>()
20+
where
21+
// False negative for now: `T::Item` has a `Res::Err` resolution
22+
T::Item: Copy + Sized,
23+
{
24+
}
25+
26+
fn ty_param<T: Iterator<Item: Clone>, >() {}
27+
28+
fn multiple_projections<T>()
29+
where
30+
T: Iterator<Item: Sized + Clone>,
31+
32+
{
33+
}
34+
35+
fn ty_param_used_in_body<T: Iterator<Item = P>, P: Clone + Default>() {
36+
P::default();
37+
}
38+
39+
fn nested_impl_trait(_: impl Iterator<Item = impl Sized>) {}
40+
41+
fn impl_trait_generic(_: impl Iterator<Item: Copy>) {}
42+
43+
fn single_impl_trait(_: impl Iterator<Item = ()>) {}
44+
45+
fn parenthesized<T: Iterator<Item: Fn()>, >() {} //~ could_be_assoc_type_bounds
46+
47+
// Make sure implicit generic lifetime parameters for delim doesn't mess up spans
48+
pub fn elided_lifetime<I, >(iter: I, delim: &str)
49+
where
50+
I: IntoIterator<Item: std::fmt::Display>,
51+
//~ could_be_assoc_type_bounds
52+
{
53+
}
54+
55+
fn parenthesized2<F: Fn()>()
56+
where
57+
F::Output: Copy,
58+
{
59+
}
60+
fn many_ty_params<T, X>()
61+
//~^ could_be_assoc_type_bounds
62+
where
63+
T: Iterator<Item: Copy>,
64+
{
65+
}
66+
67+
#[clippy::msrv = "1.78.0"]
68+
fn low_msrv<T: Iterator<Item = P>, P: Copy + Default>() {
69+
#[clippy::msrv = "1.79.0"]
70+
P::default();
71+
}
72+
73+
// More involved test case with multiple associated types and generic parameters
74+
trait Trait1<G1, G2>: Default {
75+
type A2;
76+
type A3;
77+
type A4;
78+
}
79+
80+
fn complex<T, G1, G2>()
81+
where
82+
(T, T): Trait1<G1, G2, A2 = u32, A3: Clone, A4: Clone>,
83+
84+
{
85+
}
86+
87+
proc_macros::external! {
88+
fn external<T: Iterator<Item = I>, I: Copy>() {}
89+
}
90+
proc_macros::with_span! {
91+
span
92+
fn external2<T: Iterator<Item = I>, I: Copy>() {}
93+
}
94+
95+
fn main() {}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
//@aux-build:proc_macros.rs
2+
#![allow(clippy::extra_unused_type_parameters)]
3+
4+
extern crate proc_macros;
5+
6+
fn projection_with_existing_assoc_bounds<T>()
7+
where
8+
T: Iterator<Item: Clone>,
9+
<T as Iterator>::Item: Copy + Sized,
10+
//~^ could_be_assoc_type_bounds
11+
{
12+
}
13+
14+
fn projection_with_existing_bounds<T: Iterator<Item: Clone>>()
15+
where
16+
<T as Iterator>::Item: Copy + Sized,
17+
//~^ could_be_assoc_type_bounds
18+
{
19+
}
20+
21+
fn no_fully_qualified_path<T: Iterator<Item: Clone>>()
22+
where
23+
// False negative for now: `T::Item` has a `Res::Err` resolution
24+
T::Item: Copy + Sized,
25+
{
26+
}
27+
28+
fn ty_param<T: Iterator<Item = P>, P: Clone>() {}
29+
30+
fn multiple_projections<T>()
31+
where
32+
T: Iterator,
33+
<T as Iterator>::Item: Sized,
34+
//~^ could_be_assoc_type_bounds
35+
<T as Iterator>::Item: Clone,
36+
{
37+
}
38+
39+
fn ty_param_used_in_body<T: Iterator<Item = P>, P: Clone + Default>() {
40+
P::default();
41+
}
42+
43+
fn nested_impl_trait(_: impl Iterator<Item = impl Sized>) {}
44+
45+
fn impl_trait_generic<T: Copy>(_: impl Iterator<Item = T>) {}
46+
47+
fn single_impl_trait(_: impl Iterator<Item = ()>) {}
48+
49+
fn parenthesized<T: Iterator<Item = F>, F: Fn()>() {} //~ could_be_assoc_type_bounds
50+
51+
// Make sure implicit generic lifetime parameters for delim doesn't mess up spans
52+
pub fn elided_lifetime<I, T>(iter: I, delim: &str)
53+
where
54+
I: IntoIterator<Item = T>,
55+
T: std::fmt::Display, //~ could_be_assoc_type_bounds
56+
{
57+
}
58+
59+
fn parenthesized2<F: Fn()>()
60+
where
61+
F::Output: Copy,
62+
{
63+
}
64+
fn many_ty_params<T, U: Copy, X>()
65+
//~^ could_be_assoc_type_bounds
66+
where
67+
T: Iterator<Item = U>,
68+
{
69+
}
70+
71+
#[clippy::msrv = "1.78.0"]
72+
fn low_msrv<T: Iterator<Item = P>, P: Copy + Default>() {
73+
#[clippy::msrv = "1.79.0"]
74+
P::default();
75+
}
76+
77+
// More involved test case with multiple associated types and generic parameters
78+
trait Trait1<G1, G2>: Default {
79+
type A2;
80+
type A3;
81+
type A4;
82+
}
83+
84+
fn complex<T, U, G1, G2>()
85+
where
86+
(T, T): Trait1<G1, G2, A2 = u32, A3 = U>,
87+
<(T, T) as Trait1<G1, G2>>::A4: Clone,
88+
//~^ could_be_assoc_type_bounds
89+
U: Clone,
90+
{
91+
}
92+
93+
proc_macros::external! {
94+
fn external<T: Iterator<Item = I>, I: Copy>() {}
95+
}
96+
proc_macros::with_span! {
97+
span
98+
fn external2<T: Iterator<Item = I>, I: Copy>() {}
99+
}
100+
101+
fn main() {}

0 commit comments

Comments
 (0)