Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e12dbd7

Browse files
committedDec 8, 2022
Improve help for extra_unused_type_parameters
1 parent 83c2a48 commit e12dbd7

File tree

3 files changed

+89
-24
lines changed

3 files changed

+89
-24
lines changed
 

‎clippy_lints/src/extra_unused_type_parameters.rs

+64-10
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
use clippy_utils::diagnostics::span_lint;
1+
use clippy_utils::diagnostics::span_lint_and_help;
22
use clippy_utils::trait_ref_of_method;
33
use rustc_data_structures::fx::FxHashMap;
4+
use rustc_errors::MultiSpan;
45
use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor};
56
use rustc_hir::{GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, Ty, TyKind, WherePredicate};
67
use rustc_lint::{LateContext, LateLintPass};
78
use rustc_middle::hir::nested_filter;
89
use rustc_session::{declare_lint_pass, declare_tool_lint};
9-
use rustc_span::{def_id::DefId, Span};
10+
use rustc_span::{def_id::DefId, source_map::SourceMap, BytePos, Span};
1011

1112
declare_clippy_lint! {
1213
/// ### What it does
@@ -39,10 +40,12 @@ declare_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]);
3940
struct TypeWalker<'cx, 'tcx> {
4041
cx: &'cx LateContext<'tcx>,
4142
map: FxHashMap<DefId, Span>,
43+
generics: &'tcx Generics<'tcx>,
44+
some_params_used: bool,
4245
}
4346

4447
impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
45-
fn new(cx: &'cx LateContext<'tcx>, generics: &Generics<'tcx>) -> Self {
48+
fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'tcx>) -> Self {
4649
Self {
4750
cx,
4851
map: generics
@@ -53,27 +56,78 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
5356
_ => None,
5457
})
5558
.collect(),
59+
generics,
60+
some_params_used: false,
5661
}
5762
}
5863

5964
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+
let (msg, help) = match self.map.len() {
66+
0 => return,
67+
1 => (
6568
"type parameter goes unused in function definition",
66-
);
69+
"consider removing the parameter",
70+
),
71+
_ => (
72+
"type parameters go unused in function definition",
73+
"consider removing the parameters",
74+
),
75+
};
76+
77+
let source_map = self.cx.tcx.sess.source_map();
78+
let span = if self.some_params_used {
79+
MultiSpan::from_spans(
80+
self.map
81+
.values()
82+
.into_iter()
83+
.map(|&span| {
84+
let span = span_extend_through_nested_brackets(&source_map, span);
85+
let span = span_extend_through_next_char(&source_map, span, ',', false);
86+
let max_hi = self.generics.span.hi();
87+
if span.hi() >= max_hi {
88+
span.with_hi(BytePos(max_hi.0 - 1))
89+
} else {
90+
span
91+
}
92+
})
93+
.collect(),
94+
)
95+
} else {
96+
self.generics.span.into()
97+
};
98+
99+
span_lint_and_help(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, span, msg, None, help);
100+
}
101+
}
102+
103+
fn span_extend_through_next_char(source_map: &SourceMap, span: Span, c: char, accept_commas: bool) -> Span {
104+
if let Ok(next_source) = source_map.span_to_next_source(span) {
105+
let next_source = next_source.split(c).next().unwrap_or("");
106+
if !next_source.contains('\n') && (accept_commas || !next_source.contains(',')) {
107+
return span.with_hi(BytePos(span.hi().0 + next_source.len() as u32 + 1));
67108
}
68109
}
110+
111+
span
112+
}
113+
114+
fn span_extend_through_nested_brackets(source_map: &SourceMap, span: Span) -> Span {
115+
let mut new_span = span_extend_through_next_char(source_map, span, '<', false);
116+
if new_span.hi() == span.hi() {
117+
return span;
118+
}
119+
new_span = span_extend_through_nested_brackets(source_map, new_span);
120+
span_extend_through_next_char(source_map, new_span, '>', true)
69121
}
70122

71123
impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
72124
type NestedFilter = nested_filter::OnlyBodies;
73125

74126
fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
75127
if let Some((def_id, _)) = t.peel_refs().as_generic_param() {
76-
self.map.remove(&def_id);
128+
if self.map.remove(&def_id).is_some() {
129+
self.some_params_used = true;
130+
}
77131
} else if let TyKind::OpaqueDef(id, _, _) = t.kind {
78132
// Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls
79133
// `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're

‎tests/ui/extra_unused_type_parameters.rs

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ fn used_ret<T: Default>(x: u8) -> T {
1515

1616
fn unused_with_bound<T: Default>(x: u8) {}
1717

18+
fn some_unused<A, B, C, D: Iterator<Item = (B, C)>, E>(b: B, c: C) {}
19+
1820
fn used_opaque<A>(iter: impl Iterator<Item = A>) -> usize {
1921
iter.count()
2022
}
+23-14
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,43 @@
11
error: type parameter goes unused in function definition
2-
--> $DIR/extra_unused_type_parameters.rs:4:14
2+
--> $DIR/extra_unused_type_parameters.rs:4:13
33
|
44
LL | fn unused_ty<T>(x: u8) {}
5-
| ^
5+
| ^^^
66
|
7+
= help: consider removing the parameter
78
= note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings`
89

9-
error: type parameter goes unused in function definition
10-
--> $DIR/extra_unused_type_parameters.rs:6:17
10+
error: type parameters go unused in function definition
11+
--> $DIR/extra_unused_type_parameters.rs:6:16
1112
|
1213
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
14+
| ^^^^^^
1715
|
18-
LL | fn unused_multi<T, U>(x: u8) {}
19-
| ^
16+
= help: consider removing the parameters
2017

2118
error: type parameter goes unused in function definition
22-
--> $DIR/extra_unused_type_parameters.rs:16:22
19+
--> $DIR/extra_unused_type_parameters.rs:16:21
2320
|
2421
LL | fn unused_with_bound<T: Default>(x: u8) {}
25-
| ^
22+
| ^^^^^^^^^^^^
23+
|
24+
= help: consider removing the parameter
25+
26+
error: type parameters go unused in function definition
27+
--> $DIR/extra_unused_type_parameters.rs:18:16
28+
|
29+
LL | fn some_unused<A, B, C, D: Iterator<Item = (B, C)>, E>(b: B, c: C) {}
30+
| ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^
31+
|
32+
= help: consider removing the parameters
2633

2734
error: type parameter goes unused in function definition
28-
--> $DIR/extra_unused_type_parameters.rs:39:23
35+
--> $DIR/extra_unused_type_parameters.rs:41:22
2936
|
3037
LL | fn unused_ty_impl<T>(&self) {}
31-
| ^
38+
| ^^^
39+
|
40+
= help: consider removing the parameter
3241

3342
error: aborting due to 5 previous errors
3443

0 commit comments

Comments
 (0)