Use span_suggestion in the precedence lint

This commit is contained in:
mcarton 2017-01-22 14:51:13 +01:00
parent 276ad246f1
commit b784f0d736
No known key found for this signature in database
GPG Key ID: 5E427C794CBA45E8
2 changed files with 54 additions and 35 deletions

View File

@ -1,7 +1,7 @@
use rustc::lint::*; use rustc::lint::*;
use syntax::ast::*; use syntax::ast::*;
use syntax::codemap::Spanned; use syntax::codemap::Spanned;
use utils::{span_lint, snippet}; use utils::{span_lint_and_then, snippet};
/// **What it does:** Checks for operations where precedence may be unclear /// **What it does:** Checks for operations where precedence may be unclear
/// and suggests to add parentheses. Currently it catches the following: /// and suggests to add parentheses. Currently it catches the following:
@ -36,41 +36,39 @@ impl LintPass for Precedence {
impl EarlyLintPass for Precedence { impl EarlyLintPass for Precedence {
fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
if let ExprKind::Binary(Spanned { node: op, .. }, ref left, ref right) = expr.node { 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);
});
};
if !is_bit_op(op) { if !is_bit_op(op) {
return; return;
} }
match (is_arith_expr(left), is_arith_expr(right)) { match (is_arith_expr(left), is_arith_expr(right)) {
(true, true) => { (true, true) => {
span_lint(cx, let sugg = format!("({}) {} ({})",
PRECEDENCE,
expr.span,
&format!("operator precedence can trip the unwary. Consider parenthesizing your \
expression:`({}) {} ({})`",
snippet(cx, left.span, ".."), snippet(cx, left.span, ".."),
op.to_string(), op.to_string(),
snippet(cx, right.span, ".."))); snippet(cx, right.span, ".."));
span_sugg(expr, sugg);
}, },
(true, false) => { (true, false) => {
span_lint(cx, let sugg = format!("({}) {} {}",
PRECEDENCE,
expr.span,
&format!("operator precedence can trip the unwary. Consider parenthesizing your \
expression:`({}) {} {}`",
snippet(cx, left.span, ".."), snippet(cx, left.span, ".."),
op.to_string(), op.to_string(),
snippet(cx, right.span, ".."))); snippet(cx, right.span, ".."));
span_sugg(expr, sugg);
}, },
(false, true) => { (false, true) => {
span_lint(cx, let sugg = format!("{} {} ({})",
PRECEDENCE,
expr.span,
&format!("operator precedence can trip the unwary. Consider parenthesizing your \
expression:`{} {} ({})`",
snippet(cx, left.span, ".."), snippet(cx, left.span, ".."),
op.to_string(), op.to_string(),
snippet(cx, right.span, ".."))); snippet(cx, right.span, ".."));
span_sugg(expr, sugg);
}, },
_ => (), (false, false) => (),
} }
} }
@ -82,12 +80,15 @@ impl EarlyLintPass for Precedence {
LitKind::Int(..) | LitKind::Int(..) |
LitKind::Float(..) | LitKind::Float(..) |
LitKind::FloatUnsuffixed(..) => { LitKind::FloatUnsuffixed(..) => {
span_lint(cx, span_lint_and_then(cx,
PRECEDENCE, PRECEDENCE,
expr.span, expr.span,
&format!("unary minus has lower precedence than method call. Consider \ "unary minus has lower precedence than method call",
adding parentheses to clarify your intent: -({})", |db| {
snippet(cx, rhs.span, ".."))); db.span_suggestion(expr.span,
"consider adding parentheses to clarify your intent",
format!("-({})", snippet(cx, rhs.span, "..")));
});
}, },
_ => (), _ => (),
} }

View File

@ -5,16 +5,34 @@
#[allow(identity_op)] #[allow(identity_op)]
#[allow(eq_op)] #[allow(eq_op)]
fn main() { fn main() {
format!("{} vs. {}", 1 << 2 + 3, (1 << 2) + 3); //~ERROR operator precedence can trip 1 << 2 + 3;
format!("{} vs. {}", 1 + 2 << 3, 1 + (2 << 3)); //~ERROR operator precedence can trip //~^ ERROR operator precedence can trip
format!("{} vs. {}", 4 >> 1 + 1, (4 >> 1) + 1); //~ERROR operator precedence can trip //~| SUGGESTION 1 << (2 + 3)
format!("{} vs. {}", 1 + 3 >> 2, 1 + (3 >> 2)); //~ERROR operator precedence can trip 1 + 2 << 3;
format!("{} vs. {}", 1 ^ 1 - 1, (1 ^ 1) - 1); //~ERROR operator precedence can trip //~^ERROR operator precedence can trip
format!("{} vs. {}", 3 | 2 - 1, (3 | 2) - 1); //~ERROR operator precedence can trip //~| SUGGESTION (1 + 2) << 3
format!("{} vs. {}", 3 & 5 - 2, (3 & 5) - 2); //~ERROR operator precedence can trip 4 >> 1 + 1;
//~^ERROR operator precedence can trip
//~| SUGGESTION 4 >> (1 + 1)
1 + 3 >> 2;
//~^ERROR operator precedence can trip
//~| SUGGESTION (1 + 3) >> 2
1 ^ 1 - 1;
//~^ERROR operator precedence can trip
//~| SUGGESTION 1 ^ (1 - 1)
3 | 2 - 1;
//~^ERROR operator precedence can trip
//~| SUGGESTION 3 | (2 - 1)
3 & 5 - 2;
//~^ERROR operator precedence can trip
//~| SUGGESTION 3 & (5 - 2)
format!("{} vs. {}", -1i32.abs(), (-1i32).abs()); //~ERROR unary minus has lower precedence -1i32.abs();
format!("{} vs. {}", -1f32.abs(), (-1f32).abs()); //~ERROR unary minus has lower precedence //~^ERROR unary minus has lower precedence
//~| SUGGESTION -(1i32.abs())
-1f32.abs();
//~^ERROR unary minus has lower precedence
//~| SUGGESTION -(1f32.abs())
// These should not trigger an error // These should not trigger an error
let _ = (-1i32).abs(); let _ = (-1i32).abs();