Skip to content

Commit 803f2d0

Browse files
committed
Add extra_unused_type_parameters lint
1 parent 3492856 commit 803f2d0

16 files changed

+286
-70
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4017,6 +4017,7 @@ Released 2018-09-13
40174017
[`extend_from_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_from_slice
40184018
[`extend_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_with_drain
40194019
[`extra_unused_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes
4020+
[`extra_unused_type_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_type_parameters
40204021
[`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from
40214022
[`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default
40224023
[`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
156156
crate::exhaustive_items::EXHAUSTIVE_STRUCTS_INFO,
157157
crate::exit::EXIT_INFO,
158158
crate::explicit_write::EXPLICIT_WRITE_INFO,
159+
crate::extra_unused_type_parameters::EXTRA_UNUSED_TYPE_PARAMETERS_INFO,
159160
crate::fallible_impl_from::FALLIBLE_IMPL_FROM_INFO,
160161
crate::float_literal::EXCESSIVE_PRECISION_INFO,
161162
crate::float_literal::LOSSY_FLOAT_LITERAL_INFO,
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
use clippy_utils::diagnostics::span_lint;
2+
use clippy_utils::trait_ref_of_method;
3+
use rustc_data_structures::fx::FxHashMap;
4+
use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor};
5+
use rustc_hir::{GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, Ty, WherePredicate};
6+
use rustc_lint::{LateContext, LateLintPass};
7+
use rustc_middle::hir::nested_filter;
8+
use rustc_session::{declare_lint_pass, declare_tool_lint};
9+
use rustc_span::{def_id::DefId, Span};
10+
11+
declare_clippy_lint! {
12+
/// ### What it does
13+
/// Checks for type parameters in generics that are never used anywhere else.
14+
///
15+
/// ### Why is this bad?
16+
/// Functions cannot infer the value of unused type parameters; therefore, calling them
17+
/// requires using a turbofish, which serves no purpose but to satisfy the compiler.
18+
///
19+
/// ### Example
20+
/// ```rust
21+
/// // unused type parameters
22+
/// fn unused_ty<T>(x: u8) {
23+
/// // ..
24+
/// }
25+
/// ```
26+
/// Use instead:
27+
/// ```rust
28+
/// fn no_unused_ty(x: u8) {
29+
/// // ..
30+
/// }
31+
/// ```
32+
#[clippy::version = "1.67.0"]
33+
pub EXTRA_UNUSED_TYPE_PARAMETERS,
34+
complexity,
35+
"unused type parameters in function definitions"
36+
}
37+
declare_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]);
38+
39+
struct TypeWalker<'cx, 'tcx> {
40+
cx: &'cx LateContext<'tcx>,
41+
map: FxHashMap<DefId, Span>,
42+
}
43+
44+
impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
45+
fn new(cx: &'cx LateContext<'tcx>, generics: &Generics<'tcx>) -> Self {
46+
Self {
47+
cx,
48+
map: generics
49+
.params
50+
.iter()
51+
.filter_map(|param| match param.kind {
52+
GenericParamKind::Type { .. } => Some((param.def_id.into(), param.span)),
53+
_ => None,
54+
})
55+
.collect(),
56+
}
57+
}
58+
59+
fn emit_lint(&self) {
60+
for span in self.map.values() {
61+
span_lint(
62+
self.cx,
63+
EXTRA_UNUSED_TYPE_PARAMETERS,
64+
*span,
65+
"type parameter goes unused in function definition",
66+
);
67+
}
68+
}
69+
}
70+
71+
impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
72+
type NestedFilter = nested_filter::OnlyBodies;
73+
74+
fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
75+
if let Some((def_id, _)) = t.peel_refs().as_generic_param() {
76+
self.map.remove(&def_id);
77+
} else {
78+
walk_ty(self, t);
79+
}
80+
}
81+
82+
fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) {
83+
if let WherePredicate::BoundPredicate(where_bound_predicate) = predicate {
84+
// Only check the right-hand side of where-bounds
85+
for bound in where_bound_predicate.bounds {
86+
walk_param_bound(self, bound);
87+
}
88+
}
89+
}
90+
91+
fn nested_visit_map(&mut self) -> Self::Map {
92+
self.cx.tcx.hir()
93+
}
94+
}
95+
96+
impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
97+
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
98+
if let ItemKind::Fn(_, generics, _) = item.kind {
99+
let mut walker = TypeWalker::new(cx, generics);
100+
walk_item(&mut walker, item);
101+
walker.emit_lint();
102+
}
103+
}
104+
105+
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
106+
if let ImplItemKind::Fn(..) = item.kind && trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
107+
let mut walker = TypeWalker::new(cx, item.generics);
108+
walk_impl_item(&mut walker, item);
109+
walker.emit_lint();
110+
}
111+
}
112+
}

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ mod excessive_bools;
122122
mod exhaustive_items;
123123
mod exit;
124124
mod explicit_write;
125+
mod extra_unused_type_parameters;
125126
mod fallible_impl_from;
126127
mod float_literal;
127128
mod floating_point_arithmetic;
@@ -902,6 +903,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
902903
store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
903904
store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
904905
store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock));
906+
store.register_late_pass(|_| Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters));
905907
// add lints here, do not remove this comment, it's used in `new_lint`
906908
}
907909

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#![allow(unused, clippy::needless_lifetimes)]
2+
#![warn(clippy::extra_unused_type_parameters)]
3+
4+
fn unused_ty<T>(x: u8) {}
5+
6+
fn unused_multi<T, U>(x: u8) {}
7+
8+
fn used_ty<T>(x: T, y: u8) {}
9+
10+
fn used_ref<'a, T>(x: &'a T) {}
11+
12+
fn used_ret<T: Default>(x: u8) -> T {
13+
T::default()
14+
}
15+
16+
fn unused_with_bound<T: Default>(x: u8) {}
17+
18+
fn used_opaque<A>(iter: impl Iterator<Item = A>) -> usize {
19+
iter.count()
20+
}
21+
22+
fn used_ret_opaque<A>() -> impl Iterator<Item = A> {
23+
std::iter::empty()
24+
}
25+
26+
fn used_vec_box<T>(x: Vec<Box<T>>) {}
27+
28+
fn used_body<T: Default + ToString>() -> String {
29+
T::default().to_string()
30+
}
31+
32+
fn used_closure<T: Default + ToString>() -> impl Fn() {
33+
|| println!("{}", T::default().to_string())
34+
}
35+
36+
struct S;
37+
38+
impl S {
39+
fn unused_ty_impl<T>(&self) {}
40+
}
41+
42+
// Don't lint on trait methods
43+
trait Foo {
44+
fn bar<T>(&self);
45+
}
46+
47+
impl Foo for S {
48+
fn bar<T>(&self) {}
49+
}
50+
51+
fn skip_index<A, Iter>(iter: Iter, index: usize) -> impl Iterator<Item = A>
52+
where
53+
Iter: Iterator<Item = A>,
54+
{
55+
iter.enumerate()
56+
.filter_map(move |(i, a)| if i == index { None } else { Some(a) })
57+
}
58+
59+
fn main() {}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
error: type parameter goes unused in function definition
2+
--> $DIR/extra_unused_type_parameters.rs:4:14
3+
|
4+
LL | fn unused_ty<T>(x: u8) {}
5+
| ^
6+
|
7+
= note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings`
8+
9+
error: type parameter goes unused in function definition
10+
--> $DIR/extra_unused_type_parameters.rs:6:17
11+
|
12+
LL | fn unused_multi<T, U>(x: u8) {}
13+
| ^
14+
15+
error: type parameter goes unused in function definition
16+
--> $DIR/extra_unused_type_parameters.rs:6:20
17+
|
18+
LL | fn unused_multi<T, U>(x: u8) {}
19+
| ^
20+
21+
error: type parameter goes unused in function definition
22+
--> $DIR/extra_unused_type_parameters.rs:16:22
23+
|
24+
LL | fn unused_with_bound<T: Default>(x: u8) {}
25+
| ^
26+
27+
error: type parameter goes unused in function definition
28+
--> $DIR/extra_unused_type_parameters.rs:39:23
29+
|
30+
LL | fn unused_ty_impl<T>(&self) {}
31+
| ^
32+
33+
error: aborting due to 5 previous errors
34+

tests/ui/needless_lifetimes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#![allow(
33
dead_code,
44
clippy::boxed_local,
5+
clippy::extra_unused_type_parameters,
56
clippy::needless_pass_by_value,
67
clippy::unnecessary_wraps,
78
dyn_drop,

0 commit comments

Comments
 (0)