Skip to content

Commit 08e170e

Browse files
committed
Add some documentation and minor cleanup
1 parent 363ebed commit 08e170e

File tree

3 files changed

+45
-43
lines changed

3 files changed

+45
-43
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
77

8-
[There are over 550 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
8+
[There are over 600 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
99

1010
Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html).
1111
You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category.

book/src/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
A collection of lints to catch common mistakes and improve your
77
[Rust](https://github.com/rust-lang/rust) code.
88

9-
[There are over 550 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
9+
[There are over 600 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
1010

1111
Lints are divided into categories, each with a default [lint
1212
level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how

clippy_lints/src/extra_unused_type_parameters.rs

+43-41
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ use rustc_data_structures::fx::FxHashMap;
44
use rustc_errors::MultiSpan;
55
use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor};
66
use rustc_hir::{
7-
GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, LifetimeParamKind, Ty, TyKind, WherePredicate,
7+
GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, PredicateOrigin, Ty, TyKind, WherePredicate,
88
};
99
use rustc_lint::{LateContext, LateLintPass};
1010
use rustc_middle::hir::nested_filter;
1111
use rustc_session::{declare_lint_pass, declare_tool_lint};
12-
use rustc_span::{def_id::DefId, BytePos, Span};
12+
use rustc_span::{def_id::DefId, Span};
1313

1414
declare_clippy_lint! {
1515
/// ### What it does
@@ -39,44 +39,52 @@ declare_clippy_lint! {
3939
}
4040
declare_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]);
4141

42+
/// A visitor struct that walks a given function and gathers generic type parameters, plus any
43+
/// trait bounds those parameters have.
4244
struct TypeWalker<'cx, 'tcx> {
4345
cx: &'cx LateContext<'tcx>,
44-
map: FxHashMap<DefId, Span>,
45-
bound_map: FxHashMap<DefId, Span>,
46+
/// Collection of all the type parameters and their spans.
47+
ty_params: FxHashMap<DefId, Span>,
48+
/// Collection of any (inline) trait bounds corresponding to each type parameter.
49+
bounds: FxHashMap<DefId, Span>,
50+
/// The entire `Generics` object of the function, useful for querying purposes.
4651
generics: &'tcx Generics<'tcx>,
47-
some_params_used: bool,
48-
has_non_ty_params: bool,
52+
/// The value of this will remain `true` if *every* parameter:
53+
/// 1. Is a type parameter, and
54+
/// 2. Goes unused in the function.
55+
/// Otherwise, if any type parameters end up being used, or if any lifetime or const-generic
56+
/// parameters are present, this will be set to `false`.
57+
all_params_unused: bool,
4958
}
5059

5160
impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
5261
fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'tcx>) -> Self {
53-
let mut has_non_ty_params = false;
54-
let map = generics
62+
let mut all_params_unused = true;
63+
let ty_params = generics
5564
.params
5665
.iter()
57-
.filter_map(|param| match &param.kind {
58-
GenericParamKind::Type { .. } => Some((param.def_id.into(), param.span)),
59-
GenericParamKind::Lifetime {
60-
kind: LifetimeParamKind::Elided,
61-
} => None,
62-
_ => {
63-
has_non_ty_params = true;
66+
.filter_map(|param| {
67+
if let GenericParamKind::Type { .. } = param.kind {
68+
Some((param.def_id.into(), param.span))
69+
} else {
70+
if !param.is_elided_lifetime() {
71+
all_params_unused = false;
72+
}
6473
None
65-
},
74+
}
6675
})
6776
.collect();
6877
Self {
6978
cx,
70-
map,
79+
ty_params,
80+
bounds: FxHashMap::default(),
7181
generics,
72-
has_non_ty_params,
73-
bound_map: FxHashMap::default(),
74-
some_params_used: false,
82+
all_params_unused,
7583
}
7684
}
7785

7886
fn emit_lint(&self) {
79-
let (msg, help) = match self.map.len() {
87+
let (msg, help) = match self.ty_params.len() {
8088
0 => return,
8189
1 => (
8290
"type parameter goes unused in function definition",
@@ -89,27 +97,21 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
8997
};
9098

9199
let source_map = self.cx.tcx.sess.source_map();
92-
let span = if self.some_params_used || self.has_non_ty_params {
100+
let span = if self.all_params_unused {
101+
self.generics.span.into() // Remove the entire list of generics
102+
} else {
93103
MultiSpan::from_spans(
94-
self.map
104+
self.ty_params
95105
.iter()
96-
.map(|(def_id, &(mut span))| {
97-
if let Some(bound_span) = self.bound_map.get(def_id) {
98-
span = span.with_hi(bound_span.hi());
99-
}
100-
span = source_map.span_extend_to_next_char(span, ',', false);
101-
span = span.with_hi(BytePos(span.hi().0 + 1));
102-
103-
let max_hi = self.generics.span.hi();
104-
if span.hi() >= max_hi {
105-
span = span.with_hi(BytePos(max_hi.0 - 1));
106-
}
107-
span
106+
.map(|(def_id, &span)| {
107+
// Extend the span past any trait bounds, and include the comma at the end.
108+
let span_to_extend = self.bounds.get(def_id).copied().map_or(span, Span::shrink_to_hi);
109+
let comma_range = source_map.span_extend_to_next_char(span_to_extend, '>', false);
110+
let comma_span = source_map.span_through_char(comma_range, ',');
111+
span.with_hi(comma_span.hi())
108112
})
109113
.collect(),
110114
)
111-
} else {
112-
self.generics.span.into()
113115
};
114116

115117
span_lint_and_help(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, span, msg, None, help);
@@ -121,8 +123,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
121123

122124
fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
123125
if let Some((def_id, _)) = t.peel_refs().as_generic_param() {
124-
if self.map.remove(&def_id).is_some() {
125-
self.some_params_used = true;
126+
if self.ty_params.remove(&def_id).is_some() {
127+
self.all_params_unused = false;
126128
}
127129
} else if let TyKind::OpaqueDef(id, _, _) = t.kind {
128130
// Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls
@@ -140,9 +142,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
140142
// Collect spans for bounds that appear in the list of generics (not in a where-clause)
141143
// for use in forming the help message
142144
if let Some((def_id, _)) = predicate.bounded_ty.peel_refs().as_generic_param()
143-
&& predicate.span < self.generics.where_clause_span
145+
&& let PredicateOrigin::GenericParam = predicate.origin
144146
{
145-
self.bound_map.insert(def_id, predicate.span);
147+
self.bounds.insert(def_id, predicate.span);
146148
}
147149
// Only walk the right-hand side of where-bounds
148150
for bound in predicate.bounds {

0 commit comments

Comments
 (0)