1
Fork 0

Rustup to rustc 1.16.0-nightly (468227129 2017-01-03): Recover patterns from arguments

This commit is contained in:
Manish Goregaokar 2017-01-04 13:46:41 -08:00
parent a262e3bb0b
commit e02fac4896
9 changed files with 46 additions and 36 deletions

View file

@ -1,7 +1,7 @@
use rustc::lint::*; use rustc::lint::*;
use rustc::ty; use rustc::ty;
use rustc::hir::*; 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)] #[allow(missing_copy_implementations)]
pub struct EtaPass; pub struct EtaPass;
@ -49,7 +49,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaPass {
fn check_closure(cx: &LateContext, expr: &Expr) { fn check_closure(cx: &LateContext, expr: &Expr) {
if let ExprClosure(_, ref decl, eid, _) = expr.node { 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 let ExprCall(ref caller, ref args) = ex.node {
if args.len() != decl.inputs.len() { if args.len() != decl.inputs.len() {
// Not the same number of arguments, there // 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) { for (a1, a2) in iter_input_pats(decl, body).zip(args) {
if let PatKind::Binding(_, _, ident, _) = a1.node { if let PatKind::Binding(_, _, ident, _) = a1.pat.node {
// XXXManishearth Should I be checking the binding mode here? // XXXManishearth Should I be checking the binding mode here?
if let ExprPath(QPath::Resolved(None, ref p)) = a2.node { if let ExprPath(QPath::Resolved(None, ref p)) = a2.node {
if p.segments.len() != 1 { if p.segments.len() != 1 {

View file

@ -6,7 +6,7 @@ use std::collections::HashSet;
use syntax::ast; use syntax::ast;
use syntax::abi::Abi; use syntax::abi::Abi;
use syntax::codemap::Span; 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. /// **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) { 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 { if let hir::TraitMethod::Provided(eid) = eid {
let expr = cx.tcx.map.body(eid).value; let body = cx.tcx.map.body(eid);
self.check_raw_ptr(cx, sig.unsafety, &sig.decl, &expr, item.id); self.check_raw_ptr(cx, sig.unsafety, &sig.decl, &body, item.id);
} }
} }
} }
@ -136,11 +136,14 @@ impl<'a, 'tcx> Functions {
cx: &LateContext<'a, 'tcx>, cx: &LateContext<'a, 'tcx>,
unsafety: hir::Unsafety, unsafety: hir::Unsafety,
decl: &'tcx hir::FnDecl, decl: &'tcx hir::FnDecl,
expr: &'tcx hir::Expr, body: &'tcx hir::Body,
nodeid: ast::NodeId nodeid: ast::NodeId
) { ) {
let expr = &body.value;
if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(nodeid) { 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::<HashSet<_>>(); let raw_ptrs = iter_input_pats(&decl, body).zip(decl.inputs.iter())
.filter_map(|(arg, ty)| raw_ptr_arg(arg, ty))
.collect::<HashSet<_>>();
if !raw_ptrs.is_empty() { if !raw_ptrs.is_empty() {
let mut v = DerefVisitor { let mut v = DerefVisitor {
@ -154,8 +157,8 @@ impl<'a, 'tcx> Functions {
} }
} }
fn raw_ptr_arg(cx: &LateContext, arg: &hir::Arg) -> Option<hir::def_id::DefId> { fn raw_ptr_arg(arg: &hir::Arg, ty: &hir::Ty) -> Option<hir::def_id::DefId> {
if let (&hir::PatKind::Binding(_, def_id, _, _), &hir::TyPtr(_)) = (&arg.pat.node, &cx.tcx.map.get(arg.id)) { if let (&hir::PatKind::Binding(_, def_id, _, _), hir::TyPtr(_)) = (&arg.pat.node, ty.node) {
Some(def_id) Some(def_id)
} else { } else {
None None

View file

@ -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 !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 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, span_lint(cx,
LEN_WITHOUT_IS_EMPTY, LEN_WITHOUT_IS_EMPTY,
i.span, i.span,

View file

@ -8,6 +8,7 @@
#![feature(slice_patterns)] #![feature(slice_patterns)]
#![feature(stmt_expr_attributes)] #![feature(stmt_expr_attributes)]
#![feature(repeat_str)] #![feature(repeat_str)]
#![feature(conservative_impl_trait)]
#![allow(indexing_slicing, shadow_reuse, unknown_lints, missing_docs_in_private_items)] #![allow(indexing_slicing, shadow_reuse, unknown_lints, missing_docs_in_private_items)]
#![allow(needless_lifetimes)] #![allow(needless_lifetimes)]

View file

@ -2,7 +2,7 @@ use rustc::lint::*;
use rustc::hir::*; use rustc::hir::*;
use syntax::ast; use syntax::ast;
use utils::{is_adjusted, match_path, match_trait_method, match_type, remove_blocks, paths, snippet, 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. /// **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 { if &*name.node.as_str() == "map" && args.len() == 2 {
match args[1].node { match args[1].node {
ExprClosure(_, ref decl, closure_eid, _) => { 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! {[ if_let_chain! {[
// nothing special in the argument, besides reference bindings // nothing special in the argument, besides reference bindings
// (e.g. .map(|&x| x) ) // (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) // the method is being called on a known type (option or iterator)
let Some(type_name) = get_type_name(cx, expr, &args[0]) let Some(type_name) = get_type_name(cx, expr, &args[0])
], { ], {
// look for derefs, for .map(|x| *x) // look for derefs, for .map(|x| *x)
if only_derefs(cx, &*closure_expr, arg_ident) && if only_derefs(cx, &*closure_expr, arg_ident) &&
// .cloned() only removes one level of indirection, don't lint on more // .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!( span_help_and_lint(cx, MAP_CLONE, expr.span, &format!(
"you seem to be using .map() to clone the contents of an {}, consider \ "you seem to be using .map() to clone the contents of an {}, consider \

View file

@ -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, 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, 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, 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::paths;
use utils::sugg; 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 parent = cx.tcx.map.get_parent(implitem.id);
let item = cx.tcx.map.expect_item(parent); let item = cx.tcx.map.expect_item(parent);
if_let_chain! {[ if_let_chain! {[
let hir::ImplItemKind::Method(ref sig, _) = implitem.node, let hir::ImplItemKind::Method(ref sig, id) = implitem.node,
let Some(first_arg) = sig.decl.inputs.get(0), let body = cx.tcx.map.body(id),
let Some(first_arg) = iter_input_pats(&sig.decl, body).next(),
let hir::ItemImpl(_, _, _, None, _, _) = item.node, let hir::ItemImpl(_, _, _, None, _, _) = item.node,
], { ], {
// check missing trait implementations // check missing trait implementations
@ -645,7 +646,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
if &*name.as_str() == method_name && if &*name.as_str() == method_name &&
sig.decl.inputs.len() == n_args && sig.decl.inputs.len() == n_args &&
out_type.matches(&sig.decl.output) && 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!( span_lint(cx, SHOULD_IMPLEMENT_TRAIT, implitem.span, &format!(
"defining a method called `{}` on this type; consider implementing \ "defining a method called `{}` on this type; consider implementing \
the `{}` trait or choosing a less ambiguous name", name, trait_name)); 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 { for &(ref conv, self_kinds) in &CONVENTIONS {
if_let_chain! {[ if_let_chain! {[
conv.check(&name.as_str()), conv.check(&name.as_str()),
let Some(explicit_self) = sig.decl.inputs.get(0), !self_kinds.iter().any(|k| k.matches(&first_arg, is_copy)),
!self_kinds.iter().any(|k| k.matches(&**explicit_self, is_copy)),
], { ], {
let lint = if item.vis == hir::Visibility::Public { let lint = if item.vis == hir::Visibility::Public {
WRONG_PUB_SELF_CONVENTION WRONG_PUB_SELF_CONVENTION
@ -668,7 +668,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}; };
span_lint(cx, span_lint(cx,
lint, lint,
explicit_self.span, first_arg.pat.span,
&format!("methods called `{}` usually take {}; consider choosing a less \ &format!("methods called `{}` usually take {}; consider choosing a less \
ambiguous name", ambiguous name",
conv, 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)) { !ret_ty.walk().any(|t| same_tys(cx, t, ty, implitem.id)) {
span_lint(cx, span_lint(cx,
NEW_RET_NO_SELF, NEW_RET_NO_SELF,
first_arg.span, implitem.span,
"methods called `new` usually return `Self`"); "methods called `new` usually return `Self`");
} }
}} }}

View file

@ -9,7 +9,7 @@ use rustc_const_eval::eval_const_expr_partial;
use rustc_const_math::ConstFloat; use rustc_const_math::ConstFloat;
use syntax::codemap::{Span, Spanned, ExpnFormat}; use syntax::codemap::{Span, Spanned, ExpnFormat};
use utils::{get_item_name, get_parent_expr, implements_trait, in_macro, is_integer_literal, match_path, snippet, 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; use utils::sugg::Sugg;
/// **What it does:** Checks for function arguments and let bindings denoted as `ref`. /// **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>, cx: &LateContext<'a, 'tcx>,
k: FnKind<'tcx>, k: FnKind<'tcx>,
decl: &'tcx FnDecl, decl: &'tcx FnDecl,
_: &'tcx Body, body: &'tcx Body,
_: Span, _: Span,
_: NodeId _: NodeId
) { ) {
@ -183,11 +183,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
// Does not apply to closures // Does not apply to closures
return; return;
} }
for arg in &decl.inputs { for arg in iter_input_pats(decl, body) {
if let PatKind::Binding(BindByRef(_), _, _, _) = arg.node { if let PatKind::Binding(BindByRef(_), _, _, _) = arg.pat.node {
span_lint(cx, span_lint(cx,
TOPLEVEL_REF_ARG, TOPLEVEL_REF_ARG,
arg.span, arg.pat.span,
"`ref` directly on a function argument is ignored. Consider using a reference type instead."); "`ref` directly on a function argument is ignored. Consider using a reference type instead.");
} }
} }

View file

@ -4,7 +4,7 @@ use rustc::hir::*;
use rustc::hir::intravisit::{Visitor, FnKind, NestedVisitorMap}; use rustc::hir::intravisit::{Visitor, FnKind, NestedVisitorMap};
use rustc::ty; use rustc::ty;
use syntax::codemap::Span; 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 /// **What it does:** Checks for bindings that shadow other bindings already in
/// scope, while just changing reference level or mutability. /// 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) { if in_external_macro(cx, body.value.span) {
return; 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(); let mut bindings = Vec::new();
for arg in &decl.inputs { for arg in iter_input_pats(decl, body) {
if let PatKind::Binding(_, _, ident, _) = arg.node { if let PatKind::Binding(_, _, ident, _) = arg.pat.node {
bindings.push((ident.node, ident.span)) 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)>) { fn check_block<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, block: &'tcx Block, bindings: &mut Vec<(Name, Span)>) {

View file

@ -906,3 +906,6 @@ pub fn is_self(slf: &Arg) -> bool {
} }
} }
pub fn iter_input_pats<'tcx>(decl: &FnDecl, body: &'tcx Body) -> impl Iterator<Item=&'tcx Arg> {
(0..decl.inputs.len()).map(move |i| &body.arguments[i])
}