Use span_lint_and_sugg

This commit is contained in:
Seo Sanghyeon 2017-06-22 03:04:04 +09:00
parent 88101d5b78
commit 745233f3ab
12 changed files with 91 additions and 122 deletions

View File

@ -15,7 +15,7 @@
use rustc::lint::*;
use syntax::ast;
use utils::{in_macro, snippet_block, span_lint_and_then};
use utils::{in_macro, snippet_block, span_lint_and_then, span_lint_and_sugg};
use utils::sugg::Sugg;
/// **What it does:** Checks for nested `if` statements which can be collapsed
@ -108,12 +108,12 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext, else_: &ast::Expr) {
], {
match else_.node {
ast::ExprKind::If(..) | ast::ExprKind::IfLet(..) => {
span_lint_and_then(cx,
span_lint_and_sugg(cx,
COLLAPSIBLE_IF,
block.span,
"this `else { if .. }` block can be collapsed", |db| {
db.span_suggestion(block.span, "try", snippet_block(cx, else_.span, "..").into_owned());
});
"this `else { if .. }` block can be collapsed",
"try",
snippet_block(cx, else_.span, "..").into_owned());
}
_ => (),
}

View File

@ -4,7 +4,7 @@ use rustc::ty;
use rustc::hir::*;
use syntax::ast::{Lit, LitKind, Name};
use syntax::codemap::{Span, Spanned};
use utils::{get_item_name, in_macro, snippet, span_lint, span_lint_and_then, walk_ptrs_ty};
use utils::{get_item_name, in_macro, snippet, span_lint, span_lint_and_sugg, walk_ptrs_ty};
/// **What it does:** Checks for getting the length of something via `.len()`
/// just to compare to zero, and suggests using `.is_empty()` where applicable.
@ -171,11 +171,9 @@ fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str)
fn check_len_zero(cx: &LateContext, span: Span, name: Name, args: &[Expr], lit: &Lit, op: &str) {
if let Spanned { node: LitKind::Int(0, _), .. } = *lit {
if name == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) {
span_lint_and_then(cx, LEN_ZERO, span, "length comparison to zero", |db| {
db.span_suggestion(span,
"using `is_empty` is more concise:",
format!("{}{}.is_empty()", op, snippet(cx, args[0].span, "_")));
});
span_lint_and_sugg(cx, LEN_ZERO, span, "length comparison to zero",
"using `is_empty` is more concise:",
format!("{}{}.is_empty()", op, snippet(cx, args[0].span, "_")));
}
}
}

View File

@ -377,16 +377,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
// 1) it was ugly with big bodies;
// 2) it was not indented properly;
// 3) it wasnt very smart (see #675).
span_lint_and_then(cx,
span_lint_and_sugg(cx,
WHILE_LET_LOOP,
expr.span,
"this loop could be written as a `while let` loop",
|db| {
let sug = format!("while let {} = {} {{ .. }}",
snippet(cx, arms[0].pats[0].span, ".."),
snippet(cx, matchexpr.span, ".."));
db.span_suggestion(expr.span, "try", sug);
});
"try",
format!("while let {} = {} {{ .. }}",
snippet(cx, arms[0].pats[0].span, ".."),
snippet(cx, matchexpr.span, "..")));
}
},
_ => (),
@ -405,13 +403,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
!is_iterator_used_after_while_let(cx, iter_expr) {
let iterator = snippet(cx, method_args[0].span, "_");
let loop_var = snippet(cx, pat_args[0].span, "_");
span_lint_and_then(cx,
span_lint_and_sugg(cx,
WHILE_LET_ON_ITERATOR,
expr.span,
"this loop could be written as a `for` loop",
|db| {
db.span_suggestion(expr.span, "try", format!("for {} in {} {{ .. }}", loop_var, iterator));
});
"try",
format!("for {} in {} {{ .. }}", loop_var, iterator));
}
}
}

View File

@ -9,7 +9,7 @@ use std::collections::Bound;
use syntax::ast::LitKind;
use syntax::codemap::Span;
use utils::paths;
use utils::{match_type, snippet, span_note_and_lint, span_lint_and_then, in_external_macro, expr_block, walk_ptrs_ty,
use utils::{match_type, snippet, span_note_and_lint, span_lint_and_then, span_lint_and_sugg, in_external_macro, expr_block, walk_ptrs_ty,
is_expn_of, remove_blocks};
use utils::sugg::Sugg;
@ -210,20 +210,17 @@ fn report_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm],
SINGLE_MATCH
};
let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, "..")));
span_lint_and_then(cx,
span_lint_and_sugg(cx,
lint,
expr.span,
"you seem to be trying to use match for destructuring a single pattern. Consider using `if \
let`",
|db| {
db.span_suggestion(expr.span,
"try this",
format!("if let {} = {} {}{}",
snippet(cx, arms[0].pats[0].span, ".."),
snippet(cx, ex.span, ".."),
expr_block(cx, &arms[0].body, None, ".."),
els_str));
});
"try this",
format!("if let {} = {} {}{}",
snippet(cx, arms[0].pats[0].span, ".."),
snippet(cx, ex.span, ".."),
expr_block(cx, &arms[0].body, None, ".."),
els_str));
}
fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, ty: Ty, els: Option<&Expr>) {

View File

@ -8,7 +8,7 @@ use std::borrow::Cow;
use std::fmt;
use syntax::codemap::Span;
use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, is_copy, match_path, match_trait_method,
match_type, method_chain_args, return_ty, same_tys, snippet, span_lint, span_lint_and_then,
match_type, method_chain_args, return_ty, same_tys, snippet, span_lint, span_lint_and_then, span_lint_and_sugg,
span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, last_path_segment, single_segment_path,
match_def_path, is_self, is_self_ty, iter_input_pats, match_path_old};
use utils::paths;
@ -725,15 +725,12 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir:
};
if implements_trait(cx, arg_ty, default_trait_id, &[]) {
span_lint_and_then(cx,
span_lint_and_sugg(cx,
OR_FUN_CALL,
span,
&format!("use of `{}` followed by a call to `{}`", name, path),
|db| {
db.span_suggestion(span,
"try this",
format!("{}.unwrap_or_default()", snippet(cx, self_expr.span, "_")));
});
"try this",
format!("{}.unwrap_or_default()", snippet(cx, self_expr.span, "_")));
return true;
}
}
@ -791,15 +788,12 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir:
(false, true) => snippet(cx, fun_span, ".."),
};
span_lint_and_then(cx,
span_lint_and_sugg(cx,
OR_FUN_CALL,
span,
&format!("use of `{}` followed by a function call", name),
|db| {
db.span_suggestion(span,
"try this",
format!("{}.{}_{}({})", snippet(cx, self_expr.span, "_"), name, suffix, sugg));
});
"try this",
format!("{}.{}_{}({})", snippet(cx, self_expr.span, "_"), name, suffix, sugg));
}
if args.len() == 2 {
@ -865,14 +859,12 @@ fn lint_string_extend(cx: &LateContext, expr: &hir::Expr, args: &[hir::Expr]) {
return;
};
span_lint_and_then(cx, STRING_EXTEND_CHARS, expr.span, "calling `.extend(_.chars())`", |db| {
db.span_suggestion(expr.span,
"try this",
format!("{}.push_str({}{})",
snippet(cx, args[0].span, "_"),
ref_str,
snippet(cx, target.span, "_")));
});
span_lint_and_sugg(cx, STRING_EXTEND_CHARS, expr.span, "calling `.extend(_.chars())`",
"try this",
format!("{}.push_str({}{})",
snippet(cx, args[0].span, "_"),
ref_str,
snippet(cx, target.span, "_")));
}
}
@ -951,20 +943,17 @@ fn lint_get_unwrap(cx: &LateContext, expr: &hir::Expr, get_args: &[hir::Expr], i
let mut_str = if is_mut { "_mut" } else { "" };
let borrow_str = if is_mut { "&mut " } else { "&" };
span_lint_and_then(cx,
span_lint_and_sugg(cx,
GET_UNWRAP,
expr.span,
&format!("called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise",
mut_str,
caller_type),
|db| {
db.span_suggestion(expr.span,
"try this",
format!("{}{}[{}]",
borrow_str,
snippet(cx, get_args[0].span, "_"),
snippet(cx, get_args[1].span, "_")));
});
"try this",
format!("{}{}[{}]",
borrow_str,
snippet(cx, get_args[0].span, "_"),
snippet(cx, get_args[1].span, "_")));
}
fn lint_iter_skip_next(cx: &LateContext, expr: &hir::Expr) {
@ -1216,19 +1205,15 @@ fn lint_chars_next(cx: &LateContext, expr: &hir::Expr, chain: &hir::Expr, other:
return false;
}
span_lint_and_then(cx,
span_lint_and_sugg(cx,
CHARS_NEXT_CMP,
expr.span,
"you should use the `starts_with` method",
|db| {
let sugg = format!("{}{}.starts_with({})",
if eq { "" } else { "!" },
snippet(cx, args[0][0].span, "_"),
snippet(cx, arg_char[0].span, "_")
);
db.span_suggestion(expr.span, "like this", sugg);
});
"like this",
format!("{}{}.starts_with({})",
if eq { "" } else { "!" },
snippet(cx, args[0][0].span, "_"),
snippet(cx, arg_char[0].span, "_")));
return true;
}}

View File

@ -6,7 +6,7 @@ use rustc::lint::*;
use rustc::hir::*;
use syntax::ast::LitKind;
use syntax::codemap::Spanned;
use utils::{span_lint, span_lint_and_then, snippet};
use utils::{span_lint, span_lint_and_sugg, snippet};
use utils::sugg::Sugg;
/// **What it does:** Checks for expressions of the form `if c { true } else { false }`
@ -70,11 +70,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool {
snip.to_string()
};
span_lint_and_then(cx,
span_lint_and_sugg(cx,
NEEDLESS_BOOL,
e.span,
"this if-then-else expression returns a bool literal",
|db| { db.span_suggestion(e.span, "you can reduce it to", hint); });
"you can reduce it to",
hint);
};
if let ExprBlock(ref then_block) = then_block.node {
match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) {
@ -121,39 +122,39 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison {
match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
(Bool(true), Other) => {
let hint = snippet(cx, right_side.span, "..").into_owned();
span_lint_and_then(cx,
span_lint_and_sugg(cx,
BOOL_COMPARISON,
e.span,
"equality checks against true are unnecessary",
|db| { db.span_suggestion(e.span, "try simplifying it as shown:", hint); });
"try simplifying it as shown:",
hint);
},
(Other, Bool(true)) => {
let hint = snippet(cx, left_side.span, "..").into_owned();
span_lint_and_then(cx,
span_lint_and_sugg(cx,
BOOL_COMPARISON,
e.span,
"equality checks against true are unnecessary",
|db| { db.span_suggestion(e.span, "try simplifying it as shown:", hint); });
"try simplifying it as shown:",
hint);
},
(Bool(false), Other) => {
let hint = Sugg::hir(cx, right_side, "..");
span_lint_and_then(cx,
span_lint_and_sugg(cx,
BOOL_COMPARISON,
e.span,
"equality checks against false can be replaced by a negation",
|db| {
db.span_suggestion(e.span, "try simplifying it as shown:", (!hint).to_string());
});
"try simplifying it as shown:",
(!hint).to_string());
},
(Other, Bool(false)) => {
let hint = Sugg::hir(cx, left_side, "..");
span_lint_and_then(cx,
span_lint_and_sugg(cx,
BOOL_COMPARISON,
e.span,
"equality checks against false can be replaced by a negation",
|db| {
db.span_suggestion(e.span, "try simplifying it as shown:", (!hint).to_string());
});
"try simplifying it as shown:",
(!hint).to_string());
},
_ => (),
}

View File

@ -1,7 +1,7 @@
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::hir::def::Def;
use rustc::hir::{Expr, Expr_, Stmt, StmtSemi, BlockCheckMode, UnsafeSource, BiAnd, BiOr};
use utils::{in_macro, span_lint, snippet_opt, span_lint_and_then};
use utils::{in_macro, span_lint, snippet_opt, span_lint_and_sugg};
use std::ops::Deref;
/// **What it does:** Checks for statements which have no effect.
@ -120,11 +120,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
return;
}
}
span_lint_and_then(cx,
span_lint_and_sugg(cx,
UNNECESSARY_OPERATION,
stmt.span,
"statement can be reduced",
|db| { db.span_suggestion(stmt.span, "replace it with", snippet); });
"replace it with",
snippet);
}
}
}

View File

@ -1,7 +1,7 @@
use rustc::lint::*;
use syntax::ast::*;
use syntax::codemap::Spanned;
use utils::{span_lint_and_then, snippet};
use utils::{span_lint_and_sugg, snippet};
/// **What it does:** Checks for operations where precedence may be unclear
/// and suggests to add parentheses. Currently it catches the following:
@ -38,9 +38,8 @@ impl EarlyLintPass for Precedence {
if let ExprKind::Binary(Spanned { node: op, .. }, ref left, ref right) = expr.node {
let span_sugg =
|expr: &Expr, sugg| {
span_lint_and_then(cx, PRECEDENCE, expr.span, "operator precedence can trip the unwary", |db| {
db.span_suggestion(expr.span, "consider parenthesizing your expression", sugg);
});
span_lint_and_sugg(cx, PRECEDENCE, expr.span, "operator precedence can trip the unwary",
"consider parenthesizing your expression", sugg);
};
if !is_bit_op(op) {
@ -80,15 +79,12 @@ impl EarlyLintPass for Precedence {
LitKind::Int(..) |
LitKind::Float(..) |
LitKind::FloatUnsuffixed(..) => {
span_lint_and_then(cx,
span_lint_and_sugg(cx,
PRECEDENCE,
expr.span,
"unary minus has lower precedence than method call",
|db| {
db.span_suggestion(expr.span,
"consider adding parentheses to clarify your intent",
format!("-({})", snippet(cx, rhs.span, "..")));
});
"consider adding parentheses to clarify your intent",
format!("-({})", snippet(cx, rhs.span, "..")));
},
_ => (),
}

View File

@ -1,6 +1,6 @@
use syntax::ast::{Expr, ExprKind, UnOp};
use rustc::lint::*;
use utils::{span_lint_and_then, snippet};
use utils::{span_lint_and_sugg, snippet};
/// **What it does:** Checks for usage of `*&` and `*&mut` in expressions.
///
@ -40,9 +40,8 @@ impl EarlyLintPass for Pass {
fn check_expr(&mut self, cx: &EarlyContext, e: &Expr) {
if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.node {
if let ExprKind::AddrOf(_, ref addrof_target) = without_parens(deref_target).node {
span_lint_and_then(cx, DEREF_ADDROF, e.span, "immediately dereferencing a reference", |db| {
db.span_suggestion(e.span, "try this", format!("{}", snippet(cx, addrof_target.span, "_")));
});
span_lint_and_sugg(cx, DEREF_ADDROF, e.span, "immediately dereferencing a reference",
"try this", format!("{}", snippet(cx, addrof_target.span, "_")));
}
}
}

View File

@ -2,7 +2,7 @@ use rustc::hir::*;
use rustc::lint::*;
use syntax::codemap::Spanned;
use utils::SpanlessEq;
use utils::{match_type, paths, span_lint, span_lint_and_then, walk_ptrs_ty, get_parent_expr};
use utils::{match_type, paths, span_lint, span_lint_and_sugg, walk_ptrs_ty, get_parent_expr};
/// **What it does:** Checks for string appends of the form `x = x + y` (without
/// `let`!).
@ -147,15 +147,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes {
if let ExprLit(ref lit) = args[0].node {
if let LitKind::Str(ref lit_content, _) = lit.node {
if lit_content.as_str().chars().all(|c| c.is_ascii()) && !in_macro(args[0].span) {
span_lint_and_then(cx,
span_lint_and_sugg(cx,
STRING_LIT_AS_BYTES,
e.span,
"calling `as_bytes()` on a string literal",
|db| {
let sugg = format!("b{}", snippet(cx, args[0].span, r#""foo""#));
db.span_suggestion(e.span, "consider using a byte string literal instead", sugg);
});
"consider using a byte string literal instead",
format!("b{}", snippet(cx, args[0].span, r#""foo""#)));
}
}
}

View File

@ -8,7 +8,7 @@ use std::cmp::Ordering;
use syntax::ast::{IntTy, UintTy, FloatTy};
use syntax::attr::IntType;
use syntax::codemap::Span;
use utils::{comparisons, higher, in_external_macro, in_macro, match_def_path, snippet, span_help_and_lint, span_lint, span_lint_and_then,
use utils::{comparisons, higher, in_external_macro, in_macro, match_def_path, snippet, span_help_and_lint, span_lint, span_lint_and_sugg,
opt_def_id, last_path_segment, type_size};
use utils::paths;
@ -210,15 +210,12 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) {
} else {
""
};
span_lint_and_then(cx,
span_lint_and_sugg(cx,
BORROWED_BOX,
ast_ty.span,
"you seem to be trying to use `&Box<T>`. Consider using just `&T`",
|db| {
db.span_suggestion(ast_ty.span,
"try",
format!("&{}{}{}", ltopt, mutopt, &snippet(cx, inner.span, "..")));
}
"try",
format!("&{}{}{}", ltopt, mutopt, &snippet(cx, inner.span, ".."))
);
return; // don't recurse into the type
}};

View File

@ -3,7 +3,7 @@ use rustc::lint::*;
use rustc::ty::{self, Ty};
use rustc_const_eval::ConstContext;
use syntax::codemap::Span;
use utils::{higher, is_copy, snippet, span_lint_and_then};
use utils::{higher, is_copy, snippet, span_lint_and_sugg};
/// **What it does:** Checks for usage of `&vec![..]` when using `&[..]` would
/// be possible.
@ -80,11 +80,12 @@ fn check_vec_macro(cx: &LateContext, vec_args: &higher::VecArgs, span: Span) {
},
};
span_lint_and_then(cx,
span_lint_and_sugg(cx,
USELESS_VEC,
span,
"useless use of `vec!`",
|db| { db.span_suggestion(span, "you can use a slice directly", snippet); });
"you can use a slice directly",
snippet);
}
/// Return the item type of the vector (ie. the `T` in `Vec<T>`).