diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index b24e0cdfced..87e92c2bd24 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -1,4 +1,6 @@ -use crate::utils::{get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, SpanlessEq}; +use crate::utils::{ + get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, trait_ref_of_method, SpanlessEq, +}; use crate::utils::{higher, sugg}; use if_chain::if_chain; use rustc::hir; @@ -140,13 +142,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps { }; // check that we are not inside an `impl AssignOp` of this exact operation let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id); - let parent_impl = cx.tcx.hir().get_parent_item(parent_fn); - // the crate node is the only one that is not in the map if_chain! { - if parent_impl != hir::CRATE_HIR_ID; - if let hir::Node::Item(item) = cx.tcx.hir().get_by_hir_id(parent_impl); - if let hir::ItemKind::Impl(_, _, _, _, Some(trait_ref), _, _) = - &item.node; + if let Some(trait_ref) = trait_ref_of_method(cx, parent_fn); if trait_ref.path.def.def_id() == trait_id; then { return; } } diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 19757f32e6b..5bc949a6688 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,5 +1,4 @@ -use crate::utils::{is_entrypoint_fn, span_lint}; -use if_chain::if_chain; +use crate::utils::{is_entrypoint_fn, span_lint, trait_ref_of_method}; use rustc::hir; use rustc::hir::intravisit::FnKind; use rustc::hir::{Body, Constness, FnDecl, HirId}; @@ -96,7 +95,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingConstForFn { } }, FnKind::Method(_, sig, ..) => { - if is_trait_method(cx, hir_id) || already_const(sig.header) { + if trait_ref_of_method(cx, hir_id).is_some() || already_const(sig.header) { return; } }, @@ -115,18 +114,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingConstForFn { } } -fn is_trait_method(cx: &LateContext<'_, '_>, hir_id: HirId) -> bool { - // Get the implemented trait for the current function - let parent_impl = cx.tcx.hir().get_parent_item(hir_id); - if_chain! { - if parent_impl != hir::CRATE_HIR_ID; - if let hir::Node::Item(item) = cx.tcx.hir().get_by_hir_id(parent_impl); - if let hir::ItemKind::Impl(_, _, _, _, Some(_trait_ref), _, _) = &item.node; - then { return true; } - } - false -} - // We don't have to lint on something that's already `const` fn already_const(header: hir::FnHeader) -> bool { header.constness == Constness::Const diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 0b242d614d0..76ca1dc2848 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -1,4 +1,4 @@ -use crate::utils::{get_trait_def_id, span_lint}; +use crate::utils::{get_trait_def_id, span_lint, trait_ref_of_method}; use if_chain::if_chain; use rustc::hir; use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; @@ -177,12 +177,9 @@ fn check_binop<'a>( // Get the actually implemented trait let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id); - let parent_impl = cx.tcx.hir().get_parent_item(parent_fn); if_chain! { - if parent_impl != hir::CRATE_HIR_ID; - if let hir::Node::Item(item) = cx.tcx.hir().get_by_hir_id(parent_impl); - if let hir::ItemKind::Impl(_, _, _, _, Some(ref trait_ref), _, _) = item.node; + if let Some(trait_ref) = trait_ref_of_method(cx, parent_fn); if let Some(idx) = trait_ids.iter().position(|&tid| tid == trait_ref.path.def.def_id()); if binop != expected_ops[idx]; then{ diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index f6b9a77a573..96e42121886 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -301,6 +301,33 @@ pub fn implements_trait<'a, 'tcx>( .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) } +/// Get the `hir::TraitRef` of the trait the given method is implemented for +/// +/// Use this if you want to find the `TraitRef` of the `Add` trait in this example: +/// +/// ```rust +/// struct Point(isize, isize); +/// +/// impl std::ops::Add for Point { +/// type Output = Self; +/// +/// fn add(self, other: Self) -> Self { +/// Point(0, 0) +/// } +/// } +/// ``` +pub fn trait_ref_of_method(cx: &LateContext<'_, '_>, hir_id: HirId) -> Option { + // Get the implemented trait for the current function + let parent_impl = cx.tcx.hir().get_parent_item(hir_id); + if_chain! { + if parent_impl != hir::CRATE_HIR_ID; + if let hir::Node::Item(item) = cx.tcx.hir().get_by_hir_id(parent_impl); + if let hir::ItemKind::Impl(_, _, _, _, trait_ref, _, _) = &item.node; + then { return trait_ref.clone(); } + } + None +} + /// Check whether this type implements Drop. pub fn has_drop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.ty_adt_def() {