Skip to content

Commit bde0482

Browse files
committed
Auto merge of rust-lang#11550 - blyxyas:fix-impl_trait_in_params-for_assocfn, r=dswij
`impl_trait_in_params` now supports impls and traits Before this PR, the lint `impl_trait_in_params`. This PR gives the lint support for functions in impls and traits. (Also, some pretty heavy refactor) fixes rust-lang#11548 changelog:[`impl_trait_in_params`] now supports `impl` blocks and functions in traits
2 parents 33f49f3 + 7755737 commit bde0482

File tree

8 files changed

+190
-45
lines changed

8 files changed

+190
-45
lines changed

clippy_lints/src/functions/impl_trait_in_params.rs

Lines changed: 90 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,104 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::is_in_test_function;
33

4+
use rustc_hir as hir;
45
use rustc_hir::intravisit::FnKind;
5-
use rustc_hir::{Body, HirId};
6+
use rustc_hir::{Body, GenericParam, Generics, HirId, ImplItem, ImplItemKind, TraitItem, TraitItemKind};
67
use rustc_lint::LateContext;
7-
use rustc_span::Span;
8+
use rustc_span::symbol::Ident;
9+
use rustc_span::{BytePos, Span};
810

911
use super::IMPL_TRAIT_IN_PARAMS;
1012

13+
fn report(
14+
cx: &LateContext<'_>,
15+
param: &GenericParam<'_>,
16+
ident: &Ident,
17+
generics: &Generics<'_>,
18+
first_param_span: Span,
19+
) {
20+
// No generics with nested generics, and no generics like FnMut(x)
21+
span_lint_and_then(
22+
cx,
23+
IMPL_TRAIT_IN_PARAMS,
24+
param.span,
25+
"`impl Trait` used as a function parameter",
26+
|diag| {
27+
if let Some(gen_span) = generics.span_for_param_suggestion() {
28+
// If there's already a generic param with the same bound, do not lint **this** suggestion.
29+
diag.span_suggestion_with_style(
30+
gen_span,
31+
"add a type parameter",
32+
format!(", {{ /* Generic name */ }}: {}", &param.name.ident().as_str()[5..]),
33+
rustc_errors::Applicability::HasPlaceholders,
34+
rustc_errors::SuggestionStyle::ShowAlways,
35+
);
36+
} else {
37+
diag.span_suggestion_with_style(
38+
Span::new(
39+
first_param_span.lo() - rustc_span::BytePos(1),
40+
ident.span.hi(),
41+
ident.span.ctxt(),
42+
ident.span.parent(),
43+
),
44+
"add a type parameter",
45+
format!("<{{ /* Generic name */ }}: {}>", &param.name.ident().as_str()[5..]),
46+
rustc_errors::Applicability::HasPlaceholders,
47+
rustc_errors::SuggestionStyle::ShowAlways,
48+
);
49+
}
50+
},
51+
);
52+
}
53+
1154
pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) {
12-
if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() && !is_in_test_function(cx.tcx, hir_id)
13-
{
14-
if let FnKind::ItemFn(ident, generics, _) = kind {
55+
if_chain! {
56+
if let FnKind::ItemFn(ident, generics, _) = kind;
57+
if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public();
58+
if !is_in_test_function(cx.tcx, hir_id);
59+
then {
1560
for param in generics.params {
1661
if param.is_impl_trait() {
17-
// No generics with nested generics, and no generics like FnMut(x)
18-
span_lint_and_then(
19-
cx,
20-
IMPL_TRAIT_IN_PARAMS,
21-
param.span,
22-
"'`impl Trait` used as a function parameter'",
23-
|diag| {
24-
if let Some(gen_span) = generics.span_for_param_suggestion() {
25-
diag.span_suggestion_with_style(
26-
gen_span,
27-
"add a type parameter",
28-
format!(", {{ /* Generic name */ }}: {}", &param.name.ident().as_str()[5..]),
29-
rustc_errors::Applicability::HasPlaceholders,
30-
rustc_errors::SuggestionStyle::ShowAlways,
31-
);
32-
} else {
33-
diag.span_suggestion_with_style(
34-
Span::new(
35-
body.params[0].span.lo() - rustc_span::BytePos(1),
36-
ident.span.hi(),
37-
ident.span.ctxt(),
38-
ident.span.parent(),
39-
),
40-
"add a type parameter",
41-
format!("<{{ /* Generic name */ }}: {}>", &param.name.ident().as_str()[5..]),
42-
rustc_errors::Applicability::HasPlaceholders,
43-
rustc_errors::SuggestionStyle::ShowAlways,
44-
);
45-
}
46-
},
47-
);
62+
report(cx, param, ident, generics, body.params[0].span);
63+
};
64+
}
65+
}
66+
}
67+
}
68+
69+
pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
70+
if_chain! {
71+
if let ImplItemKind::Fn(_, body_id) = impl_item.kind;
72+
if let hir::Node::Item(item) = cx.tcx.hir().get_parent(impl_item.hir_id());
73+
if let hir::ItemKind::Impl(impl_) = item.kind;
74+
if let hir::Impl { of_trait, .. } = *impl_;
75+
if of_trait.is_none();
76+
let body = cx.tcx.hir().body(body_id);
77+
if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public();
78+
if !is_in_test_function(cx.tcx, impl_item.hir_id());
79+
then {
80+
for param in impl_item.generics.params {
81+
if param.is_impl_trait() {
82+
report(cx, param, &impl_item.ident, impl_item.generics, body.params[0].span);
83+
}
84+
}
85+
}
86+
}
87+
}
88+
89+
pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>, avoid_breaking_exported_api: bool) {
90+
if_chain! {
91+
if !avoid_breaking_exported_api;
92+
if let TraitItemKind::Fn(_, _) = trait_item.kind;
93+
if let hir::Node::Item(item) = cx.tcx.hir().get_parent(trait_item.hir_id());
94+
// ^^ (Will always be a trait)
95+
if !item.vis_span.is_empty(); // Is public
96+
if !is_in_test_function(cx.tcx, trait_item.hir_id());
97+
then {
98+
for param in trait_item.generics.params {
99+
if param.is_impl_trait() {
100+
let sp = trait_item.ident.span.with_hi(trait_item.ident.span.hi() + BytePos(1));
101+
report(cx, param, &trait_item.ident, trait_item.generics, sp.shrink_to_hi());
48102
}
49103
}
50104
}

clippy_lints/src/functions/mod.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,14 +364,21 @@ pub struct Functions {
364364
too_many_arguments_threshold: u64,
365365
too_many_lines_threshold: u64,
366366
large_error_threshold: u64,
367+
avoid_breaking_exported_api: bool,
367368
}
368369

369370
impl Functions {
370-
pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64, large_error_threshold: u64) -> Self {
371+
pub fn new(
372+
too_many_arguments_threshold: u64,
373+
too_many_lines_threshold: u64,
374+
large_error_threshold: u64,
375+
avoid_breaking_exported_api: bool,
376+
) -> Self {
371377
Self {
372378
too_many_arguments_threshold,
373379
too_many_lines_threshold,
374380
large_error_threshold,
381+
avoid_breaking_exported_api,
375382
}
376383
}
377384
}
@@ -415,12 +422,14 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
415422
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
416423
must_use::check_impl_item(cx, item);
417424
result::check_impl_item(cx, item, self.large_error_threshold);
425+
impl_trait_in_params::check_impl_item(cx, item);
418426
}
419427

420428
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
421429
too_many_arguments::check_trait_item(cx, item, self.too_many_arguments_threshold);
422430
not_unsafe_ptr_arg_deref::check_trait_item(cx, item);
423431
must_use::check_trait_item(cx, item);
424432
result::check_trait_item(cx, item, self.large_error_threshold);
433+
impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api);
425434
}
426435
}

clippy_lints/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
762762
too_many_arguments_threshold,
763763
too_many_lines_threshold,
764764
large_error_threshold,
765+
avoid_breaking_exported_api,
765766
))
766767
});
767768
let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
avoid-breaking-exported-api = false
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//! As avoid-breaking-exported-api is `false`, nothing here should lint
2+
#![warn(clippy::impl_trait_in_params)]
3+
#![no_main]
4+
//@no-rustfix
5+
6+
pub trait Trait {}
7+
8+
trait Private {
9+
fn t(_: impl Trait);
10+
fn tt<T: Trait>(_: T);
11+
}
12+
13+
pub trait Public {
14+
fn t(_: impl Trait); //~ ERROR: `impl Trait` used as a function parameter
15+
fn tt<T: Trait>(_: T);
16+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: `impl Trait` used as a function parameter
2+
--> $DIR/impl_trait_in_params.rs:14:13
3+
|
4+
LL | fn t(_: impl Trait);
5+
| ^^^^^^^^^^
6+
|
7+
= note: `-D clippy::impl-trait-in-params` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::impl_trait_in_params)]`
9+
help: add a type parameter
10+
|
11+
LL | fn t<{ /* Generic name */ }: Trait>(_: impl Trait);
12+
| +++++++++++++++++++++++++++++++
13+
14+
error: aborting due to previous error
15+

tests/ui/impl_trait_in_params.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,47 @@
11
#![allow(unused)]
22
#![warn(clippy::impl_trait_in_params)]
3+
34
//@no-rustfix
45
pub trait Trait {}
56
pub trait AnotherTrait<T> {}
67

78
// Should warn
89
pub fn a(_: impl Trait) {}
9-
//~^ ERROR: '`impl Trait` used as a function parameter'
10-
//~| NOTE: `-D clippy::impl-trait-in-params` implied by `-D warnings`
10+
//~^ ERROR: `impl Trait` used as a function parameter
1111
pub fn c<C: Trait>(_: C, _: impl Trait) {}
12-
//~^ ERROR: '`impl Trait` used as a function parameter'
13-
fn d(_: impl AnotherTrait<u32>) {}
12+
//~^ ERROR: `impl Trait` used as a function parameter
1413

1514
// Shouldn't warn
1615

1716
pub fn b<B: Trait>(_: B) {}
1817
fn e<T: AnotherTrait<u32>>(_: T) {}
18+
fn d(_: impl AnotherTrait<u32>) {}
19+
20+
//------ IMPLS
21+
22+
pub trait Public {
23+
// See test in ui-toml for a case where avoid-breaking-exported-api is set to false
24+
fn t(_: impl Trait);
25+
fn tt<T: Trait>(_: T) {}
26+
}
27+
28+
trait Private {
29+
// This shouldn't lint
30+
fn t(_: impl Trait);
31+
fn tt<T: Trait>(_: T) {}
32+
}
33+
34+
struct S;
35+
impl S {
36+
pub fn h(_: impl Trait) {} //~ ERROR: `impl Trait` used as a function parameter
37+
fn i(_: impl Trait) {}
38+
pub fn j<J: Trait>(_: J) {}
39+
pub fn k<K: AnotherTrait<u32>>(_: K, _: impl AnotherTrait<u32>) {} //~ ERROR: `impl Trait` used as a function parameter
40+
}
41+
42+
// Trying with traits
43+
impl Public for S {
44+
fn t(_: impl Trait) {}
45+
}
1946

2047
fn main() {}

tests/ui/impl_trait_in_params.stderr

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
error: '`impl Trait` used as a function parameter'
2-
--> $DIR/impl_trait_in_params.rs:8:13
1+
error: `impl Trait` used as a function parameter
2+
--> $DIR/impl_trait_in_params.rs:9:13
33
|
44
LL | pub fn a(_: impl Trait) {}
55
| ^^^^^^^^^^
@@ -11,7 +11,7 @@ help: add a type parameter
1111
LL | pub fn a<{ /* Generic name */ }: Trait>(_: impl Trait) {}
1212
| +++++++++++++++++++++++++++++++
1313

14-
error: '`impl Trait` used as a function parameter'
14+
error: `impl Trait` used as a function parameter
1515
--> $DIR/impl_trait_in_params.rs:11:29
1616
|
1717
LL | pub fn c<C: Trait>(_: C, _: impl Trait) {}
@@ -22,5 +22,27 @@ help: add a type parameter
2222
LL | pub fn c<C: Trait, { /* Generic name */ }: Trait>(_: C, _: impl Trait) {}
2323
| +++++++++++++++++++++++++++++++
2424

25-
error: aborting due to 2 previous errors
25+
error: `impl Trait` used as a function parameter
26+
--> $DIR/impl_trait_in_params.rs:36:17
27+
|
28+
LL | pub fn h(_: impl Trait) {}
29+
| ^^^^^^^^^^
30+
|
31+
help: add a type parameter
32+
|
33+
LL | pub fn h<{ /* Generic name */ }: Trait>(_: impl Trait) {}
34+
| +++++++++++++++++++++++++++++++
35+
36+
error: `impl Trait` used as a function parameter
37+
--> $DIR/impl_trait_in_params.rs:39:45
38+
|
39+
LL | pub fn k<K: AnotherTrait<u32>>(_: K, _: impl AnotherTrait<u32>) {}
40+
| ^^^^^^^^^^^^^^^^^^^^^^
41+
|
42+
help: add a type parameter
43+
|
44+
LL | pub fn k<K: AnotherTrait<u32>, { /* Generic name */ }: AnotherTrait<u32>>(_: K, _: impl AnotherTrait<u32>) {}
45+
| +++++++++++++++++++++++++++++++++++++++++++
46+
47+
error: aborting due to 4 previous errors
2648

0 commit comments

Comments
 (0)