Rustup to rustc 1.16.0-nightly (468227129
2017-01-03): Recover patterns from arguments
This commit is contained in:
parent
a262e3bb0b
commit
e02fac4896
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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)]
|
||||
|
@ -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 \
|
||||
|
@ -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`");
|
||||
}
|
||||
}}
|
||||
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
@ -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)>) {
|
||||
|
@ -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])
|
||||
}
|
Loading…
Reference in New Issue
Block a user