2015-05-15 18:46:43 +02:00
|
|
|
use rustc::plugin::Registry;
|
|
|
|
use rustc::lint::*;
|
|
|
|
use rustc::middle::const_eval::lookup_const_by_id;
|
|
|
|
use rustc::middle::def::*;
|
|
|
|
use syntax::ast::*;
|
|
|
|
use syntax::ast_util::{is_comparison_binop, binop_to_string};
|
|
|
|
use syntax::ptr::P;
|
|
|
|
use syntax::codemap::Span;
|
|
|
|
|
2015-07-26 16:53:11 +02:00
|
|
|
use utils::{span_lint, snippet};
|
2015-07-09 17:02:21 +02:00
|
|
|
|
2015-05-15 18:46:43 +02:00
|
|
|
declare_lint! { pub IDENTITY_OP, Warn,
|
|
|
|
"Warn on identity operations, e.g. '_ + 0'"}
|
|
|
|
|
|
|
|
#[derive(Copy,Clone)]
|
|
|
|
pub struct IdentityOp;
|
|
|
|
|
|
|
|
impl LintPass for IdentityOp {
|
|
|
|
fn get_lints(&self) -> LintArray {
|
|
|
|
lint_array!(IDENTITY_OP)
|
|
|
|
}
|
2015-05-23 00:49:13 +02:00
|
|
|
|
2015-05-15 18:46:43 +02:00
|
|
|
fn check_expr(&mut self, cx: &Context, e: &Expr) {
|
2015-05-23 00:49:13 +02:00
|
|
|
if let ExprBinary(ref cmp, ref left, ref right) = e.node {
|
|
|
|
match cmp.node {
|
|
|
|
BiAdd | BiBitOr | BiBitXor => {
|
|
|
|
check(cx, left, 0, e.span, right.span);
|
|
|
|
check(cx, right, 0, e.span, left.span);
|
|
|
|
},
|
|
|
|
BiShl | BiShr | BiSub =>
|
|
|
|
check(cx, right, 0, e.span, left.span),
|
|
|
|
BiMul => {
|
|
|
|
check(cx, left, 1, e.span, right.span);
|
|
|
|
check(cx, right, 1, e.span, left.span);
|
|
|
|
},
|
|
|
|
BiDiv =>
|
|
|
|
check(cx, right, 1, e.span, left.span),
|
|
|
|
BiBitAnd => {
|
|
|
|
check(cx, left, -1, e.span, right.span);
|
|
|
|
check(cx, right, -1, e.span, left.span);
|
|
|
|
},
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
}
|
2015-05-15 18:46:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) {
|
2015-05-23 00:49:13 +02:00
|
|
|
if have_lit(cx, e, m) {
|
2015-07-26 16:53:11 +02:00
|
|
|
span_lint(cx, IDENTITY_OP, span, &format!(
|
2015-05-23 00:49:13 +02:00
|
|
|
"The operation is ineffective. Consider reducing it to '{}'",
|
2015-07-09 17:02:21 +02:00
|
|
|
snippet(cx, arg, "..")));
|
2015-05-23 00:49:13 +02:00
|
|
|
}
|
2015-05-15 18:46:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn have_lit(cx: &Context, e : &Expr, m: i8) -> bool {
|
2015-05-23 00:49:13 +02:00
|
|
|
match &e.node {
|
|
|
|
&ExprUnary(UnNeg, ref litexp) => have_lit(cx, litexp, -m),
|
|
|
|
&ExprLit(ref lit) => {
|
|
|
|
match (&lit.node, m) {
|
|
|
|
(&LitInt(0, _), 0) => true,
|
|
|
|
(&LitInt(1, SignedIntLit(_, Plus)), 1) => true,
|
|
|
|
(&LitInt(1, UnsuffixedIntLit(Plus)), 1) => true,
|
|
|
|
(&LitInt(1, SignedIntLit(_, Minus)), -1) => true,
|
|
|
|
(&LitInt(1, UnsuffixedIntLit(Minus)), -1) => true,
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
},
|
|
|
|
&ExprParen(ref p) => have_lit(cx, p, m),
|
|
|
|
&ExprPath(_, _) => {
|
|
|
|
match cx.tcx.def_map.borrow().get(&e.id) {
|
|
|
|
Some(&PathResolution { base_def: DefConst(id), ..}) =>
|
|
|
|
lookup_const_by_id(cx.tcx, id, Option::None)
|
|
|
|
.map_or(false, |l| have_lit(cx, l, m)),
|
|
|
|
_ => false
|
2015-05-15 18:46:43 +02:00
|
|
|
}
|
2015-05-23 00:49:13 +02:00
|
|
|
},
|
|
|
|
_ => false
|
|
|
|
}
|
2015-05-15 18:46:43 +02:00
|
|
|
}
|