Auto merge of #10536 - mkrasnitski:suggestions, r=flip1995
Add suggestions to `extra_unused_type_parameters` Change the `extra_unused_type_parameters` lint to provide machine applicable suggestions rather than just help messages. Exception to this are cases when any unused type parameters appear bounded in where clauses - for now I've deemed these cases unfixable and separated them out. Future work might be able to provide suggestions in these cases. Also, added a test case for the `avoid_breaking_exported_api` config option. r? `@flip1995` changelog: [`extra_unused_type_parameters`]: Now provides fixable suggestions.
This commit is contained in:
commit
29987062d9
@ -1,10 +1,10 @@
|
|||||||
use clippy_utils::diagnostics::span_lint_and_help;
|
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
|
||||||
use clippy_utils::trait_ref_of_method;
|
use clippy_utils::trait_ref_of_method;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_errors::MultiSpan;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor};
|
use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor};
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
BodyId, ExprKind, GenericBound, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind,
|
BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind,
|
||||||
PredicateOrigin, Ty, TyKind, WherePredicate,
|
PredicateOrigin, Ty, TyKind, WherePredicate,
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
@ -53,13 +53,19 @@ pub fn new(avoid_breaking_exported_api: bool) -> Self {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Don't lint external macros or functions with empty bodies. Also, don't lint public items if
|
/// Don't lint external macros or functions with empty bodies. Also, don't lint exported items
|
||||||
/// the `avoid_breaking_exported_api` config option is set.
|
/// if the `avoid_breaking_exported_api` config option is set.
|
||||||
fn check_false_positive(&self, cx: &LateContext<'_>, span: Span, def_id: LocalDefId, body_id: BodyId) -> bool {
|
fn is_empty_exported_or_macro(
|
||||||
|
&self,
|
||||||
|
cx: &LateContext<'_>,
|
||||||
|
span: Span,
|
||||||
|
def_id: LocalDefId,
|
||||||
|
body_id: BodyId,
|
||||||
|
) -> bool {
|
||||||
let body = cx.tcx.hir().body(body_id).value;
|
let body = cx.tcx.hir().body(body_id).value;
|
||||||
let fn_empty = matches!(&body.kind, ExprKind::Block(blk, None) if blk.stmts.is_empty() && blk.expr.is_none());
|
let fn_empty = matches!(&body.kind, ExprKind::Block(blk, None) if blk.stmts.is_empty() && blk.expr.is_none());
|
||||||
let is_exported = cx.effective_visibilities.is_exported(def_id);
|
let is_exported = cx.effective_visibilities.is_exported(def_id);
|
||||||
in_external_macro(cx.sess(), span) || (self.avoid_breaking_exported_api && is_exported) || fn_empty
|
in_external_macro(cx.sess(), span) || fn_empty || (is_exported && self.avoid_breaking_exported_api)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,85 +75,129 @@ fn check_false_positive(&self, cx: &LateContext<'_>, span: Span, def_id: LocalDe
|
|||||||
/// trait bounds those parameters have.
|
/// trait bounds those parameters have.
|
||||||
struct TypeWalker<'cx, 'tcx> {
|
struct TypeWalker<'cx, 'tcx> {
|
||||||
cx: &'cx LateContext<'tcx>,
|
cx: &'cx LateContext<'tcx>,
|
||||||
/// Collection of all the function's type parameters.
|
/// Collection of the function's type parameters. Once the function has been walked, this will
|
||||||
|
/// contain only unused type parameters.
|
||||||
ty_params: FxHashMap<DefId, Span>,
|
ty_params: FxHashMap<DefId, Span>,
|
||||||
/// Collection of any (inline) trait bounds corresponding to each type parameter.
|
/// Collection of any inline trait bounds corresponding to each type parameter.
|
||||||
bounds: FxHashMap<DefId, Span>,
|
inline_bounds: FxHashMap<DefId, Span>,
|
||||||
|
/// Collection of any type parameters with trait bounds that appear in a where clause.
|
||||||
|
where_bounds: FxHashSet<DefId>,
|
||||||
/// The entire `Generics` object of the function, useful for querying purposes.
|
/// The entire `Generics` object of the function, useful for querying purposes.
|
||||||
generics: &'tcx Generics<'tcx>,
|
generics: &'tcx Generics<'tcx>,
|
||||||
/// The value of this will remain `true` if *every* parameter:
|
|
||||||
/// 1. Is a type parameter, and
|
|
||||||
/// 2. Goes unused in the function.
|
|
||||||
/// Otherwise, if any type parameters end up being used, or if any lifetime or const-generic
|
|
||||||
/// parameters are present, this will be set to `false`.
|
|
||||||
all_params_unused: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
|
impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
|
||||||
fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'tcx>) -> Self {
|
fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'tcx>) -> Self {
|
||||||
let mut all_params_unused = true;
|
|
||||||
let ty_params = generics
|
let ty_params = generics
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|param| {
|
.filter_map(|param| match param.kind {
|
||||||
if let GenericParamKind::Type { synthetic, .. } = param.kind {
|
GenericParamKind::Type { synthetic, .. } if !synthetic => Some((param.def_id.into(), param.span)),
|
||||||
(!synthetic).then_some((param.def_id.into(), param.span))
|
_ => None,
|
||||||
} else {
|
|
||||||
if !param.is_elided_lifetime() {
|
|
||||||
all_params_unused = false;
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
cx,
|
cx,
|
||||||
ty_params,
|
ty_params,
|
||||||
bounds: FxHashMap::default(),
|
inline_bounds: FxHashMap::default(),
|
||||||
|
where_bounds: FxHashSet::default(),
|
||||||
generics,
|
generics,
|
||||||
all_params_unused,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mark_param_used(&mut self, def_id: DefId) {
|
fn get_bound_span(&self, param: &'tcx GenericParam<'tcx>) -> Span {
|
||||||
if self.ty_params.remove(&def_id).is_some() {
|
self.inline_bounds
|
||||||
self.all_params_unused = false;
|
.get(¶m.def_id.to_def_id())
|
||||||
}
|
.map_or(param.span, |bound_span| param.span.with_hi(bound_span.hi()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_help(&self, spans: Vec<Span>, msg: &str, help: &'static str) {
|
||||||
|
span_lint_and_help(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, spans, msg, None, help);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_sugg(&self, spans: Vec<Span>, msg: &str, help: &'static str) {
|
||||||
|
let suggestions: Vec<(Span, String)> = spans.iter().copied().zip(std::iter::repeat(String::new())).collect();
|
||||||
|
span_lint_and_then(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, spans, msg, |diag| {
|
||||||
|
diag.multipart_suggestion(help, suggestions, Applicability::MachineApplicable);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_lint(&self) {
|
fn emit_lint(&self) {
|
||||||
let (msg, help) = match self.ty_params.len() {
|
let explicit_params = self
|
||||||
|
.generics
|
||||||
|
.params
|
||||||
|
.iter()
|
||||||
|
.filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let extra_params = explicit_params
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, param)| self.ty_params.contains_key(¶m.def_id.to_def_id()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let (msg, help) = match extra_params.len() {
|
||||||
0 => return,
|
0 => return,
|
||||||
1 => (
|
1 => (
|
||||||
"type parameter goes unused in function definition",
|
format!(
|
||||||
|
"type parameter `{}` goes unused in function definition",
|
||||||
|
extra_params[0].1.name.ident()
|
||||||
|
),
|
||||||
"consider removing the parameter",
|
"consider removing the parameter",
|
||||||
),
|
),
|
||||||
_ => (
|
_ => (
|
||||||
"type parameters go unused in function definition",
|
format!(
|
||||||
|
"type parameters go unused in function definition: {}",
|
||||||
|
extra_params
|
||||||
|
.iter()
|
||||||
|
.map(|(_, param)| param.name.ident().to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
),
|
||||||
"consider removing the parameters",
|
"consider removing the parameters",
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
let source_map = self.cx.sess().source_map();
|
// If any parameters are bounded in where clauses, don't try to form a suggestion.
|
||||||
let span = if self.all_params_unused {
|
// Otherwise, the leftover where bound would produce code that wouldn't compile.
|
||||||
self.generics.span.into() // Remove the entire list of generics
|
if extra_params
|
||||||
|
.iter()
|
||||||
|
.any(|(_, param)| self.where_bounds.contains(¶m.def_id.to_def_id()))
|
||||||
|
{
|
||||||
|
let spans = extra_params
|
||||||
|
.iter()
|
||||||
|
.map(|(_, param)| self.get_bound_span(param))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
self.emit_help(spans, &msg, help);
|
||||||
} else {
|
} else {
|
||||||
MultiSpan::from_spans(
|
let spans = if explicit_params.len() == extra_params.len() {
|
||||||
self.ty_params
|
vec![self.generics.span] // Remove the entire list of generics
|
||||||
|
} else {
|
||||||
|
let mut end: Option<LocalDefId> = None;
|
||||||
|
extra_params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(def_id, &span)| {
|
.rev()
|
||||||
// Extend the span past any trait bounds, and include the comma at the end.
|
.map(|(idx, param)| {
|
||||||
let span_to_extend = self.bounds.get(def_id).copied().map_or(span, Span::shrink_to_hi);
|
if let Some(next) = explicit_params.get(idx + 1) && end != Some(next.def_id) {
|
||||||
let comma_range = source_map.span_extend_to_next_char(span_to_extend, '>', false);
|
// Extend the current span forward, up until the next param in the list.
|
||||||
let comma_span = source_map.span_through_char(comma_range, ',');
|
param.span.until(next.span)
|
||||||
span.with_hi(comma_span.hi())
|
} else {
|
||||||
})
|
// Extend the current span back to include the comma following the previous
|
||||||
.collect(),
|
// param. If the span of the next param in the list has already been
|
||||||
)
|
// extended, we continue the chain. This is why we're iterating in reverse.
|
||||||
};
|
end = Some(param.def_id);
|
||||||
|
|
||||||
span_lint_and_help(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, span, msg, None, help);
|
// idx will never be 0, else we'd be removing the entire list of generics
|
||||||
|
let prev = explicit_params[idx - 1];
|
||||||
|
let prev_span = self.get_bound_span(prev);
|
||||||
|
self.get_bound_span(param).with_lo(prev_span.hi())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
};
|
||||||
|
self.emit_sugg(spans, &msg, help);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +212,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
|
|||||||
|
|
||||||
fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
|
fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
|
||||||
if let Some((def_id, _)) = t.peel_refs().as_generic_param() {
|
if let Some((def_id, _)) = t.peel_refs().as_generic_param() {
|
||||||
self.mark_param_used(def_id);
|
self.ty_params.remove(&def_id);
|
||||||
} else if let TyKind::OpaqueDef(id, _, _) = t.kind {
|
} else if let TyKind::OpaqueDef(id, _, _) = t.kind {
|
||||||
// Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls
|
// Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls
|
||||||
// `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're
|
// `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're
|
||||||
@ -176,9 +226,18 @@ fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
|
|||||||
|
|
||||||
fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) {
|
fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) {
|
||||||
if let WherePredicate::BoundPredicate(predicate) = predicate {
|
if let WherePredicate::BoundPredicate(predicate) = predicate {
|
||||||
// Collect spans for any bounds on type parameters. We only keep bounds that appear in
|
// Collect spans for any bounds on type parameters.
|
||||||
// the list of generics (not in a where-clause).
|
|
||||||
if let Some((def_id, _)) = predicate.bounded_ty.peel_refs().as_generic_param() {
|
if let Some((def_id, _)) = predicate.bounded_ty.peel_refs().as_generic_param() {
|
||||||
|
match predicate.origin {
|
||||||
|
PredicateOrigin::GenericParam => {
|
||||||
|
self.inline_bounds.insert(def_id, predicate.span);
|
||||||
|
},
|
||||||
|
PredicateOrigin::WhereClause => {
|
||||||
|
self.where_bounds.insert(def_id);
|
||||||
|
},
|
||||||
|
PredicateOrigin::ImplTrait => (),
|
||||||
|
}
|
||||||
|
|
||||||
// If the bound contains non-public traits, err on the safe side and don't lint the
|
// If the bound contains non-public traits, err on the safe side and don't lint the
|
||||||
// corresponding parameter.
|
// corresponding parameter.
|
||||||
if !predicate
|
if !predicate
|
||||||
@ -187,12 +246,10 @@ fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) {
|
|||||||
.filter_map(bound_to_trait_def_id)
|
.filter_map(bound_to_trait_def_id)
|
||||||
.all(|id| self.cx.effective_visibilities.is_exported(id))
|
.all(|id| self.cx.effective_visibilities.is_exported(id))
|
||||||
{
|
{
|
||||||
self.mark_param_used(def_id);
|
self.ty_params.remove(&def_id);
|
||||||
} else if let PredicateOrigin::GenericParam = predicate.origin {
|
|
||||||
self.bounds.insert(def_id, predicate.span);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Only walk the right-hand side of where-bounds
|
// Only walk the right-hand side of where bounds
|
||||||
for bound in predicate.bounds {
|
for bound in predicate.bounds {
|
||||||
walk_param_bound(self, bound);
|
walk_param_bound(self, bound);
|
||||||
}
|
}
|
||||||
@ -207,7 +264,7 @@ fn nested_visit_map(&mut self) -> Self::Map {
|
|||||||
impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
|
impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
|
||||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||||
if let ItemKind::Fn(_, generics, body_id) = item.kind
|
if let ItemKind::Fn(_, generics, body_id) = item.kind
|
||||||
&& !self.check_false_positive(cx, item.span, item.owner_id.def_id, body_id)
|
&& !self.is_empty_exported_or_macro(cx, item.span, item.owner_id.def_id, body_id)
|
||||||
{
|
{
|
||||||
let mut walker = TypeWalker::new(cx, generics);
|
let mut walker = TypeWalker::new(cx, generics);
|
||||||
walk_item(&mut walker, item);
|
walk_item(&mut walker, item);
|
||||||
@ -219,7 +276,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>
|
|||||||
// Only lint on inherent methods, not trait methods.
|
// Only lint on inherent methods, not trait methods.
|
||||||
if let ImplItemKind::Fn(.., body_id) = item.kind
|
if let ImplItemKind::Fn(.., body_id) = item.kind
|
||||||
&& trait_ref_of_method(cx, item.owner_id.def_id).is_none()
|
&& trait_ref_of_method(cx, item.owner_id.def_id).is_none()
|
||||||
&& !self.check_false_positive(cx, item.span, item.owner_id.def_id, body_id)
|
&& !self.is_empty_exported_or_macro(cx, item.span, item.owner_id.def_id, body_id)
|
||||||
{
|
{
|
||||||
let mut walker = TypeWalker::new(cx, item.generics);
|
let mut walker = TypeWalker::new(cx, item.generics);
|
||||||
walk_impl_item(&mut walker, item);
|
walk_impl_item(&mut walker, item);
|
||||||
|
1
tests/ui-toml/extra_unused_type_parameters/clippy.toml
Normal file
1
tests/ui-toml/extra_unused_type_parameters/clippy.toml
Normal file
@ -0,0 +1 @@
|
|||||||
|
avoid-breaking-exported-api = true
|
@ -0,0 +1,9 @@
|
|||||||
|
pub struct S;
|
||||||
|
|
||||||
|
impl S {
|
||||||
|
pub fn exported_fn<T>() {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
105
tests/ui/extra_unused_type_parameters.fixed
Normal file
105
tests/ui/extra_unused_type_parameters.fixed
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#![allow(unused, clippy::needless_lifetimes)]
|
||||||
|
#![warn(clippy::extra_unused_type_parameters)]
|
||||||
|
|
||||||
|
fn unused_ty(x: u8) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unused_multi(x: u8) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unused_with_lt<'a>(x: &'a u8) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn used_ty<T>(x: T, y: u8) {}
|
||||||
|
|
||||||
|
fn used_ref<'a, T>(x: &'a T) {}
|
||||||
|
|
||||||
|
fn used_ret<T: Default>(x: u8) -> T {
|
||||||
|
T::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unused_bounded<U>(x: U) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn some_unused<B, C>(b: B, c: C) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn used_opaque<A>(iter: impl Iterator<Item = A>) -> usize {
|
||||||
|
iter.count()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn used_ret_opaque<A>() -> impl Iterator<Item = A> {
|
||||||
|
std::iter::empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn used_vec_box<T>(x: Vec<Box<T>>) {}
|
||||||
|
|
||||||
|
fn used_body<T: Default + ToString>() -> String {
|
||||||
|
T::default().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn used_closure<T: Default + ToString>() -> impl Fn() {
|
||||||
|
|| println!("{}", T::default().to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
impl S {
|
||||||
|
fn unused_ty_impl(&self) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't lint on trait methods
|
||||||
|
trait Foo {
|
||||||
|
fn bar<T>(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Foo for S {
|
||||||
|
fn bar<T>(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn skip_index<A, Iter>(iter: Iter, index: usize) -> impl Iterator<Item = A>
|
||||||
|
where
|
||||||
|
Iter: Iterator<Item = A>,
|
||||||
|
{
|
||||||
|
iter.enumerate()
|
||||||
|
.filter_map(move |(i, a)| if i == index { None } else { Some(a) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unused_opaque(dummy: impl Default) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
mod unexported_trait_bounds {
|
||||||
|
mod private {
|
||||||
|
pub trait Private {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn priv_trait_bound<T: private::Private>() {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unused_with_priv_trait_bound<T: private::Private>() {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod issue10319 {
|
||||||
|
fn assert_send<T: Send>() {}
|
||||||
|
|
||||||
|
fn assert_send_where<T>()
|
||||||
|
where
|
||||||
|
T: Send,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -1,3 +1,5 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
#![allow(unused, clippy::needless_lifetimes)]
|
#![allow(unused, clippy::needless_lifetimes)]
|
||||||
#![warn(clippy::extra_unused_type_parameters)]
|
#![warn(clippy::extra_unused_type_parameters)]
|
||||||
|
|
||||||
@ -21,14 +23,7 @@ fn used_ret<T: Default>(x: u8) -> T {
|
|||||||
T::default()
|
T::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unused_bounded<T: Default, U>(x: U) {
|
fn unused_bounded<T: Default, U, V: Default>(x: U) {
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unused_where_clause<T, U>(x: U)
|
|
||||||
where
|
|
||||||
T: Default,
|
|
||||||
{
|
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,75 +1,64 @@
|
|||||||
error: type parameter goes unused in function definition
|
error: type parameter `T` goes unused in function definition
|
||||||
--> $DIR/extra_unused_type_parameters.rs:4:13
|
--> $DIR/extra_unused_type_parameters.rs:6:13
|
||||||
|
|
|
|
||||||
LL | fn unused_ty<T>(x: u8) {
|
LL | fn unused_ty<T>(x: u8) {
|
||||||
| ^^^
|
| ^^^ help: consider removing the parameter
|
||||||
|
|
|
|
||||||
= help: consider removing the parameter
|
|
||||||
= note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings`
|
= note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings`
|
||||||
|
|
||||||
error: type parameters go unused in function definition
|
error: type parameters go unused in function definition: T, U
|
||||||
--> $DIR/extra_unused_type_parameters.rs:8:16
|
--> $DIR/extra_unused_type_parameters.rs:10:16
|
||||||
|
|
|
|
||||||
LL | fn unused_multi<T, U>(x: u8) {
|
LL | fn unused_multi<T, U>(x: u8) {
|
||||||
| ^^^^^^
|
| ^^^^^^ help: consider removing the parameters
|
||||||
|
|
|
||||||
= help: consider removing the parameters
|
|
||||||
|
|
||||||
error: type parameter goes unused in function definition
|
error: type parameter `T` goes unused in function definition
|
||||||
--> $DIR/extra_unused_type_parameters.rs:12:23
|
--> $DIR/extra_unused_type_parameters.rs:14:21
|
||||||
|
|
|
|
||||||
LL | fn unused_with_lt<'a, T>(x: &'a u8) {
|
LL | fn unused_with_lt<'a, T>(x: &'a u8) {
|
||||||
| ^
|
| ^^^ help: consider removing the parameter
|
||||||
|
|
|
||||||
= help: consider removing the parameter
|
|
||||||
|
|
||||||
error: type parameter goes unused in function definition
|
error: type parameters go unused in function definition: T, V
|
||||||
--> $DIR/extra_unused_type_parameters.rs:24:19
|
--> $DIR/extra_unused_type_parameters.rs:26:19
|
||||||
|
|
|
|
||||||
LL | fn unused_bounded<T: Default, U>(x: U) {
|
LL | fn unused_bounded<T: Default, U, V: Default>(x: U) {
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^^ ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: consider removing the parameters
|
||||||
|
|
|
||||||
|
LL - fn unused_bounded<T: Default, U, V: Default>(x: U) {
|
||||||
|
LL + fn unused_bounded<U>(x: U) {
|
||||||
|
|
|
|
||||||
= help: consider removing the parameter
|
|
||||||
|
|
||||||
error: type parameter goes unused in function definition
|
error: type parameters go unused in function definition: A, D, E
|
||||||
--> $DIR/extra_unused_type_parameters.rs:28:24
|
--> $DIR/extra_unused_type_parameters.rs:30:16
|
||||||
|
|
|
||||||
LL | fn unused_where_clause<T, U>(x: U)
|
|
||||||
| ^^
|
|
||||||
|
|
|
||||||
= help: consider removing the parameter
|
|
||||||
|
|
||||||
error: type parameters go unused in function definition
|
|
||||||
--> $DIR/extra_unused_type_parameters.rs:35:16
|
|
||||||
|
|
|
|
||||||
LL | fn some_unused<A, B, C, D: Iterator<Item = (B, C)>, E>(b: B, c: C) {
|
LL | fn some_unused<A, B, C, D: Iterator<Item = (B, C)>, E>(b: B, c: C) {
|
||||||
| ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^
|
| ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: consider removing the parameters
|
||||||
|
|
|
||||||
|
LL - fn some_unused<A, B, C, D: Iterator<Item = (B, C)>, E>(b: B, c: C) {
|
||||||
|
LL + fn some_unused<B, C>(b: B, c: C) {
|
||||||
|
|
|
|
||||||
= help: consider removing the parameters
|
|
||||||
|
|
||||||
error: type parameter goes unused in function definition
|
error: type parameter `T` goes unused in function definition
|
||||||
--> $DIR/extra_unused_type_parameters.rs:60:22
|
--> $DIR/extra_unused_type_parameters.rs:55:22
|
||||||
|
|
|
|
||||||
LL | fn unused_ty_impl<T>(&self) {
|
LL | fn unused_ty_impl<T>(&self) {
|
||||||
| ^^^
|
| ^^^ help: consider removing the parameter
|
||||||
|
|
|
||||||
= help: consider removing the parameter
|
|
||||||
|
|
||||||
error: type parameters go unused in function definition
|
error: type parameters go unused in function definition: A, B
|
||||||
--> $DIR/extra_unused_type_parameters.rs:82:17
|
--> $DIR/extra_unused_type_parameters.rs:77:17
|
||||||
|
|
|
|
||||||
LL | fn unused_opaque<A, B>(dummy: impl Default) {
|
LL | fn unused_opaque<A, B>(dummy: impl Default) {
|
||||||
| ^^^^^^
|
| ^^^^^^ help: consider removing the parameters
|
||||||
|
|
|
||||||
= help: consider removing the parameters
|
|
||||||
|
|
||||||
error: type parameter goes unused in function definition
|
error: type parameter `U` goes unused in function definition
|
||||||
--> $DIR/extra_unused_type_parameters.rs:95:58
|
--> $DIR/extra_unused_type_parameters.rs:90:56
|
||||||
|
|
|
|
||||||
LL | fn unused_with_priv_trait_bound<T: private::Private, U>() {
|
LL | fn unused_with_priv_trait_bound<T: private::Private, U>() {
|
||||||
| ^
|
| ^^^ help: consider removing the parameter
|
||||||
|
|
|
||||||
= help: consider removing the parameter
|
|
||||||
|
|
||||||
error: aborting due to 9 previous errors
|
error: aborting due to 8 previous errors
|
||||||
|
|
||||||
|
24
tests/ui/extra_unused_type_parameters_unfixable.rs
Normal file
24
tests/ui/extra_unused_type_parameters_unfixable.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#![warn(clippy::extra_unused_type_parameters)]
|
||||||
|
|
||||||
|
fn unused_where_clause<T, U>(x: U)
|
||||||
|
where
|
||||||
|
T: Default,
|
||||||
|
{
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unused_multi_where_clause<T, U, V: Default>(x: U)
|
||||||
|
where
|
||||||
|
T: Default,
|
||||||
|
{
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unused_all_where_clause<T, U: Default, V: Default>()
|
||||||
|
where
|
||||||
|
T: Default,
|
||||||
|
{
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
27
tests/ui/extra_unused_type_parameters_unfixable.stderr
Normal file
27
tests/ui/extra_unused_type_parameters_unfixable.stderr
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
error: type parameter `T` goes unused in function definition
|
||||||
|
--> $DIR/extra_unused_type_parameters_unfixable.rs:3:24
|
||||||
|
|
|
||||||
|
LL | fn unused_where_clause<T, U>(x: U)
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= help: consider removing the parameter
|
||||||
|
= note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: type parameters go unused in function definition: T, V
|
||||||
|
--> $DIR/extra_unused_type_parameters_unfixable.rs:10:30
|
||||||
|
|
|
||||||
|
LL | fn unused_multi_where_clause<T, U, V: Default>(x: U)
|
||||||
|
| ^ ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider removing the parameters
|
||||||
|
|
||||||
|
error: type parameters go unused in function definition: T, U, V
|
||||||
|
--> $DIR/extra_unused_type_parameters_unfixable.rs:17:28
|
||||||
|
|
|
||||||
|
LL | fn unused_all_where_clause<T, U: Default, V: Default>()
|
||||||
|
| ^ ^^^^^^^^^^ ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider removing the parameters
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
Loading…
Reference in New Issue
Block a user