diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index a30cd87554c5..0b34bb99bc7f 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc::ty; use rustc::hir::*; -use utils::{snippet_opt, span_lint_and_then, is_adjusted}; +use utils::{snippet_opt, span_lint_and_then, is_adjusted, iter_input_pats}; #[allow(missing_copy_implementations)] pub struct EtaPass; @@ -49,7 +49,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaPass { fn check_closure(cx: &LateContext, expr: &Expr) { if let ExprClosure(_, ref decl, eid, _) = expr.node { - let ex = cx.tcx.map.body(eid).value; + let body = cx.tcx.map.body(eid); + let ex = body.value; if let ExprCall(ref caller, ref args) = ex.node { if args.len() != decl.inputs.len() { // Not the same number of arguments, there @@ -71,8 +72,8 @@ fn check_closure(cx: &LateContext, expr: &Expr) { }, _ => (), } - for (a1, a2) in decl.inputs.iter().zip(args) { - if let PatKind::Binding(_, _, ident, _) = a1.node { + for (a1, a2) in iter_input_pats(decl, body).zip(args) { + if let PatKind::Binding(_, _, ident, _) = a1.pat.node { // XXXManishearth Should I be checking the binding mode here? if let ExprPath(QPath::Resolved(None, ref p)) = a2.node { if p.segments.len() != 1 { diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 18bc644a2638..784bca403772 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -6,7 +6,7 @@ use std::collections::HashSet; use syntax::ast; use syntax::abi::Abi; use syntax::codemap::Span; -use utils::{span_lint, type_is_unsafe_function}; +use utils::{span_lint, type_is_unsafe_function, iter_input_pats}; /// **What it does:** Checks for functions with too many parameters. /// @@ -102,7 +102,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions { } } - self.check_raw_ptr(cx, unsafety, decl, &body.value, nodeid); + self.check_raw_ptr(cx, unsafety, decl, &body, nodeid); } fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) { @@ -113,8 +113,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions { } if let hir::TraitMethod::Provided(eid) = eid { - let expr = cx.tcx.map.body(eid).value; - self.check_raw_ptr(cx, sig.unsafety, &sig.decl, &expr, item.id); + let body = cx.tcx.map.body(eid); + self.check_raw_ptr(cx, sig.unsafety, &sig.decl, &body, item.id); } } } @@ -136,11 +136,14 @@ impl<'a, 'tcx> Functions { cx: &LateContext<'a, 'tcx>, unsafety: hir::Unsafety, decl: &'tcx hir::FnDecl, - expr: &'tcx hir::Expr, + body: &'tcx hir::Body, nodeid: ast::NodeId ) { + let expr = &body.value; if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(nodeid) { - let raw_ptrs = decl.inputs.iter().filter_map(|arg| raw_ptr_arg(cx, arg)).collect::>(); + let raw_ptrs = iter_input_pats(&decl, body).zip(decl.inputs.iter()) + .filter_map(|(arg, ty)| raw_ptr_arg(arg, ty)) + .collect::>(); if !raw_ptrs.is_empty() { let mut v = DerefVisitor { @@ -154,8 +157,8 @@ impl<'a, 'tcx> Functions { } } -fn raw_ptr_arg(cx: &LateContext, arg: &hir::Arg) -> Option { - if let (&hir::PatKind::Binding(_, def_id, _, _), &hir::TyPtr(_)) = (&arg.pat.node, &cx.tcx.map.get(arg.id)) { +fn raw_ptr_arg(arg: &hir::Arg, ty: &hir::Ty) -> Option { + if let (&hir::PatKind::Binding(_, def_id, _, _), hir::TyPtr(_)) = (&arg.pat.node, ty.node) { Some(def_id) } else { None diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 9cd47a8f0566..fa4a5bf67573 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -104,7 +104,7 @@ fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[TraitItemRef] if !trait_items.iter().any(|i| is_named_self(cx, i, "is_empty")) { if let Some(i) = trait_items.iter().find(|i| is_named_self(cx, i, "len")) { - if cx.access_levels.is_exported(i.id) { + if cx.access_levels.is_exported(i.id.node_id) { span_lint(cx, LEN_WITHOUT_IS_EMPTY, i.span, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b902d18d1849..cdcb271d8d75 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -8,6 +8,7 @@ #![feature(slice_patterns)] #![feature(stmt_expr_attributes)] #![feature(repeat_str)] +#![feature(conservative_impl_trait)] #![allow(indexing_slicing, shadow_reuse, unknown_lints, missing_docs_in_private_items)] #![allow(needless_lifetimes)] diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 1418a18d3c55..311eb16514b9 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc::hir::*; use syntax::ast; use utils::{is_adjusted, match_path, match_trait_method, match_type, remove_blocks, paths, snippet, - span_help_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; + span_help_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, iter_input_pats}; /// **What it does:** Checks for mapping `clone()` over an iterator. /// @@ -31,18 +31,20 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { if &*name.node.as_str() == "map" && args.len() == 2 { match args[1].node { ExprClosure(_, ref decl, closure_eid, _) => { - let closure_expr = remove_blocks(&cx.tcx.map.body(closure_eid).value); + let body = cx.tcx.map.body(closure_eid); + let closure_expr = remove_blocks(&body.value); if_let_chain! {[ // nothing special in the argument, besides reference bindings // (e.g. .map(|&x| x) ) - let Some(arg_ident) = get_arg_name(&*decl.inputs[0]), + let Some(first_arg) = iter_input_pats(decl, body).next(), + let Some(arg_ident) = get_arg_name(&first_arg.pat), // the method is being called on a known type (option or iterator) let Some(type_name) = get_type_name(cx, expr, &args[0]) ], { // look for derefs, for .map(|x| *x) if only_derefs(cx, &*closure_expr, arg_ident) && // .cloned() only removes one level of indirection, don't lint on more - walk_ptrs_ty_depth(cx.tcx.tables().pat_ty(&*decl.inputs[0])).1 == 1 + walk_ptrs_ty_depth(cx.tcx.tables().pat_ty(&first_arg.pat)).1 == 1 { span_help_and_lint(cx, MAP_CLONE, expr.span, &format!( "you seem to be using .map() to clone the contents of an {}, consider \ diff --git a/clippy_lints/src/methods.rs b/clippy_lints/src/methods.rs index c6986cb5456e..ab84a7f927db 100644 --- a/clippy_lints/src/methods.rs +++ b/clippy_lints/src/methods.rs @@ -11,7 +11,7 @@ use syntax::codemap::Span; use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, is_copy, match_path, match_trait_method, match_type, method_chain_args, return_ty, same_tys, snippet, span_lint, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, last_path_segment, single_segment_path, - match_def_path, is_self}; + match_def_path, is_self, iter_input_pats}; use utils::paths; use utils::sugg; @@ -636,8 +636,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { let parent = cx.tcx.map.get_parent(implitem.id); let item = cx.tcx.map.expect_item(parent); if_let_chain! {[ - let hir::ImplItemKind::Method(ref sig, _) = implitem.node, - let Some(first_arg) = sig.decl.inputs.get(0), + let hir::ImplItemKind::Method(ref sig, id) = implitem.node, + let body = cx.tcx.map.body(id), + let Some(first_arg) = iter_input_pats(&sig.decl, body).next(), let hir::ItemImpl(_, _, _, None, _, _) = item.node, ], { // check missing trait implementations @@ -645,7 +646,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { if &*name.as_str() == method_name && sig.decl.inputs.len() == n_args && out_type.matches(&sig.decl.output) && - self_kind.matches(&**first_arg, false) { + self_kind.matches(&first_arg, false) { span_lint(cx, SHOULD_IMPLEMENT_TRAIT, implitem.span, &format!( "defining a method called `{}` on this type; consider implementing \ the `{}` trait or choosing a less ambiguous name", name, trait_name)); @@ -658,8 +659,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { for &(ref conv, self_kinds) in &CONVENTIONS { if_let_chain! {[ conv.check(&name.as_str()), - let Some(explicit_self) = sig.decl.inputs.get(0), - !self_kinds.iter().any(|k| k.matches(&**explicit_self, is_copy)), + !self_kinds.iter().any(|k| k.matches(&first_arg, is_copy)), ], { let lint = if item.vis == hir::Visibility::Public { WRONG_PUB_SELF_CONVENTION @@ -668,7 +668,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { }; span_lint(cx, lint, - explicit_self.span, + first_arg.pat.span, &format!("methods called `{}` usually take {}; consider choosing a less \ ambiguous name", conv, @@ -684,7 +684,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { !ret_ty.walk().any(|t| same_tys(cx, t, ty, implitem.id)) { span_lint(cx, NEW_RET_NO_SELF, - first_arg.span, + implitem.span, "methods called `new` usually return `Self`"); } }} diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index e81b9c989cd4..4af47d731726 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -9,7 +9,7 @@ use rustc_const_eval::eval_const_expr_partial; use rustc_const_math::ConstFloat; use syntax::codemap::{Span, Spanned, ExpnFormat}; use utils::{get_item_name, get_parent_expr, implements_trait, in_macro, is_integer_literal, match_path, snippet, - span_lint, span_lint_and_then, walk_ptrs_ty, last_path_segment}; + span_lint, span_lint_and_then, walk_ptrs_ty, last_path_segment, iter_input_pats}; use utils::sugg::Sugg; /// **What it does:** Checks for function arguments and let bindings denoted as `ref`. @@ -175,7 +175,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { cx: &LateContext<'a, 'tcx>, k: FnKind<'tcx>, decl: &'tcx FnDecl, - _: &'tcx Body, + body: &'tcx Body, _: Span, _: NodeId ) { @@ -183,11 +183,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { // Does not apply to closures return; } - for arg in &decl.inputs { - if let PatKind::Binding(BindByRef(_), _, _, _) = arg.node { + for arg in iter_input_pats(decl, body) { + if let PatKind::Binding(BindByRef(_), _, _, _) = arg.pat.node { span_lint(cx, TOPLEVEL_REF_ARG, - arg.span, + arg.pat.span, "`ref` directly on a function argument is ignored. Consider using a reference type instead."); } } diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 17160a5a1244..6cf8a337be1a 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -4,7 +4,7 @@ use rustc::hir::*; use rustc::hir::intravisit::{Visitor, FnKind, NestedVisitorMap}; use rustc::ty; use syntax::codemap::Span; -use utils::{higher, in_external_macro, snippet, span_lint_and_then}; +use utils::{higher, in_external_macro, snippet, span_lint_and_then, iter_input_pats}; /// **What it does:** Checks for bindings that shadow other bindings already in /// scope, while just changing reference level or mutability. @@ -92,18 +92,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { if in_external_macro(cx, body.value.span) { return; } - check_fn(cx, decl, &body.value); + check_fn(cx, decl, &body); } } -fn check_fn<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: &'tcx FnDecl, expr: &'tcx Expr) { +fn check_fn<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: &'tcx FnDecl, body: &'tcx Body) { let mut bindings = Vec::new(); - for arg in &decl.inputs { - if let PatKind::Binding(_, _, ident, _) = arg.node { + for arg in iter_input_pats(decl, body) { + if let PatKind::Binding(_, _, ident, _) = arg.pat.node { bindings.push((ident.node, ident.span)) } } - check_expr(cx, expr, &mut bindings); + check_expr(cx, &body.value, &mut bindings); } fn check_block<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, block: &'tcx Block, bindings: &mut Vec<(Name, Span)>) { diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 5f6b1777c129..9dc623dbe5f0 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -906,3 +906,6 @@ pub fn is_self(slf: &Arg) -> bool { } } +pub fn iter_input_pats<'tcx>(decl: &FnDecl, body: &'tcx Body) -> impl Iterator { + (0..decl.inputs.len()).map(move |i| &body.arguments[i]) +} \ No newline at end of file