From 8cb2ec804dced5435aaea7f465eccddcdeddba19 Mon Sep 17 00:00:00 2001 From: sinkuu Date: Fri, 17 Feb 2017 19:59:52 +0900 Subject: [PATCH] Support generic type --- clippy_lints/src/assign_ops.rs | 2 +- clippy_lints/src/methods.rs | 4 ++-- clippy_lints/src/misc.rs | 2 +- clippy_lints/src/new_without_default.rs | 4 ++-- clippy_lints/src/should_assert_eq.rs | 18 ++++++++++++------ clippy_lints/src/utils/mod.rs | 12 +++++++++--- clippy_lints/src/utils/paths.rs | 1 - tests/ui/should_assert_eq.rs | 7 +++++++ tests/ui/should_assert_eq.stderr | 10 +++++++++- 9 files changed, 43 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index 71ebb996fc57..ea3e29cff122 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -152,7 +152,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps { let hir::Item_::ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node, trait_ref.path.def.def_id() == trait_id ], { return; }} - implements_trait($cx, $ty, trait_id, vec![$rty]) + implements_trait($cx, $ty, trait_id, &[$rty], None) },)* _ => false, } diff --git a/clippy_lints/src/methods.rs b/clippy_lints/src/methods.rs index b74bd9266a45..9acf4c7e973a 100644 --- a/clippy_lints/src/methods.rs +++ b/clippy_lints/src/methods.rs @@ -724,7 +724,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir: return false; }; - if implements_trait(cx, arg_ty, default_trait_id, Vec::new()) { + if implements_trait(cx, arg_ty, default_trait_id, &[], None) { span_lint_and_then(cx, OR_FUN_CALL, span, @@ -1268,7 +1268,7 @@ fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option> { /// This checks whether a given type is known to implement Debug. fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool { match cx.tcx.lang_items.debug_trait() { - Some(debug) => implements_trait(cx, ty, debug, Vec::new()), + Some(debug) => implements_trait(cx, ty, debug, &[], None), None => false, } } diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index d397d4251117..d2f794def0cf 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -420,7 +420,7 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr, left: bool, op: S None => return, }; - if !implements_trait(cx, arg_ty, partial_eq_trait_id, vec![other_ty]) { + if !implements_trait(cx, arg_ty, partial_eq_trait_id, &[other_ty], None) { return; } diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index e4e98c260388..ece7e130c5fb 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -115,7 +115,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { self_ty.walk_shallow().next().is_none(), // implements_trait does not work with generics same_tys(cx, self_ty, return_ty(cx, id), id), let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT), - !implements_trait(cx, self_ty, default_trait_id, Vec::new()) + !implements_trait(cx, self_ty, default_trait_id, &[], None) ], { if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) { span_lint_and_then(cx, @@ -156,7 +156,7 @@ fn can_derive_default<'t, 'c>(ty: ty::Ty<'t>, cx: &LateContext<'c, 't>, default_ ty::TyAdt(adt_def, substs) if adt_def.is_struct() => { for field in adt_def.all_fields() { let f_ty = field.ty(cx.tcx, substs); - if !implements_trait(cx, f_ty, default_trait_id, Vec::new()) { + if !implements_trait(cx, f_ty, default_trait_id, &[], None) { return None; } } diff --git a/clippy_lints/src/should_assert_eq.rs b/clippy_lints/src/should_assert_eq.rs index 9bacc64f61c0..16933ea27474 100644 --- a/clippy_lints/src/should_assert_eq.rs +++ b/clippy_lints/src/should_assert_eq.rs @@ -1,13 +1,13 @@ use rustc::lint::*; use rustc::hir::*; -use utils::{paths, is_direct_expn_of, get_trait_def_id, implements_trait, span_lint}; +use utils::{is_direct_expn_of, implements_trait, span_lint}; /// **What it does:** Checks for `assert!(x == y)` which can be written better /// as `assert_eq!(x, y)` if `x` and `y` implement `Debug` trait. /// /// **Why is this bad?** `assert_eq` provides better assertion failure reporting. /// -/// **Known problems:** None. +/// **Known problems:** Hopefully none. /// /// **Example:** /// ```rust @@ -45,13 +45,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ShouldAssertEq { return; } - let debug_trait = get_trait_def_id(cx, &paths::DEBUG_TRAIT) - .expect("cannot find Debug trait"); + let debug_trait = if let Some(t) = cx.tcx.lang_items.debug_trait() { + t + } else { + return; + }; let ty1 = cx.tables.expr_ty(expr1); let ty2 = cx.tables.expr_ty(expr2); - if implements_trait(cx, ty1, debug_trait, vec![]) && - implements_trait(cx, ty2, debug_trait, vec![]) { + + let parent = cx.tcx.hir.get_parent(e.id); + + if implements_trait(cx, ty1, debug_trait, &[], Some(parent)) && + implements_trait(cx, ty2, debug_trait, &[], Some(parent)) { span_lint(cx, SHOULD_ASSERT_EQ, e.span, "use `assert_eq` for better reporting"); } }} diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 1211b77ddb87..ce581febfe41 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -317,13 +317,19 @@ pub fn implements_trait<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, trait_id: DefId, - ty_params: Vec> + ty_params: &[ty::Ty<'tcx>], + parent_node_id: Option ) -> bool { cx.tcx.populate_implementations_for_trait_if_necessary(trait_id); let ty = cx.tcx.erase_regions(&ty); - cx.tcx.infer_ctxt((), Reveal::All).enter(|infcx| { - let obligation = cx.tcx.predicate_for_trait_def(traits::ObligationCause::dummy(), trait_id, 0, ty, &ty_params); + let mut b = if let Some(id) = parent_node_id { + cx.tcx.infer_ctxt(BodyId { node_id: id }, Reveal::All) + } else { + cx.tcx.infer_ctxt((), Reveal::All) + }; + b.enter(|infcx| { + let obligation = cx.tcx.predicate_for_trait_def(traits::ObligationCause::dummy(), trait_id, 0, ty, ty_params); traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation) }) diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 6ee35e3bd966..5edff76d9969 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -15,7 +15,6 @@ pub const CMP_MIN: [&'static str; 3] = ["core", "cmp", "min"]; pub const COW: [&'static str; 3] = ["collections", "borrow", "Cow"]; pub const CSTRING_NEW: [&'static str; 5] = ["std", "ffi", "c_str", "CString", "new"]; pub const DEBUG_FMT_METHOD: [&'static str; 4] = ["core", "fmt", "Debug", "fmt"]; -pub const DEBUG_TRAIT: [&'static str; 3] = ["core", "fmt", "Debug"]; pub const DEFAULT_TRAIT: [&'static str; 3] = ["core", "default", "Default"]; pub const DISPLAY_FMT_METHOD: [&'static str; 4] = ["core", "fmt", "Display", "fmt"]; pub const DROP: [&'static str; 3] = ["core", "mem", "drop"]; diff --git a/tests/ui/should_assert_eq.rs b/tests/ui/should_assert_eq.rs index 41e3a4113833..5abf35664259 100644 --- a/tests/ui/should_assert_eq.rs +++ b/tests/ui/should_assert_eq.rs @@ -13,4 +13,11 @@ fn main() { assert!(1 == 2); assert!(Debug(1) == Debug(2)); assert!(NonDebug(1) == NonDebug(1)); // ok + + test_generic(1, 2, 3, 4); +} + +fn test_generic(x: T, y: T, z: U, w: U) { + assert!(x == y); + assert!(z == w); // ok } diff --git a/tests/ui/should_assert_eq.stderr b/tests/ui/should_assert_eq.stderr index 3c51dbe0a9c4..68d287fda8d5 100644 --- a/tests/ui/should_assert_eq.stderr +++ b/tests/ui/should_assert_eq.stderr @@ -19,5 +19,13 @@ error: use `assert_eq` for better reporting | = note: this error originates in a macro outside of the current crate -error: aborting due to 2 previous errors +error: use `assert_eq` for better reporting + --> $DIR/should_assert_eq.rs:21:5 + | +21 | assert!(x == y); + | ^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: aborting due to 3 previous errors