diff --git a/clippy_lints/src/needless_maybe_sized.rs b/clippy_lints/src/needless_maybe_sized.rs index 4bcd26c74f57..e7ae54e0d0e1 100644 --- a/clippy_lints/src/needless_maybe_sized.rs +++ b/clippy_lints/src/needless_maybe_sized.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_from_proc_macro; use rustc_errors::Applicability; use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_hir::{BoundPolarity, GenericBound, Generics, PolyTraitRef, TraitBoundModifiers, WherePredicateKind}; @@ -34,6 +35,7 @@ declare_clippy_lint! { declare_lint_pass!(NeedlessMaybeSized => [NEEDLESS_MAYBE_SIZED]); #[expect(clippy::struct_field_names)] +#[derive(Debug)] struct Bound<'tcx> { /// The [`DefId`] of the type parameter the bound refers to param: DefId, @@ -127,6 +129,7 @@ impl LateLintPass<'_> for NeedlessMaybeSized { if bound.trait_bound.modifiers == TraitBoundModifiers::NONE && let Some(sized_bound) = maybe_sized_params.get(&bound.param) && let Some(path) = path_to_sized_bound(cx, bound.trait_bound) + && !is_from_proc_macro(cx, bound.trait_bound) { span_lint_and_then( cx, diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index ff3e7b94f03b..2ae3713d427d 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -21,10 +21,10 @@ use rustc_ast::ast::{ use rustc_ast::token::CommentKind; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl, - ImplItem, ImplItemImplKind, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, - QPath, Safety, TraitImplHeader, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, - YieldSource, + Block, BlockCheckMode, Body, BoundConstness, BoundPolarity, Closure, Destination, Expr, ExprKind, FieldDef, + FnHeader, FnRetTy, HirId, Impl, ImplItem, ImplItemImplKind, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, + MatchSource, MutTy, Node, Path, PolyTraitRef, QPath, Safety, TraitBoundModifiers, TraitImplHeader, TraitItem, + TraitItemKind, TraitRef, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource, }; use rustc_lint::{EarlyContext, LateContext, LintContext}; use rustc_middle::ty::TyCtxt; @@ -537,6 +537,44 @@ fn ast_ty_search_pat(ty: &ast::Ty) -> (Pat, Pat) { } } +// NOTE: can't `impl WithSearchPat for TraitRef`, because `TraitRef` doesn't have a `span` field +// (nor a method) +fn trait_ref_search_pat(trait_ref: &TraitRef<'_>) -> (Pat, Pat) { + path_search_pat(trait_ref.path) +} + +fn poly_trait_ref_search_pat(poly_trait_ref: &PolyTraitRef<'_>) -> (Pat, Pat) { + // NOTE: unfortunately we can't use `bound_generic_params` to see whether the pattern starts with + // `for<..>`, because if it's empty, we could have either `for<>` (nothing bound), or + // no `for` at all + let PolyTraitRef { + modifiers: TraitBoundModifiers { constness, polarity }, + trait_ref, + .. + } = poly_trait_ref; + + let trait_ref_search_pat = trait_ref_search_pat(trait_ref); + + #[expect( + clippy::unnecessary_lazy_evaluations, + reason = "the closure in `or_else` has `match polarity`, which isn't free" + )] + let start = match constness { + BoundConstness::Never => None, + BoundConstness::Maybe(_) => Some(Pat::Str("[const]")), + BoundConstness::Always(_) => Some(Pat::Str("const")), + } + .or_else(|| match polarity { + BoundPolarity::Negative(_) => Some(Pat::Str("!")), + BoundPolarity::Maybe(_) => Some(Pat::Str("?")), + BoundPolarity::Positive => None, + }) + .unwrap_or(trait_ref_search_pat.0); + let end = trait_ref_search_pat.1; + + (start, end) +} + fn ident_search_pat(ident: Ident) -> (Pat, Pat) { (Pat::Sym(ident.name), Pat::Sym(ident.name)) } @@ -569,6 +607,7 @@ impl_with_search_pat!((_cx: LateContext<'tcx>, self: Ty<'_>) => ty_search_pat(se impl_with_search_pat!((_cx: LateContext<'tcx>, self: Ident) => ident_search_pat(*self)); impl_with_search_pat!((_cx: LateContext<'tcx>, self: Lit) => lit_search_pat(&self.node)); impl_with_search_pat!((_cx: LateContext<'tcx>, self: Path<'_>) => path_search_pat(self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: PolyTraitRef<'_>) => poly_trait_ref_search_pat(self)); impl_with_search_pat!((_cx: EarlyContext<'tcx>, self: Attribute) => attr_search_pat(self)); impl_with_search_pat!((_cx: EarlyContext<'tcx>, self: ast::Ty) => ast_ty_search_pat(self)); diff --git a/tests/ui/needless_maybe_sized.fixed b/tests/ui/needless_maybe_sized.fixed index f8b164396990..92840a888ada 100644 --- a/tests/ui/needless_maybe_sized.fixed +++ b/tests/ui/needless_maybe_sized.fixed @@ -133,4 +133,13 @@ struct InDerive { struct Refined(T); impl Refined {} +// in proc-macros +fn issue13360() { + #[derive(serde::Serialize)] + #[serde(bound = "T: A")] + struct Foo { + t: std::marker::PhantomData, + } +} + fn main() {} diff --git a/tests/ui/needless_maybe_sized.rs b/tests/ui/needless_maybe_sized.rs index e4312b40563f..02242260af1f 100644 --- a/tests/ui/needless_maybe_sized.rs +++ b/tests/ui/needless_maybe_sized.rs @@ -136,4 +136,13 @@ struct InDerive { struct Refined(T); impl Refined {} +// in proc-macros +fn issue13360() { + #[derive(serde::Serialize)] + #[serde(bound = "T: A")] + struct Foo { + t: std::marker::PhantomData, + } +} + fn main() {}