Rustup to rustc 1.16.0-nightly (468227129
2017-01-03): Recover patterns from arguments
This commit is contained in:
parent
a262e3bb0b
commit
e02fac4896
9 changed files with 46 additions and 36 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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 \
|
||||||
|
|
|
@ -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`");
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -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.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)>) {
|
||||||
|
|
|
@ -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…
Add table
Add a link
Reference in a new issue