diff options
Diffstat (limited to 'src/tools/clippy/clippy_lints/src/derive.rs')
-rw-r--r-- | src/tools/clippy/clippy_lints/src/derive.rs | 231 |
1 files changed, 105 insertions, 126 deletions
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 3a331564d..d8abe4110 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy}; use clippy_utils::{is_lint_allowed, match_def_path, paths}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor}; @@ -15,7 +14,7 @@ use rustc_middle::ty::{ self, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, ToPredicate, TraitPredicate, Ty, TyCtxt, }; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; @@ -232,42 +231,37 @@ fn check_hash_peq<'tcx>( ty: Ty<'tcx>, hash_is_automatically_derived: bool, ) { - if_chain! { - if let Some(peq_trait_def_id) = cx.tcx.lang_items().eq_trait(); - if let Some(def_id) = trait_ref.trait_def_id(); - if cx.tcx.is_diagnostic_item(sym::Hash, def_id); - then { - // Look for the PartialEq implementations for `ty` - cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| { - let peq_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived); - - if !hash_is_automatically_derived || peq_is_automatically_derived { - return; - } - - let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); - - // Only care about `impl PartialEq<Foo> for Foo` - // For `impl PartialEq<B> for A, input_types is [A, B] - if trait_ref.instantiate_identity().args.type_at(1) == ty { - span_lint_and_then( - cx, - DERIVED_HASH_WITH_MANUAL_EQ, - span, - "you are deriving `Hash` but have implemented `PartialEq` explicitly", - |diag| { - if let Some(local_def_id) = impl_id.as_local() { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id); - diag.span_note( - cx.tcx.hir().span(hir_id), - "`PartialEq` implemented here" - ); - } + if let Some(peq_trait_def_id) = cx.tcx.lang_items().eq_trait() + && let Some(def_id) = trait_ref.trait_def_id() + && cx.tcx.is_diagnostic_item(sym::Hash, def_id) + { + // Look for the PartialEq implementations for `ty` + cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| { + let peq_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived); + + if !hash_is_automatically_derived || peq_is_automatically_derived { + return; + } + + let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); + + // Only care about `impl PartialEq<Foo> for Foo` + // For `impl PartialEq<B> for A, input_types is [A, B] + if trait_ref.instantiate_identity().args.type_at(1) == ty { + span_lint_and_then( + cx, + DERIVED_HASH_WITH_MANUAL_EQ, + span, + "you are deriving `Hash` but have implemented `PartialEq` explicitly", + |diag| { + if let Some(local_def_id) = impl_id.as_local() { + let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id); + diag.span_note(cx.tcx.hir().span(hir_id), "`PartialEq` implemented here"); } - ); - } - }); - } + }, + ); + } + }); } } @@ -279,49 +273,38 @@ fn check_ord_partial_ord<'tcx>( ty: Ty<'tcx>, ord_is_automatically_derived: bool, ) { - if_chain! { - if let Some(ord_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Ord); - if let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait(); - if let Some(def_id) = &trait_ref.trait_def_id(); - if *def_id == ord_trait_def_id; - then { - // Look for the PartialOrd implementations for `ty` - cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| { - let partial_ord_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived); - - if partial_ord_is_automatically_derived == ord_is_automatically_derived { - return; - } - - let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); - - // Only care about `impl PartialOrd<Foo> for Foo` - // For `impl PartialOrd<B> for A, input_types is [A, B] - if trait_ref.instantiate_identity().args.type_at(1) == ty { - let mess = if partial_ord_is_automatically_derived { - "you are implementing `Ord` explicitly but have derived `PartialOrd`" - } else { - "you are deriving `Ord` but have implemented `PartialOrd` explicitly" - }; - - span_lint_and_then( - cx, - DERIVE_ORD_XOR_PARTIAL_ORD, - span, - mess, - |diag| { - if let Some(local_def_id) = impl_id.as_local() { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id); - diag.span_note( - cx.tcx.hir().span(hir_id), - "`PartialOrd` implemented here" - ); - } - } - ); - } - }); - } + if let Some(ord_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Ord) + && let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait() + && let Some(def_id) = &trait_ref.trait_def_id() + && *def_id == ord_trait_def_id + { + // Look for the PartialOrd implementations for `ty` + cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| { + let partial_ord_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived); + + if partial_ord_is_automatically_derived == ord_is_automatically_derived { + return; + } + + let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); + + // Only care about `impl PartialOrd<Foo> for Foo` + // For `impl PartialOrd<B> for A, input_types is [A, B] + if trait_ref.instantiate_identity().args.type_at(1) == ty { + let mess = if partial_ord_is_automatically_derived { + "you are implementing `Ord` explicitly but have derived `PartialOrd`" + } else { + "you are deriving `Ord` but have implemented `PartialOrd` explicitly" + }; + + span_lint_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, span, mess, |diag| { + if let Some(local_def_id) = impl_id.as_local() { + let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id); + diag.span_note(cx.tcx.hir().span(hir_id), "`PartialOrd` implemented here"); + } + }); + } + }); } } @@ -394,27 +377,27 @@ fn check_unsafe_derive_deserialize<'tcx>( visitor.has_unsafe } - if_chain! { - if let Some(trait_def_id) = trait_ref.trait_def_id(); - if match_def_path(cx, trait_def_id, &paths::SERDE_DESERIALIZE); - if let ty::Adt(def, _) = ty.kind(); - if let Some(local_def_id) = def.did().as_local(); - let adt_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id); - if !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id); - if cx.tcx.inherent_impls(def.did()) + if let Some(trait_def_id) = trait_ref.trait_def_id() + && match_def_path(cx, trait_def_id, &paths::SERDE_DESERIALIZE) + && let ty::Adt(def, _) = ty.kind() + && let Some(local_def_id) = def.did().as_local() + && let adt_hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id) + && !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id) + && cx + .tcx + .inherent_impls(def.did()) .iter() .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local())) - .any(|imp| has_unsafe(cx, imp)); - then { - span_lint_and_help( - cx, - UNSAFE_DERIVE_DESERIALIZE, - item.span, - "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`", - None, - "consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html" - ); - } + .any(|imp| has_unsafe(cx, imp)) + { + span_lint_and_help( + cx, + UNSAFE_DERIVE_DESERIALIZE, + item.span, + "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`", + None, + "consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html", + ); } } @@ -431,12 +414,10 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { return; } - if_chain! { - if let Some(header) = kind.header(); - if header.unsafety == Unsafety::Unsafe; - then { - self.has_unsafe = true; - } + if let Some(header) = kind.header() + && header.unsafety == Unsafety::Unsafe + { + self.has_unsafe = true; } walk_fn(self, kind, decl, body_id, id); @@ -463,30 +444,28 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { /// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint. fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) { - if_chain! { - if let ty::Adt(adt, args) = ty.kind(); - if cx.tcx.visibility(adt.did()).is_public(); - if let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq); - if let Some(def_id) = trait_ref.trait_def_id(); - if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id); - let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id); - if !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[]); + if let ty::Adt(adt, args) = ty.kind() + && cx.tcx.visibility(adt.did()).is_public() + && let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq) + && let Some(def_id) = trait_ref.trait_def_id() + && cx.tcx.is_diagnostic_item(sym::PartialEq, def_id) + && let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id) + && !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, adt.did(),&[]) // If all of our fields implement `Eq`, we can implement `Eq` too - if adt + && adt .all_fields() .map(|f| f.ty(cx.tcx, args)) - .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[])); - then { - span_lint_and_sugg( - cx, - DERIVE_PARTIAL_EQ_WITHOUT_EQ, - span.ctxt().outer_expn_data().call_site, - "you are deriving `PartialEq` and can implement `Eq`", - "consider deriving `Eq` as well", - "PartialEq, Eq".to_string(), - Applicability::MachineApplicable, - ) - } + .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, adt.did(), &[])) + { + span_lint_and_sugg( + cx, + DERIVE_PARTIAL_EQ_WITHOUT_EQ, + span.ctxt().outer_expn_data().call_site, + "you are deriving `PartialEq` and can implement `Eq`", + "consider deriving `Eq` as well", + "PartialEq, Eq".to_string(), + Applicability::MachineApplicable, + ); } } |