1
Fork 0

mechanically swap if_let_chain -> if_chain

This commit is contained in:
Alex Burka 2017-10-23 15:18:02 -04:00
parent 2771378620
commit 41840ae3c4
42 changed files with 1843 additions and 1750 deletions

View file

@ -94,13 +94,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass {
return;
}
for item in items {
if_let_chain! {[
let NestedMetaItemKind::MetaItem(ref mi) = item.node,
let MetaItemKind::NameValue(ref lit) = mi.node,
mi.name() == "since",
], {
if_chain! {
if let NestedMetaItemKind::MetaItem(ref mi) = item.node;
if let MetaItemKind::NameValue(ref lit) = mi.node;
if mi.name() == "since";
then {
check_semver(cx, item.span, lit);
}}
}
}
}
}
}

View file

@ -119,18 +119,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BitMask {
}
}
}
if_let_chain!{[
let Expr_::ExprBinary(ref op, ref left, ref right) = e.node,
BinOp_::BiEq == op.node,
let Expr_::ExprBinary(ref op1, ref left1, ref right1) = left.node,
BinOp_::BiBitAnd == op1.node,
let Expr_::ExprLit(ref lit) = right1.node,
let LitKind::Int(n, _) = lit.node,
let Expr_::ExprLit(ref lit1) = right.node,
let LitKind::Int(0, _) = lit1.node,
n.leading_zeros() == n.count_zeros(),
n > u128::from(self.verbose_bit_mask_threshold),
], {
if_chain! {
if let Expr_::ExprBinary(ref op, ref left, ref right) = e.node;
if BinOp_::BiEq == op.node;
if let Expr_::ExprBinary(ref op1, ref left1, ref right1) = left.node;
if BinOp_::BiBitAnd == op1.node;
if let Expr_::ExprLit(ref lit) = right1.node;
if let LitKind::Int(n, _) = lit.node;
if let Expr_::ExprLit(ref lit1) = right.node;
if let LitKind::Int(0, _) = lit1.node;
if n.leading_zeros() == n.count_zeros();
if n > u128::from(self.verbose_bit_mask_threshold);
then {
span_lint_and_then(cx,
VERBOSE_BIT_MASK,
e.span,
@ -139,7 +139,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BitMask {
let sugg = Sugg::hir(cx, left1, "...").maybe_par();
db.span_suggestion(e.span, "try", format!("{}.trailing_zeros() >= {}", sugg, n.count_ones()));
});
}}
}
}
}
}

View file

@ -37,25 +37,25 @@ impl LintPass for ByteCount {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ByteCount {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
if_let_chain!([
let ExprMethodCall(ref count, _, ref count_args) = expr.node,
count.name == "count",
count_args.len() == 1,
let ExprMethodCall(ref filter, _, ref filter_args) = count_args[0].node,
filter.name == "filter",
filter_args.len() == 2,
let ExprClosure(_, _, body_id, _, _) = filter_args[1].node,
], {
if_chain! {
if let ExprMethodCall(ref count, _, ref count_args) = expr.node;
if count.name == "count";
if count_args.len() == 1;
if let ExprMethodCall(ref filter, _, ref filter_args) = count_args[0].node;
if filter.name == "filter";
if filter_args.len() == 2;
if let ExprClosure(_, _, body_id, _, _) = filter_args[1].node;
then {
let body = cx.tcx.hir.body(body_id);
if_let_chain!([
body.arguments.len() == 1,
let Some(argname) = get_pat_name(&body.arguments[0].pat),
let ExprBinary(ref op, ref l, ref r) = body.value.node,
op.node == BiEq,
match_type(cx,
if_chain! {
if body.arguments.len() == 1;
if let Some(argname) = get_pat_name(&body.arguments[0].pat);
if let ExprBinary(ref op, ref l, ref r) = body.value.node;
if op.node == BiEq;
if match_type(cx,
walk_ptrs_ty(cx.tables.expr_ty(&filter_args[0])),
&paths::SLICE_ITER),
], {
&paths::SLICE_ITER);
then {
let needle = match get_path_name(l) {
Some(name) if check_arg(name, argname, r) => r,
_ => match get_path_name(r) {
@ -85,8 +85,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ByteCount {
format!("bytecount::count({}, {})",
snippet(cx, haystack.span, ".."),
snippet(cx, needle.span, "..")));
});
});
}
};
}
};
}
}

View file

@ -100,11 +100,11 @@ fn check_if(cx: &EarlyContext, expr: &ast::Expr) {
}
fn check_collapsible_maybe_if_let(cx: &EarlyContext, else_: &ast::Expr) {
if_let_chain! {[
let ast::ExprKind::Block(ref block) = else_.node,
let Some(else_) = expr_block(block),
!in_macro(else_.span),
], {
if_chain! {
if let ast::ExprKind::Block(ref block) = else_.node;
if let Some(else_) = expr_block(block);
if !in_macro(else_.span);
then {
match else_.node {
ast::ExprKind::If(..) | ast::ExprKind::IfLet(..) => {
span_lint_and_sugg(cx,
@ -116,14 +116,15 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext, else_: &ast::Expr) {
}
_ => (),
}
}}
}
}
}
fn check_collapsible_no_if_let(cx: &EarlyContext, expr: &ast::Expr, check: &ast::Expr, then: &ast::Block) {
if_let_chain! {[
let Some(inner) = expr_block(then),
let ast::ExprKind::If(ref check_inner, ref content, None) = inner.node,
], {
if_chain! {
if let Some(inner) = expr_block(then);
if let ast::ExprKind::If(ref check_inner, ref content, None) = inner.node;
then {
if expr.span.ctxt() != inner.span.ctxt() {
return;
}
@ -136,7 +137,8 @@ fn check_collapsible_no_if_let(cx: &EarlyContext, expr: &ast::Expr, check: &ast:
lhs.and(rhs),
snippet_block(cx, content.span, "..")));
});
}}
}
}
}
/// If the block contains only one expression, return it.

View file

@ -91,10 +91,10 @@ fn check_hash_peq<'a, 'tcx>(
ty: Ty<'tcx>,
hash_is_automatically_derived: bool,
) {
if_let_chain! {[
match_path(&trait_ref.path, &paths::HASH),
let Some(peq_trait_def_id) = cx.tcx.lang_items().eq_trait()
], {
if_chain! {
if match_path(&trait_ref.path, &paths::HASH);
if let Some(peq_trait_def_id) = cx.tcx.lang_items().eq_trait();
then {
// Look for the PartialEq implementations for `ty`
cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {
let peq_is_automatically_derived = is_automatically_derived(&cx.tcx.get_attrs(impl_id));
@ -127,7 +127,8 @@ fn check_hash_peq<'a, 'tcx>(
});
}
});
}}
}
}
}
/// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.

View file

@ -115,12 +115,12 @@ impl LintPass for Pass {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_let_chain!{[
let ExprCall(ref path, ref args) = expr.node,
let ExprPath(ref qpath) = path.node,
args.len() == 1,
let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id)),
], {
if_chain! {
if let ExprCall(ref path, ref args) = expr.node;
if let ExprPath(ref qpath) = path.node;
if args.len() == 1;
if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id));
then {
let lint;
let msg;
let arg = &args[0];
@ -159,6 +159,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
arg.span,
&format!("argument has type {}", arg_ty));
}
}}
}
}
}
}

View file

@ -87,12 +87,12 @@ fn check_cond<'a, 'tcx, 'b>(
cx: &'a LateContext<'a, 'tcx>,
check: &'b Expr,
) -> Option<(&'static str, &'b Expr, &'b Expr)> {
if_let_chain! {[
let ExprMethodCall(ref path, _, ref params) = check.node,
params.len() >= 2,
path.name == "contains_key",
let ExprAddrOf(_, ref key) = params[1].node
], {
if_chain! {
if let ExprMethodCall(ref path, _, ref params) = check.node;
if params.len() >= 2;
if path.name == "contains_key";
if let ExprAddrOf(_, ref key) = params[1].node;
then {
let map = &params[0];
let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(map));
@ -105,7 +105,8 @@ fn check_cond<'a, 'tcx, 'b>(
else {
None
};
}}
}
}
None
}
@ -121,13 +122,13 @@ struct InsertVisitor<'a, 'tcx: 'a, 'b> {
impl<'a, 'tcx, 'b> Visitor<'tcx> for InsertVisitor<'a, 'tcx, 'b> {
fn visit_expr(&mut self, expr: &'tcx Expr) {
if_let_chain! {[
let ExprMethodCall(ref path, _, ref params) = expr.node,
params.len() == 3,
path.name == "insert",
get_item_name(self.cx, self.map) == get_item_name(self.cx, &params[0]),
SpanlessEq::new(self.cx).eq_expr(self.key, &params[1])
], {
if_chain! {
if let ExprMethodCall(ref path, _, ref params) = expr.node;
if params.len() == 3;
if path.name == "insert";
if get_item_name(self.cx, self.map) == get_item_name(self.cx, &params[0]);
if SpanlessEq::new(self.cx).eq_expr(self.key, &params[1]);
then {
span_lint_and_then(self.cx, MAP_ENTRY, self.span,
&format!("usage of `contains_key` followed by `insert` on a `{}`", self.ty), |db| {
if self.sole_expr {
@ -146,7 +147,8 @@ impl<'a, 'tcx, 'b> Visitor<'tcx> for InsertVisitor<'a, 'tcx, 'b> {
db.span_suggestion(self.span, "consider using", help);
}
});
}}
}
}
if !self.sole_expr {
walk_expr(self, expr);

View file

@ -298,14 +298,14 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
match expr.node {
ExprPath(ref qpath) => {
if_let_chain! {[
let QPath::Resolved(None, ref path) = *qpath,
path.segments.len() == 1,
let def::Def::Local(local_id) = self.cx.tables.qpath_def(qpath, expr.hir_id),
local_id == self.var,
if_chain! {
if let QPath::Resolved(None, ref path) = *qpath;
if path.segments.len() == 1;
if let def::Def::Local(local_id) = self.cx.tables.qpath_def(qpath, expr.hir_id);
if local_id == self.var;
// Check that this is a read, not a write.
!is_in_assignment_position(self.cx, expr),
], {
if !is_in_assignment_position(self.cx, expr);
then {
span_note_and_lint(
self.cx,
EVAL_ORDER_DEPENDENCE,
@ -314,7 +314,8 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
self.write_expr.span,
"whether read occurs before this write depends on evaluation order"
);
}}
}
}
}
// We're about to descend a closure. Since we don't know when (or
// if) the closure will be evaluated, any reads in it might not

View file

@ -33,29 +33,29 @@ impl LintPass for Pass {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_let_chain! {[
if_chain! {
// match call to unwrap
let ExprMethodCall(ref unwrap_fun, _, ref unwrap_args) = expr.node,
unwrap_fun.name == "unwrap",
if let ExprMethodCall(ref unwrap_fun, _, ref unwrap_args) = expr.node;
if unwrap_fun.name == "unwrap";
// match call to write_fmt
unwrap_args.len() > 0,
let ExprMethodCall(ref write_fun, _, ref write_args) =
unwrap_args[0].node,
write_fun.name == "write_fmt",
if unwrap_args.len() > 0;
if let ExprMethodCall(ref write_fun, _, ref write_args) =
unwrap_args[0].node;
if write_fun.name == "write_fmt";
// match calls to std::io::stdout() / std::io::stderr ()
write_args.len() > 0,
let ExprCall(ref dest_fun, _) = write_args[0].node,
let ExprPath(ref qpath) = dest_fun.node,
let Some(dest_fun_id) =
opt_def_id(resolve_node(cx, qpath, dest_fun.hir_id)),
let Some(dest_name) = if match_def_path(cx.tcx, dest_fun_id, &["std", "io", "stdio", "stdout"]) {
if write_args.len() > 0;
if let ExprCall(ref dest_fun, _) = write_args[0].node;
if let ExprPath(ref qpath) = dest_fun.node;
if let Some(dest_fun_id) =
opt_def_id(resolve_node(cx, qpath, dest_fun.hir_id));
if let Some(dest_name) = if match_def_path(cx.tcx, dest_fun_id, &["std", "io", "stdio", "stdout"]) {
Some("stdout")
} else if match_def_path(cx.tcx, dest_fun_id, &["std", "io", "stdio", "stderr"]) {
Some("stderr")
} else {
None
},
], {
};
then {
let write_span = unwrap_args[0].span;
let calling_macro =
// ordering is important here, since `writeln!` uses `write!` internally
@ -96,6 +96,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
)
);
}
}}
}
}
}
}

View file

@ -37,13 +37,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FallibleImplFrom {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
// check for `impl From<???> for ..`
let impl_def_id = cx.tcx.hir.local_def_id(item.id);
if_let_chain!{[
let hir::ItemImpl(.., ref impl_items) = item.node,
let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(impl_def_id),
match_def_path(cx.tcx, impl_trait_ref.def_id, &FROM_TRAIT),
], {
if_chain! {
if let hir::ItemImpl(.., ref impl_items) = item.node;
if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(impl_def_id);
if match_def_path(cx.tcx, impl_trait_ref.def_id, &FROM_TRAIT);
then {
lint_impl_body(cx, item.span, impl_items);
}}
}
}
}
}
@ -60,14 +61,15 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it
impl<'a, 'tcx: 'a> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr) {
// check for `begin_panic`
if_let_chain!{[
let ExprCall(ref func_expr, _) = expr.node,
let ExprPath(QPath::Resolved(_, ref path)) = func_expr.node,
match_def_path(self.tcx, path.def.def_id(), &BEGIN_PANIC) ||
match_def_path(self.tcx, path.def.def_id(), &BEGIN_PANIC_FMT),
], {
if_chain! {
if let ExprCall(ref func_expr, _) = expr.node;
if let ExprPath(QPath::Resolved(_, ref path)) = func_expr.node;
if match_def_path(self.tcx, path.def.def_id(), &BEGIN_PANIC) ||
match_def_path(self.tcx, path.def.def_id(), &BEGIN_PANIC_FMT);
then {
self.result.push(expr.span);
}}
}
}
// check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
@ -89,11 +91,11 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it
}
for impl_item in impl_items {
if_let_chain!{[
impl_item.name == "from",
let ImplItemKind::Method(_, body_id) =
cx.tcx.hir.impl_item(impl_item.id).node,
], {
if_chain! {
if impl_item.name == "from";
if let ImplItemKind::Method(_, body_id) =
cx.tcx.hir.impl_item(impl_item.id).node;
then {
// check the body for `begin_panic` or `unwrap`
let body = cx.tcx.hir.body(body_id);
let impl_item_def_id = cx.tcx.hir.local_def_id(impl_item.id.node_id);
@ -118,7 +120,8 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it
db.span_note(fpu.result, "potential failure(s)");
});
}
}}
}
}
}
}

View file

@ -42,19 +42,20 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
match expr.node {
// `format!("{}", foo)` expansion
ExprCall(ref fun, ref args) => {
if_let_chain!{[
let ExprPath(ref qpath) = fun.node,
args.len() == 2,
let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id)),
match_def_path(cx.tcx, fun_def_id, &paths::FMT_ARGUMENTS_NEWV1),
if_chain! {
if let ExprPath(ref qpath) = fun.node;
if args.len() == 2;
if let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id));
if match_def_path(cx.tcx, fun_def_id, &paths::FMT_ARGUMENTS_NEWV1);
// ensure the format string is `"{..}"` with only one argument and no text
check_static_str(&args[0]),
if check_static_str(&args[0]);
// ensure the format argument is `{}` ie. Display with no fancy option
// and that the argument is a string
check_arg_is_display(cx, &args[1])
], {
if check_arg_is_display(cx, &args[1]);
then {
span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`");
}}
}
}
},
// `format!("foo")` expansion contains `match () { () => [], }`
ExprMatch(ref matchee, _, _) => if let ExprTup(ref tup) = matchee.node {
@ -70,15 +71,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
/// Checks if the expressions matches `&[""]`
fn check_static_str(expr: &Expr) -> bool {
if_let_chain! {[
let ExprAddrOf(_, ref expr) = expr.node, // &[""]
let ExprArray(ref exprs) = expr.node, // [""]
exprs.len() == 1,
let ExprLit(ref lit) = exprs[0].node,
let LitKind::Str(ref lit, _) = lit.node,
], {
if_chain! {
if let ExprAddrOf(_, ref expr) = expr.node; // &[""]
if let ExprArray(ref exprs) = expr.node; // [""]
if exprs.len() == 1;
if let ExprLit(ref lit) = exprs[0].node;
if let LitKind::Str(ref lit, _) = lit.node;
then {
return lit.as_str().is_empty();
}}
}
}
false
}
@ -91,25 +93,26 @@ fn check_static_str(expr: &Expr) -> bool {
/// }
/// ```
fn check_arg_is_display(cx: &LateContext, expr: &Expr) -> bool {
if_let_chain! {[
let ExprAddrOf(_, ref expr) = expr.node,
let ExprMatch(_, ref arms, _) = expr.node,
arms.len() == 1,
arms[0].pats.len() == 1,
let PatKind::Tuple(ref pat, None) = arms[0].pats[0].node,
pat.len() == 1,
let ExprArray(ref exprs) = arms[0].body.node,
exprs.len() == 1,
let ExprCall(_, ref args) = exprs[0].node,
args.len() == 2,
let ExprPath(ref qpath) = args[1].node,
let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, args[1].hir_id)),
match_def_path(cx.tcx, fun_def_id, &paths::DISPLAY_FMT_METHOD),
], {
if_chain! {
if let ExprAddrOf(_, ref expr) = expr.node;
if let ExprMatch(_, ref arms, _) = expr.node;
if arms.len() == 1;
if arms[0].pats.len() == 1;
if let PatKind::Tuple(ref pat, None) = arms[0].pats[0].node;
if pat.len() == 1;
if let ExprArray(ref exprs) = arms[0].body.node;
if exprs.len() == 1;
if let ExprCall(_, ref args) = exprs[0].node;
if args.len() == 2;
if let ExprPath(ref qpath) = args[1].node;
if let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, args[1].hir_id));
if match_def_path(cx.tcx, fun_def_id, &paths::DISPLAY_FMT_METHOD);
then {
let ty = walk_ptrs_ty(cx.tables.pat_ty(&pat[0]));
return ty.sty == ty::TyStr || match_type(cx, ty, &paths::STRING);
}}
}
}
false
}

View file

@ -34,13 +34,13 @@ impl LintPass for InvalidRef {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidRef {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_let_chain!{[
let ExprCall(ref path, ref args) = expr.node,
let ExprPath(ref qpath) = path.node,
args.len() == 0,
let ty::TyRef(..) = cx.tables.expr_ty(expr).sty,
let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id)),
], {
if_chain! {
if let ExprCall(ref path, ref args) = expr.node;
if let ExprPath(ref qpath) = path.node;
if args.len() == 0;
if let ty::TyRef(..) = cx.tables.expr_ty(expr).sty;
if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id));
then {
let msg = if match_def_path(cx.tcx, def_id, &paths::MEM_ZEROED) | match_def_path(cx.tcx, def_id, &paths::INIT) {
ZERO_REF_SUMMARY
} else if match_def_path(cx.tcx, def_id, &paths::MEM_UNINIT) | match_def_path(cx.tcx, def_id, &paths::UNINIT) {
@ -49,7 +49,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidRef {
return;
};
span_help_and_lint(cx, INVALID_REF, expr.span, msg, HELP);
}}
}
}
return;
}
}

View file

@ -63,18 +63,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetIfSeq {
fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx hir::Block) {
let mut it = block.stmts.iter().peekable();
while let Some(stmt) = it.next() {
if_let_chain! {[
let Some(expr) = it.peek(),
let hir::StmtDecl(ref decl, _) = stmt.node,
let hir::DeclLocal(ref decl) = decl.node,
let hir::PatKind::Binding(mode, canonical_id, ref name, None) = decl.pat.node,
let hir::StmtExpr(ref if_, _) = expr.node,
let hir::ExprIf(ref cond, ref then, ref else_) = if_.node,
!used_in_expr(cx, canonical_id, cond),
let hir::ExprBlock(ref then) = then.node,
let Some(value) = check_assign(cx, canonical_id, &*then),
!used_in_expr(cx, canonical_id, value),
], {
if_chain! {
if let Some(expr) = it.peek();
if let hir::StmtDecl(ref decl, _) = stmt.node;
if let hir::DeclLocal(ref decl) = decl.node;
if let hir::PatKind::Binding(mode, canonical_id, ref name, None) = decl.pat.node;
if let hir::StmtExpr(ref if_, _) = expr.node;
if let hir::ExprIf(ref cond, ref then, ref else_) = if_.node;
if !used_in_expr(cx, canonical_id, cond);
if let hir::ExprBlock(ref then) = then.node;
if let Some(value) = check_assign(cx, canonical_id, &*then);
if !used_in_expr(cx, canonical_id, value);
then {
let span = stmt.span.to(if_.span);
let (default_multi_stmts, default) = if let Some(ref else_) = *else_ {
@ -125,7 +125,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetIfSeq {
db.note("you might not need `mut` at all");
}
});
}}
}
}
}
}
}
@ -138,14 +139,15 @@ struct UsedVisitor<'a, 'tcx: 'a> {
impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for UsedVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
if_let_chain! {[
let hir::ExprPath(ref qpath) = expr.node,
let Def::Local(local_id) = self.cx.tables.qpath_def(qpath, expr.hir_id),
self.id == local_id,
], {
if_chain! {
if let hir::ExprPath(ref qpath) = expr.node;
if let Def::Local(local_id) = self.cx.tables.qpath_def(qpath, expr.hir_id);
if self.id == local_id;
then {
self.used = true;
return;
}}
}
}
hir::intravisit::walk_expr(self, expr);
}
fn nested_visit_map<'this>(&'this mut self) -> hir::intravisit::NestedVisitorMap<'this, 'tcx> {
@ -158,15 +160,15 @@ fn check_assign<'a, 'tcx>(
decl: ast::NodeId,
block: &'tcx hir::Block,
) -> Option<&'tcx hir::Expr> {
if_let_chain! {[
block.expr.is_none(),
let Some(expr) = block.stmts.iter().last(),
let hir::StmtSemi(ref expr, _) = expr.node,
let hir::ExprAssign(ref var, ref value) = expr.node,
let hir::ExprPath(ref qpath) = var.node,
let Def::Local(local_id) = cx.tables.qpath_def(qpath, var.hir_id),
decl == local_id,
], {
if_chain! {
if block.expr.is_none();
if let Some(expr) = block.stmts.iter().last();
if let hir::StmtSemi(ref expr, _) = expr.node;
if let hir::ExprAssign(ref var, ref value) = expr.node;
if let hir::ExprPath(ref qpath) = var.node;
if let Def::Local(local_id) = cx.tables.qpath_def(qpath, var.hir_id);
if decl == local_id;
then {
let mut v = UsedVisitor {
cx: cx,
id: decl,
@ -182,7 +184,8 @@ fn check_assign<'a, 'tcx>(
}
return Some(value);
}}
}
}
None
}

View file

@ -244,25 +244,26 @@ impl EarlyLintPass for LiteralDigitGrouping {
impl LiteralDigitGrouping {
fn check_lit(&self, cx: &EarlyContext, lit: &Lit) {
// Lint integral literals.
if_let_chain! {[
let LitKind::Int(..) = lit.node,
let Some(src) = snippet_opt(cx, lit.span),
let Some(firstch) = src.chars().next(),
char::to_digit(firstch, 10).is_some()
], {
if_chain! {
if let LitKind::Int(..) = lit.node;
if let Some(src) = snippet_opt(cx, lit.span);
if let Some(firstch) = src.chars().next();
if char::to_digit(firstch, 10).is_some();
then {
let digit_info = DigitInfo::new(&src, false);
let _ = Self::do_lint(digit_info.digits).map_err(|warning_type| {
warning_type.display(&digit_info.grouping_hint(), cx, &lit.span)
});
}}
}
}
// Lint floating-point literals.
if_let_chain! {[
let LitKind::Float(..) = lit.node,
let Some(src) = snippet_opt(cx, lit.span),
let Some(firstch) = src.chars().next(),
char::to_digit(firstch, 10).is_some()
], {
if_chain! {
if let LitKind::Float(..) = lit.node;
if let Some(src) = snippet_opt(cx, lit.span);
if let Some(firstch) = src.chars().next();
if char::to_digit(firstch, 10).is_some();
then {
let digit_info = DigitInfo::new(&src, true);
// Separate digits into integral and fractional parts.
let parts: Vec<&str> = digit_info
@ -295,7 +296,8 @@ impl LiteralDigitGrouping {
}
})
.map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(), cx, &lit.span));
}}
}
}
}
/// Given the sizes of the digit groups of both integral and fractional

View file

@ -611,16 +611,17 @@ fn check_for_loop<'a, 'tcx>(
}
fn same_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var: ast::NodeId) -> bool {
if_let_chain! {[
let ExprPath(ref qpath) = expr.node,
let QPath::Resolved(None, ref path) = *qpath,
path.segments.len() == 1,
let Def::Local(local_id) = cx.tables.qpath_def(qpath, expr.hir_id),
if_chain! {
if let ExprPath(ref qpath) = expr.node;
if let QPath::Resolved(None, ref path) = *qpath;
if path.segments.len() == 1;
if let Def::Local(local_id) = cx.tables.qpath_def(qpath, expr.hir_id);
// our variable!
local_id == var
], {
if local_id == var;
then {
return true;
}}
}
}
false
}
@ -725,14 +726,15 @@ fn fetch_cloned_fixed_offset_var<'a, 'tcx>(
expr: &Expr,
var: ast::NodeId,
) -> Option<FixedOffsetVar> {
if_let_chain! {[
let ExprMethodCall(ref method, _, ref args) = expr.node,
method.name == "clone",
args.len() == 1,
let Some(arg) = args.get(0),
], {
if_chain! {
if let ExprMethodCall(ref method, _, ref args) = expr.node;
if method.name == "clone";
if args.len() == 1;
if let Some(arg) = args.get(0);
then {
return get_fixed_offset_var(cx, arg, var);
}}
}
}
get_fixed_offset_var(cx, expr, var)
}
@ -821,19 +823,20 @@ fn detect_manual_memcpy<'a, 'tcx>(
};
let print_limit = |end: &Option<&Expr>, offset: Offset, var_name: &str| if let Some(end) = *end {
if_let_chain! {[
let ExprMethodCall(ref method, _, ref len_args) = end.node,
method.name == "len",
len_args.len() == 1,
let Some(arg) = len_args.get(0),
snippet(cx, arg.span, "??") == var_name,
], {
if_chain! {
if let ExprMethodCall(ref method, _, ref len_args) = end.node;
if method.name == "len";
if len_args.len() == 1;
if let Some(arg) = len_args.get(0);
if snippet(cx, arg.span, "??") == var_name;
then {
return if offset.negate {
format!("({} - {})", snippet(cx, end.span, "<src>.len()"), offset.value)
} else {
"".to_owned()
};
}}
}
}
let end_str = match limits {
ast::RangeLimits::Closed => {
@ -1003,16 +1006,17 @@ fn check_for_loop_range<'a, 'tcx>(
}
fn is_len_call(expr: &Expr, var: &Name) -> bool {
if_let_chain! {[
let ExprMethodCall(ref method, _, ref len_args) = expr.node,
len_args.len() == 1,
method.name == "len",
let ExprPath(QPath::Resolved(_, ref path)) = len_args[0].node,
path.segments.len() == 1,
path.segments[0].name == *var
], {
if_chain! {
if let ExprMethodCall(ref method, _, ref len_args) = expr.node;
if len_args.len() == 1;
if method.name == "len";
if let ExprPath(QPath::Resolved(_, ref path)) = len_args[0].node;
if path.segments.len() == 1;
if path.segments[0].name == *var;
then {
return true;
}}
}
}
false
}
@ -1374,22 +1378,24 @@ fn mut_warn_with_span(cx: &LateContext, span: Option<Span>) {
}
fn check_for_mutability(cx: &LateContext, bound: &Expr) -> Option<NodeId> {
if_let_chain! {[
let ExprPath(ref qpath) = bound.node,
let QPath::Resolved(None, _) = *qpath,
], {
if_chain! {
if let ExprPath(ref qpath) = bound.node;
if let QPath::Resolved(None, _) = *qpath;
then {
let def = cx.tables.qpath_def(qpath, bound.hir_id);
if let Def::Local(node_id) = def {
let node_str = cx.tcx.hir.get(node_id);
if_let_chain! {[
let map::Node::NodeBinding(pat) = node_str,
let PatKind::Binding(bind_ann, _, _, _) = pat.node,
let BindingAnnotation::Mutable = bind_ann,
], {
if_chain! {
if let map::Node::NodeBinding(pat) = node_str;
if let PatKind::Binding(bind_ann, _, _, _) = pat.node;
if let BindingAnnotation::Mutable = bind_ann;
then {
return Some(node_id);
}}
}
}}
}
}
}
}
None
}
@ -1476,14 +1482,14 @@ struct VarVisitor<'a, 'tcx: 'a> {
impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr) {
if_let_chain! {[
if_chain! {
// an index op
let ExprIndex(ref seqexpr, ref idx) = expr.node,
if let ExprIndex(ref seqexpr, ref idx) = expr.node;
// the indexed container is referenced by a name
let ExprPath(ref seqpath) = seqexpr.node,
let QPath::Resolved(None, ref seqvar) = *seqpath,
seqvar.segments.len() == 1,
], {
if let ExprPath(ref seqpath) = seqexpr.node;
if let QPath::Resolved(None, ref seqvar) = *seqpath;
if seqvar.segments.len() == 1;
then {
let index_used_directly = same_var(self.cx, idx, self.var);
let index_used = index_used_directly || {
let mut used_visitor = LocalUsedVisitor {
@ -1520,15 +1526,16 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
_ => (),
}
}
}}
}
}
if_let_chain! {[
if_chain! {
// directly using a variable
let ExprPath(ref qpath) = expr.node,
let QPath::Resolved(None, ref path) = *qpath,
path.segments.len() == 1,
let Def::Local(local_id) = self.cx.tables.qpath_def(qpath, expr.hir_id),
], {
if let ExprPath(ref qpath) = expr.node;
if let QPath::Resolved(None, ref path) = *qpath;
if path.segments.len() == 1;
if let Def::Local(local_id) = self.cx.tables.qpath_def(qpath, expr.hir_id);
then {
if local_id == self.var {
// we are not indexing anything, record that
self.nonindex = true;
@ -1536,7 +1543,8 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
// not the correct variable, but still a variable
self.referenced.insert(path.segments[0].name);
}
}}
}
}
walk_expr(self, expr);
}
@ -1845,12 +1853,13 @@ fn is_conditional(expr: &Expr) -> bool {
}
fn is_nested(cx: &LateContext, match_expr: &Expr, iter_expr: &Expr) -> bool {
if_let_chain! {[
let Some(loop_block) = get_enclosing_block(cx, match_expr.id),
let Some(map::Node::NodeExpr(loop_expr)) = cx.tcx.hir.find(cx.tcx.hir.get_parent_node(loop_block.id)),
], {
if_chain! {
if let Some(loop_block) = get_enclosing_block(cx, match_expr.id);
if let Some(map::Node::NodeExpr(loop_expr)) = cx.tcx.hir.find(cx.tcx.hir.get_parent_node(loop_block.id));
then {
return is_loop_nested(cx, loop_expr, iter_expr)
}}
}
}
false
}

View file

@ -35,14 +35,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
let body = cx.tcx.hir.body(closure_eid);
let closure_expr = remove_blocks(&body.value);
let ty = cx.tables.pat_ty(&body.arguments[0].pat);
if_let_chain! {[
if_chain! {
// nothing special in the argument, besides reference bindings
// (e.g. .map(|&x| x) )
let Some(first_arg) = iter_input_pats(decl, body).next(),
let Some(arg_ident) = get_arg_name(&first_arg.pat),
if let Some(first_arg) = iter_input_pats(decl, body).next();
if 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])
], {
if let Some(type_name) = get_type_name(cx, expr, &args[0]);
then {
// 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
@ -71,7 +71,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
&format!("try\n{}.cloned()", snippet(cx, args[0].span, "..")));
}
}
}}
}
}
},
ExprPath(ref path) => if match_qpath(path, &paths::CLONE) {
let type_name = get_type_name(cx, expr, &args[0]).unwrap_or("_");

View file

@ -343,12 +343,12 @@ fn check_wild_err_arm(cx: &LateContext, ex: &Expr, arms: &[Arm]) {
for arm in arms {
if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pats[0].node {
let path_str = print::to_string(print::NO_ANN, |s| s.print_qpath(path, false));
if_let_chain! {[
path_str == "Err",
inner.iter().any(|pat| pat.node == PatKind::Wild),
let ExprBlock(ref block) = arm.body.node,
is_panic_block(block)
], {
if_chain! {
if path_str == "Err";
if inner.iter().any(|pat| pat.node == PatKind::Wild);
if let ExprBlock(ref block) = arm.body.node;
if is_panic_block(block);
then {
// `Err(_)` arm with `panic!` found
span_note_and_lint(cx,
MATCH_WILD_ERR_ARM,
@ -357,7 +357,8 @@ fn check_wild_err_arm(cx: &LateContext, ex: &Expr, arms: &[Arm]) {
arm.pats[0].span,
"to remove this warning, match each error seperately \
or use unreachable macro");
}}
}
}
}
}
}
@ -428,24 +429,26 @@ fn all_ranges<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arms: &'tcx [Arm], id: NodeI
} else {
[].iter()
}.filter_map(|pat| {
if_let_chain! {[
let PatKind::Range(ref lhs, ref rhs, ref range_end) = pat.node,
let Ok(lhs) = constcx.eval(lhs),
let Ok(rhs) = constcx.eval(rhs)
], {
if_chain! {
if let PatKind::Range(ref lhs, ref rhs, ref range_end) = pat.node;
if let Ok(lhs) = constcx.eval(lhs);
if let Ok(rhs) = constcx.eval(rhs);
then {
let rhs = match *range_end {
RangeEnd::Included => Bound::Included(rhs),
RangeEnd::Excluded => Bound::Excluded(rhs),
};
return Some(SpannedRange { span: pat.span, node: (lhs, rhs) });
}}
}
}
if_let_chain! {[
let PatKind::Lit(ref value) = pat.node,
let Ok(value) = constcx.eval(value)
], {
if_chain! {
if let PatKind::Lit(ref value) = pat.node;
if let Ok(value) = constcx.eval(value);
then {
return Some(SpannedRange { span: pat.span, node: (value, Bound::Included(value)) });
}}
}
}
None
})

View file

@ -735,12 +735,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
let name = implitem.name;
let parent = cx.tcx.hir.get_parent(implitem.id);
let item = cx.tcx.hir.expect_item(parent);
if_let_chain! {[
let hir::ImplItemKind::Method(ref sig, id) = implitem.node,
let Some(first_arg_ty) = sig.decl.inputs.get(0),
let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.hir.body(id)).next(),
let hir::ItemImpl(_, _, _, _, None, ref self_ty, _) = item.node,
], {
if_chain! {
if let hir::ImplItemKind::Method(ref sig, id) = implitem.node;
if let Some(first_arg_ty) = sig.decl.inputs.get(0);
if let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.hir.body(id)).next();
if let hir::ItemImpl(_, _, _, _, None, ref self_ty, _) = item.node;
then {
// check missing trait implementations
for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS {
if name == method_name &&
@ -758,10 +758,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
let ty = cx.tcx.type_of(def_id);
let is_copy = is_copy(cx, ty);
for &(ref conv, self_kinds) in &CONVENTIONS {
if_let_chain! {[
conv.check(&name.as_str()),
!self_kinds.iter().any(|k| k.matches(first_arg_ty, first_arg, self_ty, is_copy, &sig.generics)),
], {
if_chain! {
if conv.check(&name.as_str());
if !self_kinds.iter().any(|k| k.matches(first_arg_ty, first_arg, self_ty, is_copy, &sig.generics));
then {
let lint = if item.vis == hir::Visibility::Public {
WRONG_PUB_SELF_CONVENTION
} else {
@ -777,7 +777,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
.map(|k| k.description())
.collect::<Vec<_>>()
.join(" or ")));
}}
}
}
}
let ret_ty = return_ty(cx, implitem.id);
@ -788,7 +789,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
implitem.span,
"methods called `new` usually return `Self`");
}
}}
}
}
}
}
@ -1014,20 +1016,21 @@ fn lint_extend(cx: &LateContext, expr: &hir::Expr, args: &[hir::Expr]) {
}
fn lint_cstring_as_ptr(cx: &LateContext, expr: &hir::Expr, new: &hir::Expr, unwrap: &hir::Expr) {
if_let_chain!{[
let hir::ExprCall(ref fun, ref args) = new.node,
args.len() == 1,
let hir::ExprPath(ref path) = fun.node,
let Def::Method(did) = cx.tables.qpath_def(path, fun.hir_id),
match_def_path(cx.tcx, did, &paths::CSTRING_NEW)
], {
if_chain! {
if let hir::ExprCall(ref fun, ref args) = new.node;
if args.len() == 1;
if let hir::ExprPath(ref path) = fun.node;
if let Def::Method(did) = cx.tables.qpath_def(path, fun.hir_id);
if match_def_path(cx.tcx, did, &paths::CSTRING_NEW);
then {
span_lint_and_then(cx, TEMPORARY_CSTRING_AS_PTR, expr.span,
"you are getting the inner pointer of a temporary `CString`",
|db| {
db.note("that pointer will be invalid outside this expression");
db.span_help(unwrap.span, "assign the `CString` to a variable to extend its lifetime");
});
}}
}
}
}
fn lint_iter_cloned_collect(cx: &LateContext, expr: &hir::Expr, iter_args: &[hir::Expr]) {
@ -1427,14 +1430,14 @@ fn lint_binary_expr_with_method_call<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, i
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_NEXT_CMP` lints.
fn lint_chars_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo, chain_methods: &[&str], lint: &'static Lint, suggest: &str) -> bool {
if_let_chain! {[
let Some(args) = method_chain_args(info.chain, chain_methods),
let hir::ExprCall(ref fun, ref arg_char) = info.other.node,
arg_char.len() == 1,
let hir::ExprPath(ref qpath) = fun.node,
let Some(segment) = single_segment_path(qpath),
segment.name == "Some"
], {
if_chain! {
if let Some(args) = method_chain_args(info.chain, chain_methods);
if let hir::ExprCall(ref fun, ref arg_char) = info.other.node;
if arg_char.len() == 1;
if let hir::ExprPath(ref qpath) = fun.node;
if let Some(segment) = single_segment_path(qpath);
if segment.name == "Some";
then {
let self_ty = walk_ptrs_ty(cx.tables.expr_ty_adjusted(&args[0][0]));
if self_ty.sty != ty::TyStr {
@ -1453,7 +1456,8 @@ fn lint_chars_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo, c
snippet(cx, arg_char[0].span, "_")));
return true;
}}
}
}
false
}
@ -1474,11 +1478,11 @@ fn lint_chars_last_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprIn
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
fn lint_chars_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo, chain_methods: &[&str], lint: &'static Lint, suggest: &str) -> bool {
if_let_chain! {[
let Some(args) = method_chain_args(info.chain, chain_methods),
let hir::ExprLit(ref lit) = info.other.node,
let ast::LitKind::Char(c) = lit.node,
], {
if_chain! {
if let Some(args) = method_chain_args(info.chain, chain_methods);
if let hir::ExprLit(ref lit) = info.other.node;
if let ast::LitKind::Char(c) = lit.node;
then {
span_lint_and_sugg(
cx,
lint,
@ -1493,7 +1497,8 @@ fn lint_chars_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &Binar
);
return true;
}}
}
}
false
}

View file

@ -251,12 +251,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}
fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx Stmt) {
if_let_chain! {[
let StmtDecl(ref d, _) = s.node,
let DeclLocal(ref l) = d.node,
let PatKind::Binding(an, _, i, None) = l.pat.node,
let Some(ref init) = l.init
], {
if_chain! {
if let StmtDecl(ref d, _) = s.node;
if let DeclLocal(ref l) = d.node;
if let PatKind::Binding(an, _, i, None) = l.pat.node;
if let Some(ref init) = l.init;
then {
if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut {
let init = Sugg::hir(cx, init, "..");
let (mutopt,initref) = if an == BindingAnnotation::RefMut {
@ -283,13 +283,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}
);
}
}};
if_let_chain! {[
let StmtSemi(ref expr, _) = s.node,
let Expr_::ExprBinary(ref binop, ref a, ref b) = expr.node,
binop.node == BiAnd || binop.node == BiOr,
let Some(sugg) = Sugg::hir_opt(cx, a),
], {
}
};
if_chain! {
if let StmtSemi(ref expr, _) = s.node;
if let Expr_::ExprBinary(ref binop, ref a, ref b) = expr.node;
if binop.node == BiAnd || binop.node == BiOr;
if let Some(sugg) = Sugg::hir_opt(cx, a);
then {
span_lint_and_then(cx,
SHORT_CIRCUIT_STATEMENT,
s.span,
@ -299,7 +300,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
db.span_suggestion(s.span, "replace it with",
format!("if {} {{ {}; }}", sugg, &snippet(cx, b.span, "..")));
});
}};
}
};
}
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
@ -582,17 +584,18 @@ fn non_macro_local(cx: &LateContext, def: &def::Def) -> bool {
}
fn check_cast(cx: &LateContext, span: Span, e: &Expr, ty: &Ty) {
if_let_chain! {[
let TyPtr(MutTy { mutbl, .. }) = ty.node,
let ExprLit(ref lit) = e.node,
let LitKind::Int(value, ..) = lit.node,
value == 0,
!in_constant(cx, e.id)
], {
if_chain! {
if let TyPtr(MutTy { mutbl, .. }) = ty.node;
if let ExprLit(ref lit) = e.node;
if let LitKind::Int(value, ..) = lit.node;
if value == 0;
if !in_constant(cx, e.id);
then {
let msg = match mutbl {
Mutability::MutMutable => "`0 as *mut _` detected. Consider using `ptr::null_mut()`",
Mutability::MutImmutable => "`0 as *const _` detected. Consider using `ptr::null()`",
};
span_lint(cx, ZERO_PTR, span, msg);
}}
}
}
}

View file

@ -322,16 +322,16 @@ impl EarlyLintPass for MiscEarly {
fn check_block(&mut self, cx: &EarlyContext, block: &Block) {
for w in block.stmts.windows(2) {
if_let_chain! {[
let StmtKind::Local(ref local) = w[0].node,
let Option::Some(ref t) = local.init,
let ExprKind::Closure(_, _, _, _) = t.node,
let PatKind::Ident(_, sp_ident, _) = local.pat.node,
let StmtKind::Semi(ref second) = w[1].node,
let ExprKind::Assign(_, ref call) = second.node,
let ExprKind::Call(ref closure, _) = call.node,
let ExprKind::Path(_, ref path) = closure.node
], {
if_chain! {
if let StmtKind::Local(ref local) = w[0].node;
if let Option::Some(ref t) = local.init;
if let ExprKind::Closure(_, _, _, _) = t.node;
if let PatKind::Ident(_, sp_ident, _) = local.pat.node;
if let StmtKind::Semi(ref second) = w[1].node;
if let ExprKind::Assign(_, ref call) = second.node;
if let ExprKind::Call(ref closure, _) = call.node;
if let ExprKind::Path(_, ref path) = closure.node;
then {
if sp_ident.node == (&path.segments[0]).identifier {
span_lint(
cx,
@ -340,19 +340,20 @@ impl EarlyLintPass for MiscEarly {
"Closure called just once immediately after it was declared",
);
}
}}
}
}
}
}
}
impl MiscEarly {
fn check_lit(&self, cx: &EarlyContext, lit: &Lit) {
if_let_chain! {[
let LitKind::Int(value, ..) = lit.node,
let Some(src) = snippet_opt(cx, lit.span),
let Some(firstch) = src.chars().next(),
char::to_digit(firstch, 10).is_some()
], {
if_chain! {
if let LitKind::Int(value, ..) = lit.node;
if let Some(src) = snippet_opt(cx, lit.span);
if let Some(firstch) = src.chars().next();
if char::to_digit(firstch, 10).is_some();
then {
let mut prev = '\0';
for ch in src.chars() {
if ch == 'i' || ch == 'u' {
@ -398,13 +399,14 @@ impl MiscEarly {
);
});
}
}}
if_let_chain! {[
let LitKind::Float(..) = lit.node,
let Some(src) = snippet_opt(cx, lit.span),
let Some(firstch) = src.chars().next(),
char::to_digit(firstch, 10).is_some()
], {
}
}
if_chain! {
if let LitKind::Float(..) = lit.node;
if let Some(src) = snippet_opt(cx, lit.span);
if let Some(firstch) = src.chars().next();
if char::to_digit(firstch, 10).is_some();
then {
let mut prev = '\0';
for ch in src.chars() {
if ch == 'f' {
@ -416,6 +418,7 @@ impl MiscEarly {
}
prev = ch;
}
}}
}
}
}
}

View file

@ -75,14 +75,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow {
if in_macro(pat.span) {
return;
}
if_let_chain! {[
let PatKind::Binding(BindingAnnotation::Ref, _, name, _) = pat.node,
let ty::TyRef(_, ref tam) = cx.tables.pat_ty(pat).sty,
tam.mutbl == MutImmutable,
let ty::TyRef(_, ref tam) = tam.ty.sty,
if_chain! {
if let PatKind::Binding(BindingAnnotation::Ref, _, name, _) = pat.node;
if let ty::TyRef(_, ref tam) = cx.tables.pat_ty(pat).sty;
if tam.mutbl == MutImmutable;
if let ty::TyRef(_, ref tam) = tam.ty.sty;
// only lint immutable refs, because borrowed `&mut T` cannot be moved out
tam.mutbl == MutImmutable,
], {
if tam.mutbl == MutImmutable;
then {
span_lint_and_then(
cx,
NEEDLESS_BORROW,
@ -94,6 +94,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow {
}
}
)
}}
}
}
}
}

View file

@ -64,19 +64,20 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrowedRef {
return;
}
if_let_chain! {[
if_chain! {
// Only lint immutable refs, because `&mut ref T` may be useful.
let PatKind::Ref(ref sub_pat, MutImmutable) = pat.node,
if let PatKind::Ref(ref sub_pat, MutImmutable) = pat.node;
// Check sub_pat got a `ref` keyword (excluding `ref mut`).
let PatKind::Binding(BindingAnnotation::Ref, _, spanned_name, ..) = sub_pat.node,
], {
if let PatKind::Binding(BindingAnnotation::Ref, _, spanned_name, ..) = sub_pat.node;
then {
span_lint_and_then(cx, NEEDLESS_BORROWED_REFERENCE, pat.span,
"this pattern takes a reference on something that is being de-referenced",
|db| {
let hint = snippet(cx, spanned_name.span, "..").into_owned();
db.span_suggestion(pat.span, "try removing the `&ref` part and just keep", hint);
});
}}
}
}
}
}

View file

@ -64,13 +64,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
match kind {
FnKind::ItemFn(.., attrs) => for a in attrs {
if_let_chain!{[
a.meta_item_list().is_some(),
let Some(name) = a.name(),
name == "proc_macro_derive",
], {
if_chain! {
if a.meta_item_list().is_some();
if let Some(name) = a.name();
if name == "proc_macro_derive";
then {
return;
}}
}
}
},
_ => return,
}
@ -148,17 +149,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
)
};
if_let_chain! {[
!is_self(arg),
!ty.is_mutable_pointer(),
!is_copy(cx, ty),
!fn_traits.iter().any(|&t| implements_trait(cx, ty, t, &[])),
!implements_borrow_trait,
!all_borrowable_trait,
if_chain! {
if !is_self(arg);
if !ty.is_mutable_pointer();
if !is_copy(cx, ty);
if !fn_traits.iter().any(|&t| implements_trait(cx, ty, t, &[]));
if !implements_borrow_trait;
if !all_borrowable_trait;
let PatKind::Binding(mode, canonical_id, ..) = arg.pat.node,
!moved_vars.contains(&canonical_id),
], {
if let PatKind::Binding(mode, canonical_id, ..) = arg.pat.node;
if !moved_vars.contains(&canonical_id);
then {
if mode == BindingAnnotation::Mutable || mode == BindingAnnotation::RefMut {
continue;
}
@ -166,16 +167,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
// Dereference suggestion
let sugg = |db: &mut DiagnosticBuilder| {
let deref_span = spans_need_deref.get(&canonical_id);
if_let_chain! {[
match_type(cx, ty, &paths::VEC),
let Some(clone_spans) =
get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]),
let TyPath(QPath::Resolved(_, ref path)) = input.node,
let Some(elem_ty) = path.segments.iter()
if_chain! {
if match_type(cx, ty, &paths::VEC);
if let Some(clone_spans) =
get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]);
if let TyPath(QPath::Resolved(_, ref path)) = input.node;
if let Some(elem_ty) = path.segments.iter()
.find(|seg| seg.name == "Vec")
.and_then(|ps| ps.parameters.as_ref())
.map(|params| &params.types[0]),
], {
.map(|params| &params.types[0]);
then {
let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_"));
db.span_suggestion(input.span,
"consider changing the type to",
@ -196,7 +197,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
// cannot be destructured, no need for `*` suggestion
assert!(deref_span.is_none());
return;
}}
}
}
if match_type(cx, ty, &paths::STRING) {
if let Some(clone_spans) =
@ -242,7 +244,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
"this argument is passed by value, but not consumed in the function body",
sugg,
);
}}
}
}
}
}
}
@ -299,10 +302,10 @@ impl<'a, 'tcx> MovedVariablesCtxt<'a, 'tcx> {
map::Node::NodeStmt(s) => {
// `let <pat> = x;`
if_let_chain! {[
let StmtDecl(ref decl, _) = s.node,
let DeclLocal(ref local) = decl.node,
], {
if_chain! {
if let StmtDecl(ref decl, _) = s.node;
if let DeclLocal(ref local) = decl.node;
then {
self.spans_need_deref
.entry(vid)
.or_insert_with(HashSet::new)
@ -310,7 +313,8 @@ impl<'a, 'tcx> MovedVariablesCtxt<'a, 'tcx> {
.as_ref()
.map(|e| e.span)
.expect("`let` stmt without init aren't caught by match_pat"));
}}
}
}
},
_ => {},

View file

@ -45,16 +45,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NegMultiply {
}
fn check_mul(cx: &LateContext, span: Span, lit: &Expr, exp: &Expr) {
if_let_chain!([
let ExprLit(ref l) = lit.node,
let Constant::Int(ref ci) = consts::lit_to_constant(&l.node, cx.tcx, cx.tables.expr_ty(lit)),
let Some(val) = ci.to_u64(),
val == 1,
cx.tables.expr_ty(exp).is_integral()
], {
if_chain! {
if let ExprLit(ref l) = lit.node;
if let Constant::Int(ref ci) = consts::lit_to_constant(&l.node, cx.tcx, cx.tables.expr_ty(lit));
if let Some(val) = ci.to_u64();
if val == 1;
if cx.tables.expr_ty(exp).is_integral();
then {
span_lint(cx,
NEG_MULTIPLY,
span,
"Negation by multiplying with -1");
})
}
}
}

View file

@ -117,11 +117,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
if decl.inputs.is_empty() && name == "new" && cx.access_levels.is_reachable(id) {
let self_ty = cx.tcx
.type_of(cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(id)));
if_let_chain!{[
same_tys(cx, self_ty, return_ty(cx, id)),
let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT),
!implements_trait(cx, self_ty, default_trait_id, &[])
], {
if_chain! {
if same_tys(cx, self_ty, return_ty(cx, id));
if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
if !implements_trait(cx, self_ty, default_trait_id, &[]);
then {
if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) {
span_lint_and_then(cx,
NEW_WITHOUT_DEFAULT_DERIVE, span,
@ -142,15 +142,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
span,
"try this",
&format!(
"impl Default for {} {{
"impl Default for {} {{
fn default() -> Self {{
Self::new()
}}
}}",
}}",
self_ty));
});
}
}}
}
}
}
}
}

View file

@ -43,14 +43,14 @@ impl LintPass for Pass {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_let_chain! {[ //begin checking variables
let ExprMatch(ref op, ref body, ref source) = expr.node, //test if expr is a match
let MatchSource::IfLetDesugar { .. } = *source, //test if it is an If Let
let ExprMethodCall(_, _, ref result_types) = op.node, //check is expr.ok() has type Result<T,E>.ok()
let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pats[0].node, //get operation
method_chain_args(op, &["ok"]).is_some() //test to see if using ok() methoduse std::marker::Sized;
if_chain! { //begin checking variables
if let ExprMatch(ref op, ref body, ref source) = expr.node; //test if expr is a match
if let MatchSource::IfLetDesugar { .. } = *source; //test if it is an If Let
if let ExprMethodCall(_, _, ref result_types) = op.node; //check is expr.ok() has type Result<T,E>.ok()
if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pats[0].node; //get operation
if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
], {
then {
let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &paths::RESULT);
let some_expr_string = snippet(cx, y[0].span, "");
if print::to_string(print::NO_ANN, |s| s.print_path(x, false)) == "Some" && is_result_type {
@ -58,6 +58,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
"Matching on `Some` with `ok()` is redundant",
&format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string));
}
}}
}
}
}
}

View file

@ -31,16 +31,16 @@ impl LintPass for OverflowCheckConditional {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OverflowCheckConditional {
// a + b < a, a > a + b, a < a - b, a - b > a
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_let_chain! {[
let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node,
let Expr_::ExprBinary(ref op2, ref ident1, ref ident2) = first.node,
let Expr_::ExprPath(QPath::Resolved(_, ref path1)) = ident1.node,
let Expr_::ExprPath(QPath::Resolved(_, ref path2)) = ident2.node,
let Expr_::ExprPath(QPath::Resolved(_, ref path3)) = second.node,
path1.segments[0] == path3.segments[0] || path2.segments[0] == path3.segments[0],
cx.tables.expr_ty(ident1).is_integral(),
cx.tables.expr_ty(ident2).is_integral()
], {
if_chain! {
if let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node;
if let Expr_::ExprBinary(ref op2, ref ident1, ref ident2) = first.node;
if let Expr_::ExprPath(QPath::Resolved(_, ref path1)) = ident1.node;
if let Expr_::ExprPath(QPath::Resolved(_, ref path2)) = ident2.node;
if let Expr_::ExprPath(QPath::Resolved(_, ref path3)) = second.node;
if path1.segments[0] == path3.segments[0] || path2.segments[0] == path3.segments[0];
if cx.tables.expr_ty(ident1).is_integral();
if cx.tables.expr_ty(ident2).is_integral();
then {
if let BinOp_::BiLt = op.node {
if let BinOp_::BiAdd = op2.node {
span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span,
@ -53,18 +53,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OverflowCheckConditional {
"You are trying to use classic C underflow conditions that will fail in Rust.");
}
}
}}
}
}
if_let_chain! {[
let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node,
let Expr_::ExprBinary(ref op2, ref ident1, ref ident2) = second.node,
let Expr_::ExprPath(QPath::Resolved(_, ref path1)) = ident1.node,
let Expr_::ExprPath(QPath::Resolved(_, ref path2)) = ident2.node,
let Expr_::ExprPath(QPath::Resolved(_, ref path3)) = first.node,
path1.segments[0] == path3.segments[0] || path2.segments[0] == path3.segments[0],
cx.tables.expr_ty(ident1).is_integral(),
cx.tables.expr_ty(ident2).is_integral()
], {
if_chain! {
if let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node;
if let Expr_::ExprBinary(ref op2, ref ident1, ref ident2) = second.node;
if let Expr_::ExprPath(QPath::Resolved(_, ref path1)) = ident1.node;
if let Expr_::ExprPath(QPath::Resolved(_, ref path2)) = ident2.node;
if let Expr_::ExprPath(QPath::Resolved(_, ref path3)) = first.node;
if path1.segments[0] == path3.segments[0] || path2.segments[0] == path3.segments[0];
if cx.tables.expr_ty(ident1).is_integral();
if cx.tables.expr_ty(ident2).is_integral();
then {
if let BinOp_::BiGt = op.node {
if let BinOp_::BiAdd = op2.node {
span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span,
@ -77,6 +78,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OverflowCheckConditional {
"You are trying to use classic C underflow conditions that will fail in Rust.");
}
}
}}
}
}
}
}

View file

@ -34,23 +34,24 @@ impl LintPass for Pass {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_let_chain! {[
let ExprBlock(ref block) = expr.node,
let Some(ref ex) = block.expr,
let ExprCall(ref fun, ref params) = ex.node,
params.len() == 2,
let ExprPath(ref qpath) = fun.node,
let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id)),
match_def_path(cx.tcx, fun_def_id, &paths::BEGIN_PANIC),
let ExprLit(ref lit) = params[0].node,
is_direct_expn_of(expr.span, "panic").is_some(),
let LitKind::Str(ref string, _) = lit.node,
let Some(par) = string.as_str().find('{'),
string.as_str()[par..].contains('}'),
params[0].span.source_callee().is_none()
], {
if_chain! {
if let ExprBlock(ref block) = expr.node;
if let Some(ref ex) = block.expr;
if let ExprCall(ref fun, ref params) = ex.node;
if params.len() == 2;
if let ExprPath(ref qpath) = fun.node;
if let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id));
if match_def_path(cx.tcx, fun_def_id, &paths::BEGIN_PANIC);
if let ExprLit(ref lit) = params[0].node;
if is_direct_expn_of(expr.span, "panic").is_some();
if let LitKind::Str(ref string, _) = lit.node;
if let Some(par) = string.as_str().find('{');
if string.as_str()[par..].contains('}');
if params[0].span.source_callee().is_none();
then {
span_lint(cx, PANIC_PARAMS, params[0].span,
"you probably are missing some parameter in your format string");
}}
}
}
}
}

View file

@ -37,12 +37,12 @@ impl LintPass for Pass {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
if_let_chain! {[
let ItemImpl(_, _, _, _, Some(ref trait_ref), _, ref impl_items) = item.node,
!is_automatically_derived(&*item.attrs),
let Some(eq_trait) = cx.tcx.lang_items().eq_trait(),
trait_ref.path.def.def_id() == eq_trait
], {
if_chain! {
if let ItemImpl(_, _, _, _, Some(ref trait_ref), _, ref impl_items) = item.node;
if !is_automatically_derived(&*item.attrs);
if let Some(eq_trait) = cx.tcx.lang_items().eq_trait();
if trait_ref.path.def.def_id() == eq_trait;
then {
for impl_item in impl_items {
if impl_item.name == "ne" {
span_lint(cx,
@ -51,6 +51,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
"re-implementing `PartialEq::ne` is unnecessary")
}
}
}};
}
};
}
}

View file

@ -89,11 +89,11 @@ impl LintPass for Pass {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_let_chain! {[
let ExprCall(ref fun, ref args) = expr.node,
let ExprPath(ref qpath) = fun.node,
let Some(fun_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id)),
], {
if_chain! {
if let ExprCall(ref fun, ref args) = expr.node;
if let ExprPath(ref qpath) = fun.node;
if let Some(fun_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id));
then {
// Search for `std::io::_print(..)` which is unique in a
// `print!` expansion.
@ -107,25 +107,26 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
span_lint(cx, PRINT_STDOUT, span, &format!("use of `{}!`", name));
if_let_chain!{[
if_chain! {
// ensure we're calling Arguments::new_v1
args.len() == 1,
let ExprCall(ref args_fun, ref args_args) = args[0].node,
let ExprPath(ref qpath) = args_fun.node,
let Some(const_def_id) = opt_def_id(resolve_node(cx, qpath, args_fun.hir_id)),
match_def_path(cx.tcx, const_def_id, &paths::FMT_ARGUMENTS_NEWV1),
args_args.len() == 2,
let ExprAddrOf(_, ref match_expr) = args_args[1].node,
let ExprMatch(ref args, _, _) = match_expr.node,
let ExprTup(ref args) = args.node,
let Some((fmtstr, fmtlen)) = get_argument_fmtstr_parts(&args_args[0]),
], {
if args.len() == 1;
if let ExprCall(ref args_fun, ref args_args) = args[0].node;
if let ExprPath(ref qpath) = args_fun.node;
if let Some(const_def_id) = opt_def_id(resolve_node(cx, qpath, args_fun.hir_id));
if match_def_path(cx.tcx, const_def_id, &paths::FMT_ARGUMENTS_NEWV1);
if args_args.len() == 2;
if let ExprAddrOf(_, ref match_expr) = args_args[1].node;
if let ExprMatch(ref args, _, _) = match_expr.node;
if let ExprTup(ref args) = args.node;
if let Some((fmtstr, fmtlen)) = get_argument_fmtstr_parts(&args_args[0]);
then {
match name {
"print" => check_print(cx, span, args, fmtstr, fmtlen),
"println" => check_println(cx, span, fmtstr, fmtlen),
_ => (),
}
}}
}
}
}
}
// Search for something like
@ -140,7 +141,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}
}
}
}}
}
}
}
}
@ -152,36 +154,38 @@ fn check_print<'a, 'tcx>(
fmtstr: InternedString,
fmtlen: usize,
) {
if_let_chain!{[
if_chain! {
// check the final format string part
let Some('\n') = fmtstr.chars().last(),
if let Some('\n') = fmtstr.chars().last();
// "foo{}bar" is made into two strings + one argument,
// if the format string starts with `{}` (eg. "{}foo"),
// the string array is prepended an empty string "".
// We only want to check the last string after any `{}`:
args.len() < fmtlen,
], {
if args.len() < fmtlen;
then {
span_lint(cx, PRINT_WITH_NEWLINE, span,
"using `print!()` with a format string that ends in a \
newline, consider using `println!()` instead");
}}
}
}
}
/// Check for println!("")
fn check_println<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, fmtstr: InternedString, fmtlen: usize) {
if_let_chain!{[
if_chain! {
// check that the string is empty
fmtlen == 1,
fmtstr.deref() == "\n",
if fmtlen == 1;
if fmtstr.deref() == "\n";
// check the presence of that string
let Ok(snippet) = cx.sess().codemap().span_to_snippet(span),
snippet.contains("\"\""),
], {
if let Ok(snippet) = cx.sess().codemap().span_to_snippet(span);
if snippet.contains("\"\"");
then {
span_lint(cx, PRINT_WITH_NEWLINE, span,
"using `println!(\"\")`, consider using `println!()` instead");
}}
}
}
}
fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool {
@ -202,14 +206,15 @@ fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool {
/// Returns the slice of format string parts in an `Arguments::new_v1` call.
fn get_argument_fmtstr_parts(expr: &Expr) -> Option<(InternedString, usize)> {
if_let_chain! {[
let ExprAddrOf(_, ref expr) = expr.node, // &["…", "…", …]
let ExprArray(ref exprs) = expr.node,
let Some(expr) = exprs.last(),
let ExprLit(ref lit) = expr.node,
let LitKind::Str(ref lit, _) = lit.node,
], {
if_chain! {
if let ExprAddrOf(_, ref expr) = expr.node; // &["…", "…", …]
if let ExprArray(ref exprs) = expr.node;
if let Some(expr) = exprs.last();
if let ExprLit(ref lit) = expr.node;
if let LitKind::Str(ref lit, _) = lit.node;
then {
return Some((lit.as_str(), exprs.len()));
}}
}
}
None
}

View file

@ -156,13 +156,14 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId, opt_body_id: Option<
{
if match_type(cx, ty, &paths::VEC) {
let mut ty_snippet = None;
if_let_chain!([
let TyPath(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).node,
let Some(&PathSegment{parameters: Some(ref parameters), ..}) = path.segments.last(),
parameters.types.len() == 1,
], {
if_chain! {
if let TyPath(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).node;
if let Some(&PathSegment{parameters: Some(ref parameters), ..}) = path.segments.last();
if parameters.types.len() == 1;
then {
ty_snippet = snippet_opt(cx, parameters.types[0].span);
});
}
};
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) {
span_lint_and_then(
cx,

View file

@ -113,35 +113,36 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} else if name == "zip" && args.len() == 2 {
let iter = &args[0].node;
let zip_arg = &args[1];
if_let_chain! {[
if_chain! {
// .iter() call
let ExprMethodCall(ref iter_path, _, ref iter_args ) = *iter,
iter_path.name == "iter",
if let ExprMethodCall(ref iter_path, _, ref iter_args ) = *iter;
if iter_path.name == "iter";
// range expression in .zip() call: 0..x.len()
let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(zip_arg),
is_integer_literal(start, 0),
if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(zip_arg);
if is_integer_literal(start, 0);
// .len() call
let ExprMethodCall(ref len_path, _, ref len_args) = end.node,
len_path.name == "len" && len_args.len() == 1,
if let ExprMethodCall(ref len_path, _, ref len_args) = end.node;
if len_path.name == "len" && len_args.len() == 1;
// .iter() and .len() called on same Path
let ExprPath(QPath::Resolved(_, ref iter_path)) = iter_args[0].node,
let ExprPath(QPath::Resolved(_, ref len_path)) = len_args[0].node,
iter_path.segments == len_path.segments
], {
if let ExprPath(QPath::Resolved(_, ref iter_path)) = iter_args[0].node;
if let ExprPath(QPath::Resolved(_, ref len_path)) = len_args[0].node;
if iter_path.segments == len_path.segments;
then {
span_lint(cx,
RANGE_ZIP_WITH_LEN,
expr.span,
&format!("It is more idiomatic to use {}.iter().enumerate()",
snippet(cx, iter_args[0].span, "_")));
}}
}
}
}
}
// exclusive range plus one: x..(y+1)
if_let_chain! {[
let Some(higher::Range { start, end: Some(end), limits: RangeLimits::HalfOpen }) = higher::range(expr),
let Some(y) = y_plus_one(end),
], {
if_chain! {
if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::HalfOpen }) = higher::range(expr);
if let Some(y) = y_plus_one(end);
then {
span_lint_and_then(
cx,
RANGE_PLUS_ONE,
@ -155,13 +156,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
format!("{}..={}", start, end));
},
);
}}
}
}
// inclusive range minus one: x..=(y-1)
if_let_chain! {[
let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::range(expr),
let Some(y) = y_minus_one(end),
], {
if_chain! {
if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::range(expr);
if let Some(y) = y_minus_one(end);
then {
span_lint_and_then(
cx,
RANGE_MINUS_ONE,
@ -175,7 +177,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
format!("{}..{}", start, end));
},
);
}}
}
}
}
}

View file

@ -86,12 +86,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}
fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx Block) {
if_let_chain!{[
self.last.is_none(),
let Some(ref expr) = block.expr,
match_type(cx, cx.tables.expr_ty(expr), &paths::REGEX),
let Some(span) = is_expn_of(expr.span, "regex"),
], {
if_chain! {
if self.last.is_none();
if let Some(ref expr) = block.expr;
if match_type(cx, cx.tables.expr_ty(expr), &paths::REGEX);
if let Some(span) = is_expn_of(expr.span, "regex");
then {
if !self.spans.contains(&span) {
span_lint(cx,
REGEX_MACRO,
@ -101,7 +101,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
self.spans.insert(span);
}
self.last = Some(block.id);
}}
}
}
}
fn check_block_post(&mut self, _: &LateContext<'a, 'tcx>, block: &'tcx Block) {
@ -111,12 +112,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_let_chain!{[
let ExprCall(ref fun, ref args) = expr.node,
let ExprPath(ref qpath) = fun.node,
args.len() == 1,
let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, fun.hir_id)),
], {
if_chain! {
if let ExprCall(ref fun, ref args) = expr.node;
if let ExprPath(ref qpath) = fun.node;
if args.len() == 1;
if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, fun.hir_id));
then {
if match_def_path(cx.tcx, def_id, &paths::REGEX_NEW) ||
match_def_path(cx.tcx, def_id, &paths::REGEX_BUILDER_NEW) {
check_regex(cx, &args[0], true);
@ -128,7 +129,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} else if match_def_path(cx.tcx, def_id, &paths::REGEX_BYTES_SET_NEW) {
check_set(cx, &args[0], false);
}
}}
}
}
}
}
@ -179,14 +181,15 @@ fn is_trivial_regex(s: &regex_syntax::Expr) -> Option<&'static str> {
}
fn check_set<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, utf8: bool) {
if_let_chain! {[
let ExprAddrOf(_, ref expr) = expr.node,
let ExprArray(ref exprs) = expr.node,
], {
if_chain! {
if let ExprAddrOf(_, ref expr) = expr.node;
if let ExprArray(ref exprs) = expr.node;
then {
for expr in exprs {
check_regex(cx, expr, utf8);
}
}}
}
}
}
fn check_regex<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, utf8: bool) {

View file

@ -103,20 +103,20 @@ impl ReturnPass {
let mut it = block.stmts.iter();
// we need both a let-binding stmt and an expr
if_let_chain! {[
let Some(retexpr) = it.next_back(),
let ast::StmtKind::Expr(ref retexpr) = retexpr.node,
let Some(stmt) = it.next_back(),
let ast::StmtKind::Local(ref local) = stmt.node,
if_chain! {
if let Some(retexpr) = it.next_back();
if let ast::StmtKind::Expr(ref retexpr) = retexpr.node;
if let Some(stmt) = it.next_back();
if let ast::StmtKind::Local(ref local) = stmt.node;
// don't lint in the presence of type inference
local.ty.is_none(),
!local.attrs.iter().any(attr_is_cfg),
let Some(ref initexpr) = local.init,
let ast::PatKind::Ident(_, Spanned { node: id, .. }, _) = local.pat.node,
let ast::ExprKind::Path(_, ref path) = retexpr.node,
match_path_ast(path, &[&id.name.as_str()]),
!in_external_macro(cx, initexpr.span),
], {
if local.ty.is_none();
if !local.attrs.iter().any(attr_is_cfg);
if let Some(ref initexpr) = local.init;
if let ast::PatKind::Ident(_, Spanned { node: id, .. }, _) = local.pat.node;
if let ast::ExprKind::Path(_, ref path) = retexpr.node;
if match_path_ast(path, &[&id.name.as_str()]);
if !in_external_macro(cx, initexpr.span);
then {
span_note_and_lint(cx,
LET_AND_RETURN,
retexpr.span,
@ -124,7 +124,8 @@ impl ReturnPass {
Consider returning the expression directly.",
initexpr.span,
"this expression can be directly returned");
}}
}
}
}
}

View file

@ -59,27 +59,27 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Swap {
/// Implementation of the `MANUAL_SWAP` lint.
fn check_manual_swap(cx: &LateContext, block: &Block) {
for w in block.stmts.windows(3) {
if_let_chain!{[
if_chain! {
// let t = foo();
let StmtDecl(ref tmp, _) = w[0].node,
let DeclLocal(ref tmp) = tmp.node,
let Some(ref tmp_init) = tmp.init,
let PatKind::Binding(_, _, ref tmp_name, None) = tmp.pat.node,
if let StmtDecl(ref tmp, _) = w[0].node;
if let DeclLocal(ref tmp) = tmp.node;
if let Some(ref tmp_init) = tmp.init;
if let PatKind::Binding(_, _, ref tmp_name, None) = tmp.pat.node;
// foo() = bar();
let StmtSemi(ref first, _) = w[1].node,
let ExprAssign(ref lhs1, ref rhs1) = first.node,
if let StmtSemi(ref first, _) = w[1].node;
if let ExprAssign(ref lhs1, ref rhs1) = first.node;
// bar() = t;
let StmtSemi(ref second, _) = w[2].node,
let ExprAssign(ref lhs2, ref rhs2) = second.node,
let ExprPath(QPath::Resolved(None, ref rhs2)) = rhs2.node,
rhs2.segments.len() == 1,
if let StmtSemi(ref second, _) = w[2].node;
if let ExprAssign(ref lhs2, ref rhs2) = second.node;
if let ExprPath(QPath::Resolved(None, ref rhs2)) = rhs2.node;
if rhs2.segments.len() == 1;
tmp_name.node.as_str() == rhs2.segments[0].name.as_str(),
SpanlessEq::new(cx).ignore_fn().eq_expr(tmp_init, lhs1),
SpanlessEq::new(cx).ignore_fn().eq_expr(rhs1, lhs2)
], {
if tmp_name.node.as_str() == rhs2.segments[0].name.as_str();
if SpanlessEq::new(cx).ignore_fn().eq_expr(tmp_init, lhs1);
if SpanlessEq::new(cx).ignore_fn().eq_expr(rhs1, lhs2);
then {
fn check_for_slice<'a>(
cx: &LateContext,
lhs1: &'a Expr,
@ -136,22 +136,23 @@ fn check_manual_swap(cx: &LateContext, block: &Block) {
}
}
});
}}
}
}
}
}
/// Implementation of the `ALMOST_SWAPPED` lint.
fn check_suspicious_swap(cx: &LateContext, block: &Block) {
for w in block.stmts.windows(2) {
if_let_chain!{[
let StmtSemi(ref first, _) = w[0].node,
let StmtSemi(ref second, _) = w[1].node,
!differing_macro_contexts(first.span, second.span),
let ExprAssign(ref lhs0, ref rhs0) = first.node,
let ExprAssign(ref lhs1, ref rhs1) = second.node,
SpanlessEq::new(cx).ignore_fn().eq_expr(lhs0, rhs1),
SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, rhs0)
], {
if_chain! {
if let StmtSemi(ref first, _) = w[0].node;
if let StmtSemi(ref second, _) = w[1].node;
if !differing_macro_contexts(first.span, second.span);
if let ExprAssign(ref lhs0, ref rhs0) = first.node;
if let ExprAssign(ref lhs1, ref rhs1) = second.node;
if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs0, rhs1);
if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, rhs0);
then {
let lhs0 = Sugg::hir_opt(cx, lhs0);
let rhs0 = Sugg::hir_opt(cx, rhs0);
let (what, lhs, rhs) = if let (Some(first), Some(second)) = (lhs0, rhs0) {
@ -173,6 +174,7 @@ fn check_suspicious_swap(cx: &LateContext, block: &Block) {
db.note("or maybe you should use `std::mem::replace`?");
}
});
}}
}
}
}
}

View file

@ -301,14 +301,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
/// lifetime, but it should be rare.
fn get_type_snippet(cx: &LateContext, path: &QPath, to_rty: Ty) -> String {
let seg = last_path_segment(path);
if_let_chain!{[
let Some(ref params) = seg.parameters,
!params.parenthesized,
let Some(to_ty) = params.types.get(1),
let TyRptr(_, ref to_ty) = to_ty.node,
], {
if_chain! {
if let Some(ref params) = seg.parameters;
if !params.parenthesized;
if let Some(to_ty) = params.types.get(1);
if let TyRptr(_, ref to_ty) = to_ty.node;
then {
return snippet(cx, to_ty.ty.span, &to_rty.to_string()).to_string();
}}
}
}
to_rty.to_string()
}

View file

@ -158,21 +158,22 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) {
if let Some(def_id) = opt_def_id(def) {
if Some(def_id) == cx.tcx.lang_items().owned_box() {
let last = last_path_segment(qpath);
if_let_chain! {[
let Some(ref params) = last.parameters,
!params.parenthesized,
let Some(vec) = params.types.get(0),
let TyPath(ref qpath) = vec.node,
let Some(did) = opt_def_id(cx.tables.qpath_def(qpath, cx.tcx.hir.node_to_hir_id(vec.id))),
match_def_path(cx.tcx, did, &paths::VEC),
], {
if_chain! {
if let Some(ref params) = last.parameters;
if !params.parenthesized;
if let Some(vec) = params.types.get(0);
if let TyPath(ref qpath) = vec.node;
if let Some(did) = opt_def_id(cx.tables.qpath_def(qpath, cx.tcx.hir.node_to_hir_id(vec.id)));
if match_def_path(cx.tcx, did, &paths::VEC);
then {
span_help_and_lint(cx,
BOX_VEC,
ast_ty.span,
"you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
"`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.");
return; // don't recurse into the type
}}
}
}
} else if match_def_path(cx.tcx, def_id, &paths::LINKED_LIST) {
span_help_and_lint(
cx,
@ -227,15 +228,15 @@ fn check_ty_rptr(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool, lt: &Lifeti
TyPath(ref qpath) => {
let hir_id = cx.tcx.hir.node_to_hir_id(mut_ty.ty.id);
let def = cx.tables.qpath_def(qpath, hir_id);
if_let_chain! {[
let Some(def_id) = opt_def_id(def),
Some(def_id) == cx.tcx.lang_items().owned_box(),
let QPath::Resolved(None, ref path) = *qpath,
let [ref bx] = *path.segments,
let Some(ref params) = bx.parameters,
!params.parenthesized,
let [ref inner] = *params.types
], {
if_chain! {
if let Some(def_id) = opt_def_id(def);
if Some(def_id) == cx.tcx.lang_items().owned_box();
if let QPath::Resolved(None, ref path) = *qpath;
if let [ref bx] = *path.segments;
if let Some(ref params) = bx.parameters;
if !params.parenthesized;
if let [ref inner] = *params.types;
then {
if is_any_trait(inner) {
// Ignore `Box<Any>` types, see #1884 for details.
return;
@ -259,7 +260,8 @@ fn check_ty_rptr(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool, lt: &Lifeti
format!("&{}{}{}", ltopt, mutopt, &snippet(cx, inner.span, ".."))
);
return; // don't recurse into the type
}};
}
};
check_ty(cx, &mut_ty.ty, is_local);
},
_ => check_ty(cx, &mut_ty.ty, is_local),
@ -268,15 +270,16 @@ fn check_ty_rptr(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool, lt: &Lifeti
// Returns true if given type is `Any` trait.
fn is_any_trait(t: &hir::Ty) -> bool {
if_let_chain! {[
let TyTraitObject(ref traits, _) = t.node,
traits.len() >= 1,
if_chain! {
if let TyTraitObject(ref traits, _) = t.node;
if traits.len() >= 1;
// Only Send/Sync can be used as additional traits, so it is enough to
// check only the first trait.
match_path(&traits[0].trait_ref.path, &paths::ANY_TRAIT)
], {
if match_path(&traits[0].trait_ref.path, &paths::ANY_TRAIT);
then {
return true;
}}
}
}
false
}
@ -1719,11 +1722,11 @@ impl<'a, 'b, 'tcx: 'a + 'b> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'
}
fn visit_expr(&mut self, e: &'tcx Expr) {
if_let_chain!{[
let ExprCall(ref fun, ref args) = e.node,
let ExprPath(QPath::TypeRelative(ref ty, ref method)) = fun.node,
let TyPath(QPath::Resolved(None, ref ty_path)) = ty.node,
], {
if_chain! {
if let ExprCall(ref fun, ref args) = e.node;
if let ExprPath(QPath::TypeRelative(ref ty, ref method)) = fun.node;
if let TyPath(QPath::Resolved(None, ref ty_path)) = ty.node;
then {
if !same_tys(self.cx, self.target.ty(), self.body.expr_ty(e)) {
return;
}
@ -1755,7 +1758,8 @@ impl<'a, 'b, 'tcx: 'a + 'b> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'
);
}
}
}}
}
}
walk_expr(self, e);
}

View file

@ -54,10 +54,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
if in_macro(item.span) {
return;
}
if_let_chain!([
let ItemImpl(.., ref item_type, ref refs) = item.node,
let Ty_::TyPath(QPath::Resolved(_, ref item_path)) = item_type.node,
], {
if_chain! {
if let ItemImpl(.., ref item_type, ref refs) = item.node;
if let Ty_::TyPath(QPath::Resolved(_, ref item_path)) = item_type.node;
then {
let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).parameters;
let should_check = if let Some(ref params) = *parameters {
!params.parenthesized && params.lifetimes.len() == 0
@ -73,7 +73,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
visitor.visit_impl_item(cx.tcx.hir.impl_item(impl_item_ref.id));
}
}
})
}
}
}
}

View file

@ -120,13 +120,14 @@ pub fn is_from_for_desugar(decl: &hir::Decl) -> bool {
// // do stuff
// }
// ```
if_let_chain! {[
let hir::DeclLocal(ref loc) = decl.node,
let Some(ref expr) = loc.init,
let hir::ExprMatch(_, _, hir::MatchSource::ForLoopDesugar) = expr.node,
], {
if_chain! {
if let hir::DeclLocal(ref loc) = decl.node;
if let Some(ref expr) = loc.init;
if let hir::ExprMatch(_, _, hir::MatchSource::ForLoopDesugar) = expr.node;
then {
return true;
}}
}
}
// This detects a variable binding in for loop to avoid `let_unit_value`
// lint (see issue #1964).
@ -136,12 +137,13 @@ pub fn is_from_for_desugar(decl: &hir::Decl) -> bool {
// // anything
// }
// ```
if_let_chain! {[
let hir::DeclLocal(ref loc) = decl.node,
let hir::LocalSource::ForLoopDesugar = loc.source,
], {
if_chain! {
if let hir::DeclLocal(ref loc) = decl.node;
if let hir::LocalSource::ForLoopDesugar = loc.source;
then {
return true;
}}
}
}
false
}
@ -149,19 +151,20 @@ pub fn is_from_for_desugar(decl: &hir::Decl) -> bool {
/// Recover the essential nodes of a desugared for loop:
/// `for pat in arg { body }` becomes `(pat, arg, body)`.
pub fn for_loop(expr: &hir::Expr) -> Option<(&hir::Pat, &hir::Expr, &hir::Expr)> {
if_let_chain! {[
let hir::ExprMatch(ref iterexpr, ref arms, hir::MatchSource::ForLoopDesugar) = expr.node,
let hir::ExprCall(_, ref iterargs) = iterexpr.node,
iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none(),
let hir::ExprLoop(ref block, _, _) = arms[0].body.node,
block.expr.is_none(),
let [ _, _, ref let_stmt, ref body ] = *block.stmts,
let hir::StmtDecl(ref decl, _) = let_stmt.node,
let hir::DeclLocal(ref decl) = decl.node,
let hir::StmtExpr(ref expr, _) = body.node,
], {
if_chain! {
if let hir::ExprMatch(ref iterexpr, ref arms, hir::MatchSource::ForLoopDesugar) = expr.node;
if let hir::ExprCall(_, ref iterargs) = iterexpr.node;
if iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none();
if let hir::ExprLoop(ref block, _, _) = arms[0].body.node;
if block.expr.is_none();
if let [ _, _, ref let_stmt, ref body ] = *block.stmts;
if let hir::StmtDecl(ref decl, _) = let_stmt.node;
if let hir::DeclLocal(ref decl) = decl.node;
if let hir::StmtExpr(ref expr, _) = body.node;
then {
return Some((&*decl.pat, &iterargs[0], expr));
}}
}
}
None
}
@ -176,31 +179,33 @@ pub enum VecArgs<'a> {
/// Returns the arguments of the `vec!` macro if this expression was expanded
/// from `vec!`.
pub fn vec_macro<'e>(cx: &LateContext, expr: &'e hir::Expr) -> Option<VecArgs<'e>> {
if_let_chain!{[
let hir::ExprCall(ref fun, ref args) = expr.node,
let hir::ExprPath(ref path) = fun.node,
is_expn_of(fun.span, "vec").is_some(),
let Some(fun_def_id) = opt_def_id(resolve_node(cx, path, fun.hir_id)),
], {
if_chain! {
if let hir::ExprCall(ref fun, ref args) = expr.node;
if let hir::ExprPath(ref path) = fun.node;
if is_expn_of(fun.span, "vec").is_some();
if let Some(fun_def_id) = opt_def_id(resolve_node(cx, path, fun.hir_id));
then {
return if match_def_path(cx.tcx, fun_def_id, &paths::VEC_FROM_ELEM) && args.len() == 2 {
// `vec![elem; size]` case
Some(VecArgs::Repeat(&args[0], &args[1]))
}
else if match_def_path(cx.tcx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 {
// `vec![a, b, c]` case
if_let_chain!{[
let hir::ExprBox(ref boxed) = args[0].node,
let hir::ExprArray(ref args) = boxed.node
], {
if_chain! {
if let hir::ExprBox(ref boxed) = args[0].node;
if let hir::ExprArray(ref args) = boxed.node;
then {
return Some(VecArgs::Vec(&*args));
}}
}
}
None
}
else {
None
};
}}
}
}
None
}

View file

@ -1004,13 +1004,14 @@ pub fn is_self(slf: &Arg) -> bool {
}
pub fn is_self_ty(slf: &hir::Ty) -> bool {
if_let_chain! {[
let TyPath(ref qp) = slf.node,
let QPath::Resolved(None, ref path) = *qp,
let Def::SelfTy(..) = path.def,
], {
if_chain! {
if let TyPath(ref qp) = slf.node;
if let QPath::Resolved(None, ref path) = *qp;
if let Def::SelfTy(..) = path.def;
then {
return true
}}
}
}
false
}
@ -1022,16 +1023,17 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl, body: &'tcx Body) -> impl Iterator<I
/// expanded from `?` operator or `try` macro.
pub fn is_try(expr: &Expr) -> Option<&Expr> {
fn is_ok(arm: &Arm) -> bool {
if_let_chain! {[
let PatKind::TupleStruct(ref path, ref pat, None) = arm.pats[0].node,
match_qpath(path, &paths::RESULT_OK[1..]),
let PatKind::Binding(_, defid, _, None) = pat[0].node,
let ExprPath(QPath::Resolved(None, ref path)) = arm.body.node,
let Def::Local(lid) = path.def,
lid == defid,
], {
if_chain! {
if let PatKind::TupleStruct(ref path, ref pat, None) = arm.pats[0].node;
if match_qpath(path, &paths::RESULT_OK[1..]);
if let PatKind::Binding(_, defid, _, None) = pat[0].node;
if let ExprPath(QPath::Resolved(None, ref path)) = arm.body.node;
if let Def::Local(lid) = path.def;
if lid == defid;
then {
return true;
}}
}
}
false
}
@ -1049,15 +1051,16 @@ pub fn is_try(expr: &Expr) -> Option<&Expr> {
return Some(expr);
}
if_let_chain! {[
arms.len() == 2,
arms[0].pats.len() == 1 && arms[0].guard.is_none(),
arms[1].pats.len() == 1 && arms[1].guard.is_none(),
(is_ok(&arms[0]) && is_err(&arms[1])) ||
(is_ok(&arms[1]) && is_err(&arms[0])),
], {
if_chain! {
if arms.len() == 2;
if arms[0].pats.len() == 1 && arms[0].guard.is_none();
if arms[1].pats.len() == 1 && arms[1].guard.is_none();
if (is_ok(&arms[0]) && is_err(&arms[1])) ||
(is_ok(&arms[1]) && is_err(&arms[0]));
then {
return Some(expr);
}}
}
}
}
None

View file

@ -35,25 +35,27 @@ impl LintPass for Pass {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
// search for `&vec![_]` expressions where the adjusted type is `&[_]`
if_let_chain!{[
let ty::TyRef(_, ref ty) = cx.tables.expr_ty_adjusted(expr).sty,
let ty::TySlice(..) = ty.ty.sty,
let ExprAddrOf(_, ref addressee) = expr.node,
let Some(vec_args) = higher::vec_macro(cx, addressee),
], {
if_chain! {
if let ty::TyRef(_, ref ty) = cx.tables.expr_ty_adjusted(expr).sty;
if let ty::TySlice(..) = ty.ty.sty;
if let ExprAddrOf(_, ref addressee) = expr.node;
if let Some(vec_args) = higher::vec_macro(cx, addressee);
then {
check_vec_macro(cx, &vec_args, expr.span);
}}
}
}
// search for `for _ in vec![…]`
if_let_chain!{[
let Some((_, arg, _)) = higher::for_loop(expr),
let Some(vec_args) = higher::vec_macro(cx, arg),
is_copy(cx, vec_type(cx.tables.expr_ty_adjusted(arg))),
], {
if_chain! {
if let Some((_, arg, _)) = higher::for_loop(expr);
if let Some(vec_args) = higher::vec_macro(cx, arg);
if is_copy(cx, vec_type(cx.tables.expr_ty_adjusted(arg)));
then {
// report the error around the `vec!` not inside `<std macros>:`
let span = arg.span.ctxt().outer().expn_info().map(|info| info.call_site).expect("unable to get call_site");
check_vec_macro(cx, &vec_args, span);
}}
}
}
}
}

View file

@ -31,17 +31,17 @@ impl LintPass for Pass {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
// check for instances of 0.0/0.0
if_let_chain! {[
let ExprBinary(ref op, ref left, ref right) = expr.node,
let BinOp_::BiDiv = op.node,
if_chain! {
if let ExprBinary(ref op, ref left, ref right) = expr.node;
if let BinOp_::BiDiv = op.node;
// TODO - constant_simple does not fold many operations involving floats.
// That's probably fine for this lint - it's pretty unlikely that someone would
// do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too.
let Some(Constant::Float(ref lhs_value, lhs_width)) = constant_simple(cx, left),
let Some(Constant::Float(ref rhs_value, rhs_width)) = constant_simple(cx, right),
Ok(0.0) == lhs_value.parse(),
Ok(0.0) == rhs_value.parse()
], {
if let Some(Constant::Float(ref lhs_value, lhs_width)) = constant_simple(cx, left);
if let Some(Constant::Float(ref rhs_value, rhs_width)) = constant_simple(cx, right);
if Ok(0.0) == lhs_value.parse();
if Ok(0.0) == rhs_value.parse();
then {
// since we're about to suggest a use of std::f32::NaN or std::f64::NaN,
// match the precision of the literals that are given.
let float_type = match (lhs_width, rhs_width) {
@ -52,6 +52,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
span_help_and_lint(cx, ZERO_DIVIDED_BY_ZERO, expr.span,
"constant division of 0.0 with 0.0 will always result in NaN",
&format!("Consider using `std::{}::NAN` if you would like a constant representing NaN", float_type));
}}
}
}
}
}