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::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 {

View File

@ -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::<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() {
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> {
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<hir::def_id::DefId> {
if let (&hir::PatKind::Binding(_, def_id, _, _), hir::TyPtr(_)) = (&arg.pat.node, ty.node) {
Some(def_id)
} else {
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 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,

View File

@ -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)]

View File

@ -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 \

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,
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`");
}
}}

View File

@ -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.");
}
}

View File

@ -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)>) {

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])
}