Skip to content

Commit c82ff00

Browse files
committed
Do not suggest to derive Default on generics with implicit arguments
1 parent 149392b commit c82ff00

File tree

3 files changed

+87
-8
lines changed

3 files changed

+87
-8
lines changed

Diff for: clippy_lints/src/derivable_impls.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_hir::{
88
Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, Ty, TyKind,
99
};
1010
use rustc_lint::{LateContext, LateLintPass};
11-
use rustc_middle::ty::{AdtDef, DefIdTree};
11+
use rustc_middle::ty::{Adt, AdtDef, DefIdTree, SubstsRef};
1212
use rustc_session::{declare_tool_lint, impl_lint_pass};
1313
use rustc_span::sym;
1414

@@ -81,13 +81,18 @@ fn check_struct<'tcx>(
8181
self_ty: &Ty<'_>,
8282
func_expr: &Expr<'_>,
8383
adt_def: AdtDef<'_>,
84+
substs: SubstsRef<'_>,
8485
) {
8586
if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind {
86-
if let Some(PathSegment { args: Some(a), .. }) = p.segments.last() {
87-
for arg in a.args {
88-
if !matches!(arg, GenericArg::Lifetime(_)) {
89-
return;
90-
}
87+
if let Some(PathSegment { args, .. }) = p.segments.last() {
88+
let args = args.map(|a| a.args).unwrap_or(&[]);
89+
90+
// substs contains the generic parameters of the type declaration, while args contains the arguments
91+
// used at instantiation time. If both len are not equal, it means that some parameters were not
92+
// provided (which means that the default values were used); in this case we will not risk
93+
// suggesting too broad a rewrite. We won't either if any argument is a type or a const.
94+
if substs.len() != args.len() || args.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_))) {
95+
return;
9196
}
9297
}
9398
}
@@ -184,15 +189,15 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
184189
if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir);
185190
if let ImplItemKind::Fn(_, b) = &impl_item.kind;
186191
if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b);
187-
if let Some(adt_def) = cx.tcx.type_of(item.owner_id).subst_identity().ty_adt_def();
192+
if let &Adt(adt_def, substs) = cx.tcx.type_of(item.owner_id).subst_identity().kind();
188193
if let attrs = cx.tcx.hir().attrs(item.hir_id());
189194
if !attrs.iter().any(|attr| attr.doc_str().is_some());
190195
if let child_attrs = cx.tcx.hir().attrs(impl_item_hir);
191196
if !child_attrs.iter().any(|attr| attr.doc_str().is_some());
192197

193198
then {
194199
if adt_def.is_struct() {
195-
check_struct(cx, item, self_ty, func_expr, adt_def);
200+
check_struct(cx, item, self_ty, func_expr, adt_def, substs);
196201
} else if adt_def.is_enum() && self.msrv.meets(msrvs::DEFAULT_ENUM_ATTRIBUTE) {
197202
check_enum(cx, item, func_expr, adt_def);
198203
}

Diff for: tests/ui/derivable_impls.fixed

+37
Original file line numberDiff line numberDiff line change
@@ -231,4 +231,41 @@ impl Default for NonExhaustiveEnum {
231231
}
232232
}
233233

234+
// https://github.com/rust-lang/rust-clippy/issues/10396
235+
236+
#[derive(Default)]
237+
struct DefaultType;
238+
239+
struct GenericType<T = DefaultType> {
240+
t: T,
241+
}
242+
243+
impl Default for GenericType {
244+
fn default() -> Self {
245+
Self { t: Default::default() }
246+
}
247+
}
248+
249+
struct InnerGenericType<T> {
250+
t: T,
251+
}
252+
253+
impl Default for InnerGenericType<DefaultType> {
254+
fn default() -> Self {
255+
Self { t: Default::default() }
256+
}
257+
}
258+
259+
struct OtherGenericType<T = DefaultType> {
260+
inner: InnerGenericType<T>,
261+
}
262+
263+
impl Default for OtherGenericType {
264+
fn default() -> Self {
265+
Self {
266+
inner: Default::default(),
267+
}
268+
}
269+
}
270+
234271
fn main() {}

Diff for: tests/ui/derivable_impls.rs

+37
Original file line numberDiff line numberDiff line change
@@ -267,4 +267,41 @@ impl Default for NonExhaustiveEnum {
267267
}
268268
}
269269

270+
// https://github.com/rust-lang/rust-clippy/issues/10396
271+
272+
#[derive(Default)]
273+
struct DefaultType;
274+
275+
struct GenericType<T = DefaultType> {
276+
t: T,
277+
}
278+
279+
impl Default for GenericType {
280+
fn default() -> Self {
281+
Self { t: Default::default() }
282+
}
283+
}
284+
285+
struct InnerGenericType<T> {
286+
t: T,
287+
}
288+
289+
impl Default for InnerGenericType<DefaultType> {
290+
fn default() -> Self {
291+
Self { t: Default::default() }
292+
}
293+
}
294+
295+
struct OtherGenericType<T = DefaultType> {
296+
inner: InnerGenericType<T>,
297+
}
298+
299+
impl Default for OtherGenericType {
300+
fn default() -> Self {
301+
Self {
302+
inner: Default::default(),
303+
}
304+
}
305+
}
306+
270307
fn main() {}

0 commit comments

Comments
 (0)