all: whitespace cleanup
* 4-space indentation * no trailing whitespace * no tabs
This commit is contained in:
parent
2cb26126d3
commit
e318328d63
@ -87,7 +87,7 @@ You can add options to `allow`/`warn`/`deny`:
|
||||
|
||||
*`deny` produces error instead of warnings*
|
||||
|
||||
To have cargo compile your crate with clippy without needing `#![plugin(clippy)]`
|
||||
To have cargo compile your crate with clippy without needing `#![plugin(clippy)]`
|
||||
in your code, you can use:
|
||||
|
||||
```
|
||||
|
@ -15,12 +15,12 @@ declare_lint! {
|
||||
"Warn if a user writes an approximate known constant in their code"
|
||||
}
|
||||
|
||||
const KNOWN_CONSTS : &'static [(f64, &'static str)] = &[(f64::E, "E"), (f64::FRAC_1_PI, "FRAC_1_PI"),
|
||||
(f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2"), (f64::FRAC_2_PI, "FRAC_2_PI"),
|
||||
(f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI"), (f64::FRAC_PI_2, "FRAC_PI_2"), (f64::FRAC_PI_3, "FRAC_PI_3"),
|
||||
(f64::FRAC_PI_4, "FRAC_PI_4"), (f64::FRAC_PI_6, "FRAC_PI_6"), (f64::FRAC_PI_8, "FRAC_PI_8"),
|
||||
(f64::LN_10, "LN_10"), (f64::LN_2, "LN_2"), (f64::LOG10_E, "LOG10_E"), (f64::LOG2_E, "LOG2_E"),
|
||||
(f64::PI, "PI"), (f64::SQRT_2, "SQRT_2")];
|
||||
const KNOWN_CONSTS : &'static [(f64, &'static str)] = &[(f64::E, "E"), (f64::FRAC_1_PI, "FRAC_1_PI"),
|
||||
(f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2"), (f64::FRAC_2_PI, "FRAC_2_PI"),
|
||||
(f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI"), (f64::FRAC_PI_2, "FRAC_PI_2"), (f64::FRAC_PI_3, "FRAC_PI_3"),
|
||||
(f64::FRAC_PI_4, "FRAC_PI_4"), (f64::FRAC_PI_6, "FRAC_PI_6"), (f64::FRAC_PI_8, "FRAC_PI_8"),
|
||||
(f64::LN_10, "LN_10"), (f64::LN_2, "LN_2"), (f64::LOG10_E, "LOG10_E"), (f64::LOG2_E, "LOG2_E"),
|
||||
(f64::PI, "PI"), (f64::SQRT_2, "SQRT_2")];
|
||||
|
||||
const EPSILON_DIVISOR : f64 = 8192f64; //TODO: test to find a good value
|
||||
|
||||
@ -31,34 +31,34 @@ impl LintPass for ApproxConstant {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(APPROX_CONSTANT)
|
||||
}
|
||||
|
||||
|
||||
fn check_expr(&mut self, cx: &Context, e: &Expr) {
|
||||
if let &ExprLit(ref lit) = &e.node {
|
||||
check_lit(cx, lit, e.span);
|
||||
}
|
||||
if let &ExprLit(ref lit) = &e.node {
|
||||
check_lit(cx, lit, e.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_lit(cx: &Context, lit: &Lit, span: Span) {
|
||||
match &lit.node {
|
||||
&LitFloat(ref str, TyF32) => check_known_consts(cx, span, str, "f32"),
|
||||
&LitFloat(ref str, TyF64) => check_known_consts(cx, span, str, "f64"),
|
||||
&LitFloatUnsuffixed(ref str) => check_known_consts(cx, span, str, "f{32, 64}"),
|
||||
_ => ()
|
||||
}
|
||||
match &lit.node {
|
||||
&LitFloat(ref str, TyF32) => check_known_consts(cx, span, str, "f32"),
|
||||
&LitFloat(ref str, TyF64) => check_known_consts(cx, span, str, "f64"),
|
||||
&LitFloatUnsuffixed(ref str) => check_known_consts(cx, span, str, "f{32, 64}"),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
fn check_known_consts(cx: &Context, span: Span, str: &str, module: &str) {
|
||||
if let Ok(value) = str.parse::<f64>() {
|
||||
for &(constant, name) in KNOWN_CONSTS {
|
||||
if within_epsilon(constant, value) {
|
||||
span_lint(cx, APPROX_CONSTANT, span, &format!(
|
||||
"Approximate value of {}::{} found, consider using it directly.", module, &name));
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Ok(value) = str.parse::<f64>() {
|
||||
for &(constant, name) in KNOWN_CONSTS {
|
||||
if within_epsilon(constant, value) {
|
||||
span_lint(cx, APPROX_CONSTANT, span, &format!(
|
||||
"Approximate value of {}::{} found, consider using it directly.", module, &name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn within_epsilon(target: f64, value: f64) -> bool {
|
||||
f64::abs(value - target) < f64::abs((if target > value { target } else { value })) / EPSILON_DIVISOR
|
||||
f64::abs(value - target) < f64::abs((if target > value { target } else { value })) / EPSILON_DIVISOR
|
||||
}
|
||||
|
138
src/attrs.rs
138
src/attrs.rs
@ -19,92 +19,92 @@ impl LintPass for AttrPass {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(INLINE_ALWAYS)
|
||||
}
|
||||
|
||||
|
||||
fn check_item(&mut self, cx: &Context, item: &Item) {
|
||||
if is_relevant_item(item) {
|
||||
cx.sess().codemap().with_expn_info(item.span.expn_id,
|
||||
|info| check_attrs(cx, info, &item.ident, &item.attrs))
|
||||
}
|
||||
}
|
||||
|
||||
if is_relevant_item(item) {
|
||||
cx.sess().codemap().with_expn_info(item.span.expn_id,
|
||||
|info| check_attrs(cx, info, &item.ident, &item.attrs))
|
||||
}
|
||||
}
|
||||
|
||||
fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) {
|
||||
if is_relevant_impl(item) {
|
||||
cx.sess().codemap().with_expn_info(item.span.expn_id,
|
||||
|info| check_attrs(cx, info, &item.ident, &item.attrs))
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) {
|
||||
if is_relevant_trait(item) {
|
||||
cx.sess().codemap().with_expn_info(item.span.expn_id,
|
||||
|info| check_attrs(cx, info, &item.ident, &item.attrs))
|
||||
}
|
||||
}
|
||||
if is_relevant_impl(item) {
|
||||
cx.sess().codemap().with_expn_info(item.span.expn_id,
|
||||
|info| check_attrs(cx, info, &item.ident, &item.attrs))
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) {
|
||||
if is_relevant_trait(item) {
|
||||
cx.sess().codemap().with_expn_info(item.span.expn_id,
|
||||
|info| check_attrs(cx, info, &item.ident, &item.attrs))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_relevant_item(item: &Item) -> bool {
|
||||
if let &ItemFn(_, _, _, _, _, ref block) = &item.node {
|
||||
is_relevant_block(block)
|
||||
} else { false }
|
||||
if let &ItemFn(_, _, _, _, _, ref block) = &item.node {
|
||||
is_relevant_block(block)
|
||||
} else { false }
|
||||
}
|
||||
|
||||
fn is_relevant_impl(item: &ImplItem) -> bool {
|
||||
match item.node {
|
||||
MethodImplItem(_, ref block) => is_relevant_block(block),
|
||||
_ => false
|
||||
}
|
||||
match item.node {
|
||||
MethodImplItem(_, ref block) => is_relevant_block(block),
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
fn is_relevant_trait(item: &TraitItem) -> bool {
|
||||
match item.node {
|
||||
MethodTraitItem(_, None) => true,
|
||||
MethodTraitItem(_, Some(ref block)) => is_relevant_block(block),
|
||||
_ => false
|
||||
}
|
||||
match item.node {
|
||||
MethodTraitItem(_, None) => true,
|
||||
MethodTraitItem(_, Some(ref block)) => is_relevant_block(block),
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
fn is_relevant_block(block: &Block) -> bool {
|
||||
for stmt in block.stmts.iter() {
|
||||
match stmt.node {
|
||||
StmtDecl(_, _) => return true,
|
||||
StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => {
|
||||
return is_relevant_expr(expr);
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
block.expr.as_ref().map_or(false, |e| is_relevant_expr(&*e))
|
||||
for stmt in block.stmts.iter() {
|
||||
match stmt.node {
|
||||
StmtDecl(_, _) => return true,
|
||||
StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => {
|
||||
return is_relevant_expr(expr);
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
block.expr.as_ref().map_or(false, |e| is_relevant_expr(&*e))
|
||||
}
|
||||
|
||||
fn is_relevant_expr(expr: &Expr) -> bool {
|
||||
match expr.node {
|
||||
ExprBlock(ref block) => is_relevant_block(block),
|
||||
ExprRet(Some(ref e)) | ExprParen(ref e) =>
|
||||
is_relevant_expr(&*e),
|
||||
ExprRet(None) | ExprBreak(_) | ExprMac(_) => false,
|
||||
ExprCall(ref path_expr, _) => {
|
||||
if let ExprPath(_, ref path) = path_expr.node {
|
||||
!match_path(path, &["std", "rt", "begin_unwind"])
|
||||
} else { true }
|
||||
}
|
||||
_ => true
|
||||
}
|
||||
match expr.node {
|
||||
ExprBlock(ref block) => is_relevant_block(block),
|
||||
ExprRet(Some(ref e)) | ExprParen(ref e) =>
|
||||
is_relevant_expr(&*e),
|
||||
ExprRet(None) | ExprBreak(_) | ExprMac(_) => false,
|
||||
ExprCall(ref path_expr, _) => {
|
||||
if let ExprPath(_, ref path) = path_expr.node {
|
||||
!match_path(path, &["std", "rt", "begin_unwind"])
|
||||
} else { true }
|
||||
}
|
||||
_ => true
|
||||
}
|
||||
}
|
||||
|
||||
fn check_attrs(cx: &Context, info: Option<&ExpnInfo>, ident: &Ident,
|
||||
attrs: &[Attribute]) {
|
||||
if in_macro(cx, info) { return; }
|
||||
|
||||
for attr in attrs {
|
||||
if let MetaList(ref inline, ref values) = attr.node.value.node {
|
||||
if values.len() != 1 || inline != &"inline" { continue; }
|
||||
if let MetaWord(ref always) = values[0].node {
|
||||
if always != &"always" { continue; }
|
||||
span_lint(cx, INLINE_ALWAYS, attr.span, &format!(
|
||||
"You have declared #[inline(always)] on {}. This \
|
||||
is usually a bad idea. Are you sure?",
|
||||
ident.name.as_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
fn check_attrs(cx: &Context, info: Option<&ExpnInfo>, ident: &Ident,
|
||||
attrs: &[Attribute]) {
|
||||
if in_macro(cx, info) { return; }
|
||||
|
||||
for attr in attrs {
|
||||
if let MetaList(ref inline, ref values) = attr.node.value.node {
|
||||
if values.len() != 1 || inline != &"inline" { continue; }
|
||||
if let MetaWord(ref always) = values[0].node {
|
||||
if always != &"always" { continue; }
|
||||
span_lint(cx, INLINE_ALWAYS, attr.span, &format!(
|
||||
"You have declared #[inline(always)] on {}. This \
|
||||
is usually a bad idea. Are you sure?",
|
||||
ident.name.as_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
260
src/bit_mask.rs
260
src/bit_mask.rs
@ -12,23 +12,23 @@ declare_lint! {
|
||||
pub BAD_BIT_MASK,
|
||||
Deny,
|
||||
"Deny the use of incompatible bit masks in comparisons, e.g. \
|
||||
'(a & 1) == 2'"
|
||||
'(a & 1) == 2'"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub INEFFECTIVE_BIT_MASK,
|
||||
Warn,
|
||||
"Warn on the use of an ineffective bit mask in comparisons, e.g. \
|
||||
'(a & 1) > 2'"
|
||||
pub INEFFECTIVE_BIT_MASK,
|
||||
Warn,
|
||||
"Warn on the use of an ineffective bit mask in comparisons, e.g. \
|
||||
'(a & 1) > 2'"
|
||||
}
|
||||
|
||||
/// Checks for incompatible bit masks in comparisons, e.g. `x & 1 == 2`.
|
||||
/// Checks for incompatible bit masks in comparisons, e.g. `x & 1 == 2`.
|
||||
/// This cannot work because the bit that makes up the value two was
|
||||
/// zeroed out by the bit-and with 1. So the formula for detecting if an
|
||||
/// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
|
||||
/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
|
||||
/// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
|
||||
/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
|
||||
/// `!=`, `>=`, `>`}) can be determined from the following table:
|
||||
///
|
||||
///
|
||||
/// |Comparison |Bit-Op|Example |is always|Formula |
|
||||
/// |------------|------|------------|---------|----------------------|
|
||||
/// |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` |
|
||||
@ -37,7 +37,7 @@ declare_lint! {
|
||||
/// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` |
|
||||
/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` |
|
||||
/// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` |
|
||||
///
|
||||
///
|
||||
/// This lint is **deny** by default
|
||||
///
|
||||
/// There is also a lint that warns on ineffective masks that is *warn*
|
||||
@ -49,140 +49,140 @@ impl LintPass for BitMask {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(BAD_BIT_MASK, INEFFECTIVE_BIT_MASK)
|
||||
}
|
||||
|
||||
|
||||
fn check_expr(&mut self, cx: &Context, e: &Expr) {
|
||||
if let ExprBinary(ref cmp, ref left, ref right) = e.node {
|
||||
if is_comparison_binop(cmp.node) {
|
||||
fetch_int_literal(cx, right).map_or_else(||
|
||||
fetch_int_literal(cx, left).map_or((), |cmp_val|
|
||||
check_compare(cx, right, invert_cmp(cmp.node),
|
||||
cmp_val, &e.span)),
|
||||
|cmp_opt| check_compare(cx, left, cmp.node, cmp_opt,
|
||||
&e.span))
|
||||
}
|
||||
}
|
||||
if is_comparison_binop(cmp.node) {
|
||||
fetch_int_literal(cx, right).map_or_else(||
|
||||
fetch_int_literal(cx, left).map_or((), |cmp_val|
|
||||
check_compare(cx, right, invert_cmp(cmp.node),
|
||||
cmp_val, &e.span)),
|
||||
|cmp_opt| check_compare(cx, left, cmp.node, cmp_opt,
|
||||
&e.span))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn invert_cmp(cmp : BinOp_) -> BinOp_ {
|
||||
match cmp {
|
||||
BiEq => BiEq,
|
||||
BiNe => BiNe,
|
||||
BiLt => BiGt,
|
||||
BiGt => BiLt,
|
||||
BiLe => BiGe,
|
||||
BiGe => BiLe,
|
||||
_ => BiOr // Dummy
|
||||
}
|
||||
match cmp {
|
||||
BiEq => BiEq,
|
||||
BiNe => BiNe,
|
||||
BiLt => BiGt,
|
||||
BiGt => BiLt,
|
||||
BiLe => BiGe,
|
||||
BiGe => BiLe,
|
||||
_ => BiOr // Dummy
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn check_compare(cx: &Context, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, span: &Span) {
|
||||
match &bit_op.node {
|
||||
&ExprParen(ref subexp) => check_compare(cx, subexp, cmp_op, cmp_value, span),
|
||||
&ExprBinary(ref op, ref left, ref right) => {
|
||||
if op.node != BiBitAnd && op.node != BiBitOr { return; }
|
||||
fetch_int_literal(cx, right).or_else(|| fetch_int_literal(
|
||||
cx, left)).map_or((), |mask| check_bit_mask(cx, op.node,
|
||||
cmp_op, mask, cmp_value, span))
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
match &bit_op.node {
|
||||
&ExprParen(ref subexp) => check_compare(cx, subexp, cmp_op, cmp_value, span),
|
||||
&ExprBinary(ref op, ref left, ref right) => {
|
||||
if op.node != BiBitAnd && op.node != BiBitOr { return; }
|
||||
fetch_int_literal(cx, right).or_else(|| fetch_int_literal(
|
||||
cx, left)).map_or((), |mask| check_bit_mask(cx, op.node,
|
||||
cmp_op, mask, cmp_value, span))
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_,
|
||||
mask_value: u64, cmp_value: u64, span: &Span) {
|
||||
match cmp_op {
|
||||
BiEq | BiNe => match bit_op {
|
||||
BiBitAnd => if mask_value & cmp_value != mask_value {
|
||||
if cmp_value != 0 {
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ & {} can never be equal to {}",
|
||||
mask_value, cmp_value));
|
||||
}
|
||||
} else {
|
||||
if mask_value == 0 {
|
||||
span_lint(cx, BAD_BIT_MASK, *span,
|
||||
&format!("&-masking with zero"));
|
||||
}
|
||||
},
|
||||
BiBitOr => if mask_value | cmp_value != cmp_value {
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ | {} can never be equal to {}",
|
||||
mask_value, cmp_value));
|
||||
},
|
||||
_ => ()
|
||||
},
|
||||
BiLt | BiGe => match bit_op {
|
||||
BiBitAnd => if mask_value < cmp_value {
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ & {} will always be lower than {}",
|
||||
mask_value, cmp_value));
|
||||
} else {
|
||||
if mask_value == 0 {
|
||||
span_lint(cx, BAD_BIT_MASK, *span,
|
||||
&format!("&-masking with zero"));
|
||||
}
|
||||
},
|
||||
BiBitOr => if mask_value >= cmp_value {
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ | {} will never be lower than {}",
|
||||
mask_value, cmp_value));
|
||||
} else {
|
||||
if mask_value < cmp_value {
|
||||
span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!(
|
||||
"ineffective bit mask: x | {} compared to {} is the same as x compared directly",
|
||||
mask_value, cmp_value));
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
},
|
||||
BiLe | BiGt => match bit_op {
|
||||
BiBitAnd => if mask_value <= cmp_value {
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ & {} will never be higher than {}",
|
||||
mask_value, cmp_value));
|
||||
} else {
|
||||
if mask_value == 0 {
|
||||
span_lint(cx, BAD_BIT_MASK, *span,
|
||||
&format!("&-masking with zero"));
|
||||
}
|
||||
},
|
||||
BiBitOr => if mask_value > cmp_value {
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ | {} will always be higher than {}",
|
||||
mask_value, cmp_value));
|
||||
} else {
|
||||
if mask_value < cmp_value {
|
||||
span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!(
|
||||
"ineffective bit mask: x | {} compared to {} is the same as x compared directly",
|
||||
mask_value, cmp_value));
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_,
|
||||
mask_value: u64, cmp_value: u64, span: &Span) {
|
||||
match cmp_op {
|
||||
BiEq | BiNe => match bit_op {
|
||||
BiBitAnd => if mask_value & cmp_value != mask_value {
|
||||
if cmp_value != 0 {
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ & {} can never be equal to {}",
|
||||
mask_value, cmp_value));
|
||||
}
|
||||
} else {
|
||||
if mask_value == 0 {
|
||||
span_lint(cx, BAD_BIT_MASK, *span,
|
||||
&format!("&-masking with zero"));
|
||||
}
|
||||
},
|
||||
BiBitOr => if mask_value | cmp_value != cmp_value {
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ | {} can never be equal to {}",
|
||||
mask_value, cmp_value));
|
||||
},
|
||||
_ => ()
|
||||
},
|
||||
BiLt | BiGe => match bit_op {
|
||||
BiBitAnd => if mask_value < cmp_value {
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ & {} will always be lower than {}",
|
||||
mask_value, cmp_value));
|
||||
} else {
|
||||
if mask_value == 0 {
|
||||
span_lint(cx, BAD_BIT_MASK, *span,
|
||||
&format!("&-masking with zero"));
|
||||
}
|
||||
},
|
||||
BiBitOr => if mask_value >= cmp_value {
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ | {} will never be lower than {}",
|
||||
mask_value, cmp_value));
|
||||
} else {
|
||||
if mask_value < cmp_value {
|
||||
span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!(
|
||||
"ineffective bit mask: x | {} compared to {} is the same as x compared directly",
|
||||
mask_value, cmp_value));
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
},
|
||||
BiLe | BiGt => match bit_op {
|
||||
BiBitAnd => if mask_value <= cmp_value {
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ & {} will never be higher than {}",
|
||||
mask_value, cmp_value));
|
||||
} else {
|
||||
if mask_value == 0 {
|
||||
span_lint(cx, BAD_BIT_MASK, *span,
|
||||
&format!("&-masking with zero"));
|
||||
}
|
||||
},
|
||||
BiBitOr => if mask_value > cmp_value {
|
||||
span_lint(cx, BAD_BIT_MASK, *span, &format!(
|
||||
"incompatible bit mask: _ | {} will always be higher than {}",
|
||||
mask_value, cmp_value));
|
||||
} else {
|
||||
if mask_value < cmp_value {
|
||||
span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!(
|
||||
"ineffective bit mask: x | {} compared to {} is the same as x compared directly",
|
||||
mask_value, cmp_value));
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
fn fetch_int_literal(cx: &Context, lit : &Expr) -> Option<u64> {
|
||||
match &lit.node {
|
||||
&ExprLit(ref lit_ptr) => {
|
||||
if let &LitInt(value, _) = &lit_ptr.node {
|
||||
Option::Some(value) //TODO: Handle sign
|
||||
} else { Option::None }
|
||||
},
|
||||
&ExprPath(_, _) => {
|
||||
// Important to let the borrow expire before the const lookup to avoid double
|
||||
// borrowing.
|
||||
let def_map = cx.tcx.def_map.borrow();
|
||||
match def_map.get(&lit.id) {
|
||||
Some(&PathResolution { base_def: DefConst(def_id), ..}) => Some(def_id),
|
||||
_ => None
|
||||
}
|
||||
match &lit.node {
|
||||
&ExprLit(ref lit_ptr) => {
|
||||
if let &LitInt(value, _) = &lit_ptr.node {
|
||||
Option::Some(value) //TODO: Handle sign
|
||||
} else { Option::None }
|
||||
},
|
||||
&ExprPath(_, _) => {
|
||||
// Important to let the borrow expire before the const lookup to avoid double
|
||||
// borrowing.
|
||||
let def_map = cx.tcx.def_map.borrow();
|
||||
match def_map.get(&lit.id) {
|
||||
Some(&PathResolution { base_def: DefConst(def_id), ..}) => Some(def_id),
|
||||
_ => None
|
||||
}
|
||||
.and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, Option::None))
|
||||
.and_then(|l| fetch_int_literal(cx, l)),
|
||||
_ => Option::None
|
||||
}
|
||||
}
|
||||
.and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, Option::None))
|
||||
.and_then(|l| fetch_int_literal(cx, l)),
|
||||
_ => Option::None
|
||||
}
|
||||
}
|
||||
|
@ -34,24 +34,24 @@ impl LintPass for CollapsibleIf {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(COLLAPSIBLE_IF)
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &Context, expr: &Expr) {
|
||||
cx.sess().codemap().with_expn_info(expr.span.expn_id,
|
||||
|info| check_expr_expd(cx, expr, info))
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &Context, expr: &Expr) {
|
||||
cx.sess().codemap().with_expn_info(expr.span.expn_id,
|
||||
|info| check_expr_expd(cx, expr, info))
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) {
|
||||
if in_macro(cx, info) { return; }
|
||||
|
||||
if let ExprIf(ref check, ref then, None) = e.node {
|
||||
if let Some(&Expr{ node: ExprIf(ref check_inner, _, None), ..}) =
|
||||
single_stmt_of_block(then) {
|
||||
span_lint(cx, COLLAPSIBLE_IF, e.span, &format!(
|
||||
"This if statement can be collapsed. Try: if {} && {}\n{:?}",
|
||||
check_to_string(check), check_to_string(check_inner), e));
|
||||
}
|
||||
}
|
||||
if in_macro(cx, info) { return; }
|
||||
|
||||
if let ExprIf(ref check, ref then, None) = e.node {
|
||||
if let Some(&Expr{ node: ExprIf(ref check_inner, _, None), ..}) =
|
||||
single_stmt_of_block(then) {
|
||||
span_lint(cx, COLLAPSIBLE_IF, e.span, &format!(
|
||||
"This if statement can be collapsed. Try: if {} && {}\n{:?}",
|
||||
check_to_string(check), check_to_string(check_inner), e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn requires_brackets(e: &Expr) -> bool {
|
||||
|
136
src/eq_op.rs
136
src/eq_op.rs
@ -18,12 +18,12 @@ impl LintPass for EqOp {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(EQ_OP)
|
||||
}
|
||||
|
||||
|
||||
fn check_expr(&mut self, cx: &Context, e: &Expr) {
|
||||
if let ExprBinary(ref op, ref left, ref right) = e.node {
|
||||
if is_cmp_or_bit(op) && is_exp_equal(left, right) {
|
||||
span_lint(cx, EQ_OP, e.span, &format!(
|
||||
"equal expressions as operands to {}",
|
||||
"equal expressions as operands to {}",
|
||||
ast_util::binop_to_string(op.node)));
|
||||
}
|
||||
}
|
||||
@ -32,36 +32,36 @@ impl LintPass for EqOp {
|
||||
|
||||
pub fn is_exp_equal(left : &Expr, right : &Expr) -> bool {
|
||||
match (&left.node, &right.node) {
|
||||
(&ExprBinary(ref lop, ref ll, ref lr),
|
||||
&ExprBinary(ref rop, ref rl, ref rr)) =>
|
||||
lop.node == rop.node &&
|
||||
(&ExprBinary(ref lop, ref ll, ref lr),
|
||||
&ExprBinary(ref rop, ref rl, ref rr)) =>
|
||||
lop.node == rop.node &&
|
||||
is_exp_equal(ll, rl) && is_exp_equal(lr, rr),
|
||||
(&ExprBox(ref lpl, ref lbox), &ExprBox(ref rpl, ref rbox)) =>
|
||||
both(lpl, rpl, |l, r| is_exp_equal(l, r)) &&
|
||||
(&ExprBox(ref lpl, ref lbox), &ExprBox(ref rpl, ref rbox)) =>
|
||||
both(lpl, rpl, |l, r| is_exp_equal(l, r)) &&
|
||||
is_exp_equal(lbox, rbox),
|
||||
(&ExprCall(ref lcallee, ref largs),
|
||||
&ExprCall(ref rcallee, ref rargs)) => is_exp_equal(lcallee,
|
||||
(&ExprCall(ref lcallee, ref largs),
|
||||
&ExprCall(ref rcallee, ref rargs)) => is_exp_equal(lcallee,
|
||||
rcallee) && is_exps_equal(largs, rargs),
|
||||
(&ExprCast(ref lc, ref lty), &ExprCast(ref rc, ref rty)) =>
|
||||
(&ExprCast(ref lc, ref lty), &ExprCast(ref rc, ref rty)) =>
|
||||
is_ty_equal(lty, rty) && is_exp_equal(lc, rc),
|
||||
(&ExprField(ref lfexp, ref lfident),
|
||||
&ExprField(ref rfexp, ref rfident)) =>
|
||||
(&ExprField(ref lfexp, ref lfident),
|
||||
&ExprField(ref rfexp, ref rfident)) =>
|
||||
lfident.node == rfident.node && is_exp_equal(lfexp, rfexp),
|
||||
(&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node,
|
||||
(&ExprMethodCall(ref lident, ref lcty, ref lmargs),
|
||||
&ExprMethodCall(ref rident, ref rcty, ref rmargs)) =>
|
||||
lident.node == rident.node && is_tys_equal(lcty, rcty) &&
|
||||
(&ExprMethodCall(ref lident, ref lcty, ref lmargs),
|
||||
&ExprMethodCall(ref rident, ref rcty, ref rmargs)) =>
|
||||
lident.node == rident.node && is_tys_equal(lcty, rcty) &&
|
||||
is_exps_equal(lmargs, rmargs),
|
||||
(&ExprParen(ref lparen), _) => is_exp_equal(lparen, right),
|
||||
(_, &ExprParen(ref rparen)) => is_exp_equal(left, rparen),
|
||||
(&ExprPath(ref lqself, ref lsubpath),
|
||||
&ExprPath(ref rqself, ref rsubpath)) =>
|
||||
both(lqself, rqself, |l, r| is_qself_equal(l, r)) &&
|
||||
is_path_equal(lsubpath, rsubpath),
|
||||
(&ExprTup(ref ltup), &ExprTup(ref rtup)) =>
|
||||
(&ExprPath(ref lqself, ref lsubpath),
|
||||
&ExprPath(ref rqself, ref rsubpath)) =>
|
||||
both(lqself, rqself, |l, r| is_qself_equal(l, r)) &&
|
||||
is_path_equal(lsubpath, rsubpath),
|
||||
(&ExprTup(ref ltup), &ExprTup(ref rtup)) =>
|
||||
is_exps_equal(ltup, rtup),
|
||||
(&ExprUnary(lunop, ref l), &ExprUnary(runop, ref r)) =>
|
||||
lunop == runop && is_exp_equal(l, r),
|
||||
(&ExprUnary(lunop, ref l), &ExprUnary(runop, ref r)) =>
|
||||
lunop == runop && is_exp_equal(l, r),
|
||||
(&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(l, r),
|
||||
_ => false
|
||||
}
|
||||
@ -74,7 +74,7 @@ fn is_exps_equal(left : &[P<Expr>], right : &[P<Expr>]) -> bool {
|
||||
fn is_path_equal(left : &Path, right : &Path) -> bool {
|
||||
// The == of idents doesn't work with different contexts,
|
||||
// we have to be explicit about hygiene
|
||||
left.global == right.global && over(&left.segments, &right.segments,
|
||||
left.global == right.global && over(&left.segments, &right.segments,
|
||||
|l, r| l.identifier.name == r.identifier.name
|
||||
&& l.identifier.ctxt == r.identifier.ctxt
|
||||
&& l.parameters == r.parameters)
|
||||
@ -87,23 +87,23 @@ fn is_qself_equal(left : &QSelf, right : &QSelf) -> bool {
|
||||
fn is_ty_equal(left : &Ty, right : &Ty) -> bool {
|
||||
match (&left.node, &right.node) {
|
||||
(&TyVec(ref lvec), &TyVec(ref rvec)) => is_ty_equal(lvec, rvec),
|
||||
(&TyFixedLengthVec(ref lfvty, ref lfvexp),
|
||||
&TyFixedLengthVec(ref rfvty, ref rfvexp)) =>
|
||||
(&TyFixedLengthVec(ref lfvty, ref lfvexp),
|
||||
&TyFixedLengthVec(ref rfvty, ref rfvexp)) =>
|
||||
is_ty_equal(lfvty, rfvty) && is_exp_equal(lfvexp, rfvexp),
|
||||
(&TyPtr(ref lmut), &TyPtr(ref rmut)) => is_mut_ty_equal(lmut, rmut),
|
||||
(&TyRptr(ref ltime, ref lrmut), &TyRptr(ref rtime, ref rrmut)) =>
|
||||
both(ltime, rtime, is_lifetime_equal) &&
|
||||
(&TyRptr(ref ltime, ref lrmut), &TyRptr(ref rtime, ref rrmut)) =>
|
||||
both(ltime, rtime, is_lifetime_equal) &&
|
||||
is_mut_ty_equal(lrmut, rrmut),
|
||||
(&TyBareFn(ref lbare), &TyBareFn(ref rbare)) =>
|
||||
(&TyBareFn(ref lbare), &TyBareFn(ref rbare)) =>
|
||||
is_bare_fn_ty_equal(lbare, rbare),
|
||||
(&TyTup(ref ltup), &TyTup(ref rtup)) => is_tys_equal(ltup, rtup),
|
||||
(&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) =>
|
||||
(&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) =>
|
||||
both(lq, rq, is_qself_equal) && is_path_equal(lpath, rpath),
|
||||
(&TyObjectSum(ref lsumty, ref lobounds),
|
||||
&TyObjectSum(ref rsumty, ref robounds)) =>
|
||||
is_ty_equal(lsumty, rsumty) &&
|
||||
(&TyObjectSum(ref lsumty, ref lobounds),
|
||||
&TyObjectSum(ref rsumty, ref robounds)) =>
|
||||
is_ty_equal(lsumty, rsumty) &&
|
||||
is_param_bounds_equal(lobounds, robounds),
|
||||
(&TyPolyTraitRef(ref ltbounds), &TyPolyTraitRef(ref rtbounds)) =>
|
||||
(&TyPolyTraitRef(ref ltbounds), &TyPolyTraitRef(ref rtbounds)) =>
|
||||
is_param_bounds_equal(ltbounds, rtbounds),
|
||||
(&TyParen(ref lty), &TyParen(ref rty)) => is_ty_equal(lty, rty),
|
||||
(&TyTypeof(ref lof), &TyTypeof(ref rof)) => is_exp_equal(lof, rof),
|
||||
@ -112,13 +112,13 @@ fn is_ty_equal(left : &Ty, right : &Ty) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_param_bound_equal(left : &TyParamBound, right : &TyParamBound)
|
||||
fn is_param_bound_equal(left : &TyParamBound, right : &TyParamBound)
|
||||
-> bool {
|
||||
match(left, right) {
|
||||
(&TraitTyParamBound(ref lpoly, ref lmod),
|
||||
&TraitTyParamBound(ref rpoly, ref rmod)) =>
|
||||
(&TraitTyParamBound(ref lpoly, ref lmod),
|
||||
&TraitTyParamBound(ref rpoly, ref rmod)) =>
|
||||
lmod == rmod && is_poly_traitref_equal(lpoly, rpoly),
|
||||
(&RegionTyParamBound(ref ltime), &RegionTyParamBound(ref rtime)) =>
|
||||
(&RegionTyParamBound(ref ltime), &RegionTyParamBound(ref rtime)) =>
|
||||
is_lifetime_equal(ltime, rtime),
|
||||
_ => false
|
||||
}
|
||||
@ -140,24 +140,24 @@ fn is_mut_ty_equal(left : &MutTy, right : &MutTy) -> bool {
|
||||
}
|
||||
|
||||
fn is_bare_fn_ty_equal(left : &BareFnTy, right : &BareFnTy) -> bool {
|
||||
left.unsafety == right.unsafety && left.abi == right.abi &&
|
||||
is_lifetimedefs_equal(&left.lifetimes, &right.lifetimes) &&
|
||||
left.unsafety == right.unsafety && left.abi == right.abi &&
|
||||
is_lifetimedefs_equal(&left.lifetimes, &right.lifetimes) &&
|
||||
is_fndecl_equal(&left.decl, &right.decl)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_fndecl_equal(left : &P<FnDecl>, right : &P<FnDecl>) -> bool {
|
||||
left.variadic == right.variadic &&
|
||||
is_args_equal(&left.inputs, &right.inputs) &&
|
||||
left.variadic == right.variadic &&
|
||||
is_args_equal(&left.inputs, &right.inputs) &&
|
||||
is_fnret_ty_equal(&left.output, &right.output)
|
||||
}
|
||||
|
||||
fn is_fnret_ty_equal(left : &FunctionRetTy, right : &FunctionRetTy)
|
||||
fn is_fnret_ty_equal(left : &FunctionRetTy, right : &FunctionRetTy)
|
||||
-> bool {
|
||||
match (left, right) {
|
||||
(&NoReturn(_), &NoReturn(_)) |
|
||||
(&NoReturn(_), &NoReturn(_)) |
|
||||
(&DefaultReturn(_), &DefaultReturn(_)) => true,
|
||||
(&Return(ref lty), &Return(ref rty)) => is_ty_equal(lty, rty),
|
||||
_ => false
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,49 +172,49 @@ fn is_args_equal(left : &[Arg], right : &[Arg]) -> bool {
|
||||
fn is_pat_equal(left : &Pat, right : &Pat) -> bool {
|
||||
match(&left.node, &right.node) {
|
||||
(&PatWild(lwild), &PatWild(rwild)) => lwild == rwild,
|
||||
(&PatIdent(ref lmode, ref lident, Option::None),
|
||||
(&PatIdent(ref lmode, ref lident, Option::None),
|
||||
&PatIdent(ref rmode, ref rident, Option::None)) =>
|
||||
lmode == rmode && is_ident_equal(&lident.node, &rident.node),
|
||||
(&PatIdent(ref lmode, ref lident, Option::Some(ref lpat)),
|
||||
(&PatIdent(ref lmode, ref lident, Option::Some(ref lpat)),
|
||||
&PatIdent(ref rmode, ref rident, Option::Some(ref rpat))) =>
|
||||
lmode == rmode && is_ident_equal(&lident.node, &rident.node) &&
|
||||
lmode == rmode && is_ident_equal(&lident.node, &rident.node) &&
|
||||
is_pat_equal(lpat, rpat),
|
||||
(&PatEnum(ref lpath, ref lenum), &PatEnum(ref rpath, ref renum)) =>
|
||||
is_path_equal(lpath, rpath) && both(lenum, renum, |l, r|
|
||||
(&PatEnum(ref lpath, ref lenum), &PatEnum(ref rpath, ref renum)) =>
|
||||
is_path_equal(lpath, rpath) && both(lenum, renum, |l, r|
|
||||
is_pats_equal(l, r)),
|
||||
(&PatStruct(ref lpath, ref lfieldpat, lbool),
|
||||
(&PatStruct(ref lpath, ref lfieldpat, lbool),
|
||||
&PatStruct(ref rpath, ref rfieldpat, rbool)) =>
|
||||
lbool == rbool && is_path_equal(lpath, rpath) &&
|
||||
lbool == rbool && is_path_equal(lpath, rpath) &&
|
||||
is_spanned_fieldpats_equal(lfieldpat, rfieldpat),
|
||||
(&PatTup(ref ltup), &PatTup(ref rtup)) => is_pats_equal(ltup, rtup),
|
||||
(&PatBox(ref lboxed), &PatBox(ref rboxed)) =>
|
||||
(&PatTup(ref ltup), &PatTup(ref rtup)) => is_pats_equal(ltup, rtup),
|
||||
(&PatBox(ref lboxed), &PatBox(ref rboxed)) =>
|
||||
is_pat_equal(lboxed, rboxed),
|
||||
(&PatRegion(ref lpat, ref lmut), &PatRegion(ref rpat, ref rmut)) =>
|
||||
(&PatRegion(ref lpat, ref lmut), &PatRegion(ref rpat, ref rmut)) =>
|
||||
is_pat_equal(lpat, rpat) && lmut == rmut,
|
||||
(&PatLit(ref llit), &PatLit(ref rlit)) => is_exp_equal(llit, rlit),
|
||||
(&PatRange(ref lfrom, ref lto), &PatRange(ref rfrom, ref rto)) =>
|
||||
is_exp_equal(lfrom, rfrom) && is_exp_equal(lto, rto),
|
||||
(&PatVec(ref lfirst, Option::None, ref llast),
|
||||
(&PatVec(ref lfirst, Option::None, ref llast),
|
||||
&PatVec(ref rfirst, Option::None, ref rlast)) =>
|
||||
is_pats_equal(lfirst, rfirst) && is_pats_equal(llast, rlast),
|
||||
(&PatVec(ref lfirst, Option::Some(ref lpat), ref llast),
|
||||
(&PatVec(ref lfirst, Option::Some(ref lpat), ref llast),
|
||||
&PatVec(ref rfirst, Option::Some(ref rpat), ref rlast)) =>
|
||||
is_pats_equal(lfirst, rfirst) && is_pat_equal(lpat, rpat) &&
|
||||
is_pats_equal(lfirst, rfirst) && is_pat_equal(lpat, rpat) &&
|
||||
is_pats_equal(llast, rlast),
|
||||
// I don't match macros for now, the code is slow enough as is ;-)
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
fn is_spanned_fieldpats_equal(left : &[code::Spanned<FieldPat>],
|
||||
fn is_spanned_fieldpats_equal(left : &[code::Spanned<FieldPat>],
|
||||
right : &[code::Spanned<FieldPat>]) -> bool {
|
||||
over(left, right, |l, r| is_fieldpat_equal(&l.node, &r.node))
|
||||
}
|
||||
|
||||
fn is_fieldpat_equal(left : &FieldPat, right : &FieldPat) -> bool {
|
||||
left.is_shorthand == right.is_shorthand &&
|
||||
is_ident_equal(&left.ident, &right.ident) &&
|
||||
is_pat_equal(&left.pat, &right.pat)
|
||||
left.is_shorthand == right.is_shorthand &&
|
||||
is_ident_equal(&left.ident, &right.ident) &&
|
||||
is_pat_equal(&left.pat, &right.pat)
|
||||
}
|
||||
|
||||
fn is_ident_equal(left : &Ident, right : &Ident) -> bool {
|
||||
@ -227,11 +227,11 @@ fn is_pats_equal(left : &[P<Pat>], right : &[P<Pat>]) -> bool {
|
||||
|
||||
fn is_lifetimedef_equal(left : &LifetimeDef, right : &LifetimeDef)
|
||||
-> bool {
|
||||
is_lifetime_equal(&left.lifetime, &right.lifetime) &&
|
||||
is_lifetime_equal(&left.lifetime, &right.lifetime) &&
|
||||
over(&left.bounds, &right.bounds, is_lifetime_equal)
|
||||
}
|
||||
|
||||
fn is_lifetimedefs_equal(left : &[LifetimeDef], right : &[LifetimeDef])
|
||||
fn is_lifetimedefs_equal(left : &[LifetimeDef], right : &[LifetimeDef])
|
||||
-> bool {
|
||||
over(left, right, is_lifetimedef_equal)
|
||||
}
|
||||
@ -244,13 +244,13 @@ fn is_tys_equal(left : &[P<Ty>], right : &[P<Ty>]) -> bool {
|
||||
over(left, right, |l, r| is_ty_equal(l, r))
|
||||
}
|
||||
|
||||
fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool
|
||||
fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool
|
||||
where F: FnMut(&X, &X) -> bool {
|
||||
left.len() == right.len() && left.iter().zip(right).all(|(x, y)|
|
||||
left.len() == right.len() && left.iter().zip(right).all(|(x, y)|
|
||||
eq_fn(x, y))
|
||||
}
|
||||
|
||||
fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn : F) -> bool
|
||||
fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn : F) -> bool
|
||||
where F: FnMut(&X, &X) -> bool {
|
||||
l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false,
|
||||
|y| eq_fn(x, y)))
|
||||
@ -258,7 +258,7 @@ fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn : F) -> bool
|
||||
|
||||
fn is_cmp_or_bit(op : &BinOp) -> bool {
|
||||
match op.node {
|
||||
BiEq | BiLt | BiLe | BiGt | BiGe | BiNe | BiAnd | BiOr |
|
||||
BiEq | BiLt | BiLe | BiGt | BiGe | BiNe | BiAnd | BiOr |
|
||||
BiBitXor | BiBitAnd | BiBitOr => true,
|
||||
_ => false
|
||||
}
|
||||
|
@ -58,4 +58,3 @@ impl LintPass for EtaPass {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ use utils::{span_lint, snippet};
|
||||
|
||||
declare_lint! { pub IDENTITY_OP, Warn,
|
||||
"Warn on identity operations, e.g. '_ + 0'"}
|
||||
|
||||
|
||||
#[derive(Copy,Clone)]
|
||||
pub struct IdentityOp;
|
||||
|
||||
@ -27,7 +27,7 @@ impl LintPass for IdentityOp {
|
||||
check(cx, left, 0, e.span, right.span);
|
||||
check(cx, right, 0, e.span, left.span);
|
||||
},
|
||||
BiShl | BiShr | BiSub =>
|
||||
BiShl | BiShr | BiSub =>
|
||||
check(cx, right, 0, e.span, left.span),
|
||||
BiMul => {
|
||||
check(cx, left, 1, e.span, right.span);
|
||||
@ -49,14 +49,14 @@ impl LintPass for IdentityOp {
|
||||
fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) {
|
||||
if have_lit(cx, e, m) {
|
||||
span_lint(cx, IDENTITY_OP, span, &format!(
|
||||
"The operation is ineffective. Consider reducing it to '{}'",
|
||||
"The operation is ineffective. Consider reducing it to '{}'",
|
||||
snippet(cx, arg, "..")));
|
||||
}
|
||||
}
|
||||
|
||||
fn have_lit(cx: &Context, e : &Expr, m: i8) -> bool {
|
||||
match &e.node {
|
||||
&ExprUnary(UnNeg, ref litexp) => have_lit(cx, litexp, -m),
|
||||
&ExprUnary(UnNeg, ref litexp) => have_lit(cx, litexp, -m),
|
||||
&ExprLit(ref lit) => {
|
||||
match (&lit.node, m) {
|
||||
(&LitInt(0, _), 0) => true,
|
||||
@ -68,9 +68,9 @@ fn have_lit(cx: &Context, e : &Expr, m: i8) -> bool {
|
||||
}
|
||||
},
|
||||
&ExprParen(ref p) => have_lit(cx, p, m),
|
||||
&ExprPath(_, _) => {
|
||||
&ExprPath(_, _) => {
|
||||
match cx.tcx.def_map.borrow().get(&e.id) {
|
||||
Some(&PathResolution { base_def: DefConst(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
|
||||
|
210
src/len_zero.rs
210
src/len_zero.rs
@ -22,130 +22,130 @@ declare_lint!(pub LEN_WITHOUT_IS_EMPTY, Warn,
|
||||
pub struct LenZero;
|
||||
|
||||
impl LintPass for LenZero {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(LEN_ZERO, LEN_WITHOUT_IS_EMPTY)
|
||||
}
|
||||
|
||||
fn check_item(&mut self, cx: &Context, item: &Item) {
|
||||
match &item.node {
|
||||
&ItemTrait(_, _, _, ref trait_items) =>
|
||||
check_trait_items(cx, item, trait_items),
|
||||
&ItemImpl(_, _, _, None, _, ref impl_items) => // only non-trait
|
||||
check_impl_items(cx, item, impl_items),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &Context, expr: &Expr) {
|
||||
if let &ExprBinary(Spanned{node: cmp, ..}, ref left, ref right) =
|
||||
&expr.node {
|
||||
match cmp {
|
||||
BiEq => check_cmp(cx, expr.span, left, right, ""),
|
||||
BiGt | BiNe => check_cmp(cx, expr.span, left, right, "!"),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_item(&mut self, cx: &Context, item: &Item) {
|
||||
match &item.node {
|
||||
&ItemTrait(_, _, _, ref trait_items) =>
|
||||
check_trait_items(cx, item, trait_items),
|
||||
&ItemImpl(_, _, _, None, _, ref impl_items) => // only non-trait
|
||||
check_impl_items(cx, item, impl_items),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &Context, expr: &Expr) {
|
||||
if let &ExprBinary(Spanned{node: cmp, ..}, ref left, ref right) =
|
||||
&expr.node {
|
||||
match cmp {
|
||||
BiEq => check_cmp(cx, expr.span, left, right, ""),
|
||||
BiGt | BiNe => check_cmp(cx, expr.span, left, right, "!"),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P<TraitItem>]) {
|
||||
fn is_named_self(item: &TraitItem, name: &str) -> bool {
|
||||
item.ident.name == name && if let MethodTraitItem(ref sig, _) =
|
||||
item.node { is_self_sig(sig) } else { false }
|
||||
}
|
||||
fn is_named_self(item: &TraitItem, name: &str) -> bool {
|
||||
item.ident.name == name && if let MethodTraitItem(ref sig, _) =
|
||||
item.node { is_self_sig(sig) } else { false }
|
||||
}
|
||||
|
||||
if !trait_items.iter().any(|i| is_named_self(i, "is_empty")) {
|
||||
//span_lint(cx, LEN_WITHOUT_IS_EMPTY, item.span, &format!("trait {}", item.ident.as_str()));
|
||||
for i in trait_items {
|
||||
if is_named_self(i, "len") {
|
||||
span_lint(cx, LEN_WITHOUT_IS_EMPTY, i.span,
|
||||
&format!("Trait '{}' has a '.len(_: &Self)' method, but no \
|
||||
'.is_empty(_: &Self)' method. Consider adding one.",
|
||||
item.ident.name));
|
||||
}
|
||||
};
|
||||
}
|
||||
if !trait_items.iter().any(|i| is_named_self(i, "is_empty")) {
|
||||
//span_lint(cx, LEN_WITHOUT_IS_EMPTY, item.span, &format!("trait {}", item.ident.as_str()));
|
||||
for i in trait_items {
|
||||
if is_named_self(i, "len") {
|
||||
span_lint(cx, LEN_WITHOUT_IS_EMPTY, i.span,
|
||||
&format!("Trait '{}' has a '.len(_: &Self)' method, but no \
|
||||
'.is_empty(_: &Self)' method. Consider adding one.",
|
||||
item.ident.name));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn check_impl_items(cx: &Context, item: &Item, impl_items: &[P<ImplItem>]) {
|
||||
fn is_named_self(item: &ImplItem, name: &str) -> bool {
|
||||
item.ident.name == name && if let MethodImplItem(ref sig, _) =
|
||||
item.node { is_self_sig(sig) } else { false }
|
||||
}
|
||||
fn is_named_self(item: &ImplItem, name: &str) -> bool {
|
||||
item.ident.name == name && if let MethodImplItem(ref sig, _) =
|
||||
item.node { is_self_sig(sig) } else { false }
|
||||
}
|
||||
|
||||
if !impl_items.iter().any(|i| is_named_self(i, "is_empty")) {
|
||||
for i in impl_items {
|
||||
if is_named_self(i, "len") {
|
||||
let s = i.span;
|
||||
span_lint(cx, LEN_WITHOUT_IS_EMPTY,
|
||||
Span{ lo: s.lo, hi: s.lo, expn_id: s.expn_id },
|
||||
&format!("Item '{}' has a '.len(_: &Self)' method, but no \
|
||||
'.is_empty(_: &Self)' method. Consider adding one.",
|
||||
item.ident.name));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !impl_items.iter().any(|i| is_named_self(i, "is_empty")) {
|
||||
for i in impl_items {
|
||||
if is_named_self(i, "len") {
|
||||
let s = i.span;
|
||||
span_lint(cx, LEN_WITHOUT_IS_EMPTY,
|
||||
Span{ lo: s.lo, hi: s.lo, expn_id: s.expn_id },
|
||||
&format!("Item '{}' has a '.len(_: &Self)' method, but no \
|
||||
'.is_empty(_: &Self)' method. Consider adding one.",
|
||||
item.ident.name));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_self_sig(sig: &MethodSig) -> bool {
|
||||
if let SelfStatic = sig.explicit_self.node {
|
||||
false } else { sig.decl.inputs.len() == 1 }
|
||||
if let SelfStatic = sig.explicit_self.node {
|
||||
false } else { sig.decl.inputs.len() == 1 }
|
||||
}
|
||||
|
||||
fn check_cmp(cx: &Context, span: Span, left: &Expr, right: &Expr, empty: &str) {
|
||||
match (&left.node, &right.node) {
|
||||
(&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) =>
|
||||
check_len_zero(cx, span, method, args, lit, empty),
|
||||
(&ExprMethodCall(ref method, _, ref args), &ExprLit(ref lit)) =>
|
||||
check_len_zero(cx, span, method, args, lit, empty),
|
||||
_ => ()
|
||||
}
|
||||
match (&left.node, &right.node) {
|
||||
(&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) =>
|
||||
check_len_zero(cx, span, method, args, lit, empty),
|
||||
(&ExprMethodCall(ref method, _, ref args), &ExprLit(ref lit)) =>
|
||||
check_len_zero(cx, span, method, args, lit, empty),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent,
|
||||
args: &[P<Expr>], lit: &Lit, empty: &str) {
|
||||
if let &Spanned{node: LitInt(0, _), ..} = lit {
|
||||
if method.node.name == "len" && args.len() == 1 &&
|
||||
has_is_empty(cx, &*args[0]) {
|
||||
span_lint(cx, LEN_ZERO, span, &format!(
|
||||
"Consider replacing the len comparison with '{}_.is_empty()'",
|
||||
empty))
|
||||
}
|
||||
}
|
||||
fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent,
|
||||
args: &[P<Expr>], lit: &Lit, empty: &str) {
|
||||
if let &Spanned{node: LitInt(0, _), ..} = lit {
|
||||
if method.node.name == "len" && args.len() == 1 &&
|
||||
has_is_empty(cx, &*args[0]) {
|
||||
span_lint(cx, LEN_ZERO, span, &format!(
|
||||
"Consider replacing the len comparison with '{}_.is_empty()'",
|
||||
empty))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// check if this type has an is_empty method
|
||||
fn has_is_empty(cx: &Context, expr: &Expr) -> bool {
|
||||
/// get a ImplOrTraitItem and return true if it matches is_empty(self)
|
||||
fn is_is_empty(cx: &Context, id: &ImplOrTraitItemId) -> bool {
|
||||
if let &MethodTraitItemId(def_id) = id {
|
||||
if let ty::MethodTraitItem(ref method) =
|
||||
cx.tcx.impl_or_trait_item(def_id) {
|
||||
method.name.as_str() == "is_empty"
|
||||
&& method.fty.sig.skip_binder().inputs.len() == 1
|
||||
} else { false }
|
||||
} else { false }
|
||||
}
|
||||
|
||||
/// check the inherent impl's items for an is_empty(self) method
|
||||
fn has_is_empty_impl(cx: &Context, id: &DefId) -> bool {
|
||||
let impl_items = cx.tcx.impl_items.borrow();
|
||||
cx.tcx.inherent_impls.borrow().get(id).map_or(false,
|
||||
|ids| ids.iter().any(|iid| impl_items.get(iid).map_or(false,
|
||||
|iids| iids.iter().any(|i| is_is_empty(cx, i)))))
|
||||
}
|
||||
|
||||
let ty = &walk_ty(&cx.tcx.expr_ty(expr));
|
||||
match ty.sty {
|
||||
ty::TyTrait(_) => cx.tcx.trait_item_def_ids.borrow().get(
|
||||
&ty.ty_to_def_id().expect("trait impl not found")).map_or(false,
|
||||
|ids| ids.iter().any(|i| is_is_empty(cx, i))),
|
||||
ty::TyProjection(_) => ty.ty_to_def_id().map_or(false,
|
||||
|id| has_is_empty_impl(cx, &id)),
|
||||
ty::TyEnum(ref id, _) | ty::TyStruct(ref id, _) =>
|
||||
has_is_empty_impl(cx, &id.did),
|
||||
ty::TyArray(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
/// get a ImplOrTraitItem and return true if it matches is_empty(self)
|
||||
fn is_is_empty(cx: &Context, id: &ImplOrTraitItemId) -> bool {
|
||||
if let &MethodTraitItemId(def_id) = id {
|
||||
if let ty::MethodTraitItem(ref method) =
|
||||
cx.tcx.impl_or_trait_item(def_id) {
|
||||
method.name.as_str() == "is_empty"
|
||||
&& method.fty.sig.skip_binder().inputs.len() == 1
|
||||
} else { false }
|
||||
} else { false }
|
||||
}
|
||||
|
||||
/// check the inherent impl's items for an is_empty(self) method
|
||||
fn has_is_empty_impl(cx: &Context, id: &DefId) -> bool {
|
||||
let impl_items = cx.tcx.impl_items.borrow();
|
||||
cx.tcx.inherent_impls.borrow().get(id).map_or(false,
|
||||
|ids| ids.iter().any(|iid| impl_items.get(iid).map_or(false,
|
||||
|iids| iids.iter().any(|i| is_is_empty(cx, i)))))
|
||||
}
|
||||
|
||||
let ty = &walk_ty(&cx.tcx.expr_ty(expr));
|
||||
match ty.sty {
|
||||
ty::TyTrait(_) => cx.tcx.trait_item_def_ids.borrow().get(
|
||||
&ty.ty_to_def_id().expect("trait impl not found")).map_or(false,
|
||||
|ids| ids.iter().any(|i| is_is_empty(cx, i))),
|
||||
ty::TyProjection(_) => ty.ty_to_def_id().map_or(false,
|
||||
|id| has_is_empty_impl(cx, &id)),
|
||||
ty::TyEnum(ref id, _) | ty::TyStruct(ref id, _) =>
|
||||
has_is_empty_impl(cx, &id.did),
|
||||
ty::TyArray(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -12,50 +12,50 @@ declare_lint!(pub MUT_MUT, Warn,
|
||||
pub struct MutMut;
|
||||
|
||||
impl LintPass for MutMut {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(MUT_MUT)
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &Context, expr: &Expr) {
|
||||
cx.sess().codemap().with_expn_info(expr.span.expn_id,
|
||||
|info| check_expr_expd(cx, expr, info))
|
||||
}
|
||||
|
||||
fn check_ty(&mut self, cx: &Context, ty: &Ty) {
|
||||
unwrap_mut(ty).and_then(unwrap_mut).map_or((), |_| span_lint(cx, MUT_MUT,
|
||||
ty.span, "Generally you want to avoid &mut &mut _ if possible."))
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &Context, expr: &Expr) {
|
||||
cx.sess().codemap().with_expn_info(expr.span.expn_id,
|
||||
|info| check_expr_expd(cx, expr, info))
|
||||
}
|
||||
|
||||
fn check_ty(&mut self, cx: &Context, ty: &Ty) {
|
||||
unwrap_mut(ty).and_then(unwrap_mut).map_or((), |_| span_lint(cx, MUT_MUT,
|
||||
ty.span, "Generally you want to avoid &mut &mut _ if possible."))
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr_expd(cx: &Context, expr: &Expr, info: Option<&ExpnInfo>) {
|
||||
if in_macro(cx, info) { return; }
|
||||
if in_macro(cx, info) { return; }
|
||||
|
||||
fn unwrap_addr(expr : &Expr) -> Option<&Expr> {
|
||||
match expr.node {
|
||||
ExprAddrOf(MutMutable, ref e) => Option::Some(e),
|
||||
_ => Option::None
|
||||
}
|
||||
}
|
||||
|
||||
unwrap_addr(expr).map_or((), |e| {
|
||||
unwrap_addr(e).map(|_| {
|
||||
span_lint(cx, MUT_MUT, expr.span,
|
||||
"Generally you want to avoid &mut &mut _ if possible.")
|
||||
}).unwrap_or_else(|| {
|
||||
if let TyRef(_, TypeAndMut{ty: _, mutbl: MutMutable}) =
|
||||
cx.tcx.expr_ty(e).sty {
|
||||
span_lint(cx, MUT_MUT, expr.span,
|
||||
"This expression mutably borrows a mutable reference. \
|
||||
Consider reborrowing")
|
||||
}
|
||||
})
|
||||
})
|
||||
fn unwrap_addr(expr : &Expr) -> Option<&Expr> {
|
||||
match expr.node {
|
||||
ExprAddrOf(MutMutable, ref e) => Option::Some(e),
|
||||
_ => Option::None
|
||||
}
|
||||
}
|
||||
|
||||
unwrap_addr(expr).map_or((), |e| {
|
||||
unwrap_addr(e).map(|_| {
|
||||
span_lint(cx, MUT_MUT, expr.span,
|
||||
"Generally you want to avoid &mut &mut _ if possible.")
|
||||
}).unwrap_or_else(|| {
|
||||
if let TyRef(_, TypeAndMut{ty: _, mutbl: MutMutable}) =
|
||||
cx.tcx.expr_ty(e).sty {
|
||||
span_lint(cx, MUT_MUT, expr.span,
|
||||
"This expression mutably borrows a mutable reference. \
|
||||
Consider reborrowing")
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn unwrap_mut(ty : &Ty) -> Option<&Ty> {
|
||||
match ty.node {
|
||||
TyPtr(MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty),
|
||||
TyRptr(_, MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty),
|
||||
_ => Option::None
|
||||
}
|
||||
match ty.node {
|
||||
TyPtr(MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty),
|
||||
TyRptr(_, MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty),
|
||||
_ => Option::None
|
||||
}
|
||||
}
|
||||
|
@ -25,38 +25,39 @@ impl LintPass for NeedlessBool {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(NEEDLESS_BOOL)
|
||||
}
|
||||
|
||||
|
||||
fn check_expr(&mut self, cx: &Context, e: &Expr) {
|
||||
if let ExprIf(_, ref then_block, Option::Some(ref else_expr)) = e.node {
|
||||
match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) {
|
||||
(Option::Some(true), Option::Some(true)) => {
|
||||
span_lint(cx, NEEDLESS_BOOL, e.span,
|
||||
"your if-then-else expression will always return true"); },
|
||||
(Option::Some(true), Option::Some(false)) => {
|
||||
span_lint(cx, NEEDLESS_BOOL, e.span,
|
||||
"you can reduce your if-statement to its predicate"); },
|
||||
(Option::Some(false), Option::Some(true)) => {
|
||||
span_lint(cx, NEEDLESS_BOOL, e.span,
|
||||
"you can reduce your if-statement to '!' + your predicate"); },
|
||||
(Option::Some(false), Option::Some(false)) => {
|
||||
span_lint(cx, NEEDLESS_BOOL, e.span,
|
||||
"your if-then-else expression will always return false"); },
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) {
|
||||
(Option::Some(true), Option::Some(true)) => {
|
||||
span_lint(cx, NEEDLESS_BOOL, e.span,
|
||||
"your if-then-else expression will always return true"); },
|
||||
(Option::Some(true), Option::Some(false)) => {
|
||||
span_lint(cx, NEEDLESS_BOOL, e.span,
|
||||
"you can reduce your if-statement to its predicate"); },
|
||||
(Option::Some(false), Option::Some(true)) => {
|
||||
span_lint(cx, NEEDLESS_BOOL, e.span,
|
||||
"you can reduce your if-statement to '!' + your predicate"); },
|
||||
(Option::Some(false), Option::Some(false)) => {
|
||||
span_lint(cx, NEEDLESS_BOOL, e.span,
|
||||
"your if-then-else expression will always return false"); },
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fetch_bool_block(block: &Block) -> Option<bool> {
|
||||
if block.stmts.is_empty() {
|
||||
block.expr.as_ref().map(de_p).and_then(fetch_bool_expr)
|
||||
} else { Option::None }
|
||||
if block.stmts.is_empty() {
|
||||
block.expr.as_ref().map(de_p).and_then(fetch_bool_expr)
|
||||
} else { Option::None }
|
||||
}
|
||||
|
||||
|
||||
fn fetch_bool_expr(expr: &Expr) -> Option<bool> {
|
||||
match &expr.node {
|
||||
&ExprBlock(ref block) => fetch_bool_block(block),
|
||||
&ExprLit(ref lit_ptr) => if let &LitBool(value) = &lit_ptr.node { Option::Some(value) } else { Option::None },
|
||||
_ => Option::None
|
||||
}
|
||||
match &expr.node {
|
||||
&ExprBlock(ref block) => fetch_bool_block(block),
|
||||
&ExprLit(ref lit_ptr) => if let &LitBool(value) = &lit_ptr.node {
|
||||
Option::Some(value) } else { Option::None },
|
||||
_ => Option::None
|
||||
}
|
||||
}
|
||||
|
@ -26,44 +26,44 @@ impl LintPass for PtrArg {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(PTR_ARG)
|
||||
}
|
||||
|
||||
|
||||
fn check_item(&mut self, cx: &Context, item: &Item) {
|
||||
if let &ItemFn(ref decl, _, _, _, _, _) = &item.node {
|
||||
check_fn(cx, decl);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) {
|
||||
if let &MethodImplItem(ref sig, _) = &item.node {
|
||||
check_fn(cx, &sig.decl);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) {
|
||||
if let &MethodTraitItem(ref sig, _) = &item.node {
|
||||
check_fn(cx, &sig.decl);
|
||||
}
|
||||
}
|
||||
if let &ItemFn(ref decl, _, _, _, _, _) = &item.node {
|
||||
check_fn(cx, decl);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) {
|
||||
if let &MethodImplItem(ref sig, _) = &item.node {
|
||||
check_fn(cx, &sig.decl);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) {
|
||||
if let &MethodTraitItem(ref sig, _) = &item.node {
|
||||
check_fn(cx, &sig.decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_fn(cx: &Context, decl: &FnDecl) {
|
||||
for arg in &decl.inputs {
|
||||
match &arg.ty.node {
|
||||
&TyPtr(ref p) | &TyRptr(_, ref p) =>
|
||||
check_ptr_subtype(cx, arg.ty.span, &p.ty),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
for arg in &decl.inputs {
|
||||
match &arg.ty.node {
|
||||
&TyPtr(ref p) | &TyRptr(_, ref p) =>
|
||||
check_ptr_subtype(cx, arg.ty.span, &p.ty),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_ptr_subtype(cx: &Context, span: Span, ty: &Ty) {
|
||||
match_ty_unwrap(ty, &["Vec"]).map_or_else(|| match_ty_unwrap(ty,
|
||||
&["String"]).map_or((), |_| {
|
||||
span_lint(cx, PTR_ARG, span,
|
||||
"Writing '&String' instead of '&str' involves a new Object \
|
||||
where a slices will do. Consider changing the type to &str")
|
||||
}), |_| span_lint(cx, PTR_ARG, span, "Writing '&Vec<_>' instead of \
|
||||
'&[_]' involves one more reference and cannot be used with \
|
||||
non-vec-based slices. Consider changing the type to &[...]")
|
||||
)
|
||||
match_ty_unwrap(ty, &["Vec"]).map_or_else(|| match_ty_unwrap(ty,
|
||||
&["String"]).map_or((), |_| {
|
||||
span_lint(cx, PTR_ARG, span,
|
||||
"Writing '&String' instead of '&str' involves a new Object \
|
||||
where a slices will do. Consider changing the type to &str")
|
||||
}), |_| span_lint(cx, PTR_ARG, span,
|
||||
"Writing '&Vec<_>' instead of \
|
||||
'&[_]' involves one more reference and cannot be used with \
|
||||
non-vec-based slices. Consider changing the type to &[...]"))
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
//! This LintPass catches both string addition and string addition + assignment
|
||||
//!
|
||||
//!
|
||||
//! Note that since we have two lints where one subsumes the other, we try to
|
||||
//! disable the subsumed lint unless it has a higher level
|
||||
|
||||
@ -25,11 +25,11 @@ impl LintPass for StringAdd {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(STRING_ADD_ASSIGN)
|
||||
}
|
||||
|
||||
|
||||
fn check_expr(&mut self, cx: &Context, e: &Expr) {
|
||||
if let &ExprAssign(ref target, ref src) = &e.node {
|
||||
if is_string(cx, target) && is_add(src, target) {
|
||||
span_lint(cx, STRING_ADD_ASSIGN, e.span,
|
||||
if is_string(cx, target) && is_add(src, target) {
|
||||
span_lint(cx, STRING_ADD_ASSIGN, e.span,
|
||||
"You assign the result of adding something to this string. \
|
||||
Consider using `String::push_str(..) instead.")
|
||||
}
|
||||
@ -47,7 +47,7 @@ fn is_add(src: &Expr, target: &Expr) -> bool {
|
||||
match &src.node {
|
||||
&ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) =>
|
||||
is_exp_equal(target, left),
|
||||
&ExprBlock(ref block) => block.stmts.is_empty() &&
|
||||
&ExprBlock(ref block) => block.stmts.is_empty() &&
|
||||
block.expr.as_ref().map_or(false, |expr| is_add(&*expr, target)),
|
||||
&ExprParen(ref expr) => is_add(&*expr, target),
|
||||
_ => false
|
||||
|
@ -9,38 +9,38 @@ declare_lint!{ pub ZERO_WIDTH_SPACE, Deny, "Zero-width space is confusing" }
|
||||
pub struct Unicode;
|
||||
|
||||
impl LintPass for Unicode {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(ZERO_WIDTH_SPACE)
|
||||
}
|
||||
|
||||
|
||||
fn check_expr(&mut self, cx: &Context, expr: &Expr) {
|
||||
if let ExprLit(ref lit) = expr.node {
|
||||
if let LitStr(ref string, _) = lit.node {
|
||||
check_str(cx, string, lit.span)
|
||||
}
|
||||
}
|
||||
}
|
||||
if let ExprLit(ref lit) = expr.node {
|
||||
if let LitStr(ref string, _) = lit.node {
|
||||
check_str(cx, string, lit.span)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_str(cx: &Context, string: &str, span: Span) {
|
||||
let mut start: Option<usize> = None;
|
||||
for (i, c) in string.char_indices() {
|
||||
if c == '\u{200B}' {
|
||||
if start.is_none() { start = Some(i); }
|
||||
} else {
|
||||
lint_zero_width(cx, span, start);
|
||||
start = None;
|
||||
}
|
||||
}
|
||||
lint_zero_width(cx, span, start);
|
||||
let mut start: Option<usize> = None;
|
||||
for (i, c) in string.char_indices() {
|
||||
if c == '\u{200B}' {
|
||||
if start.is_none() { start = Some(i); }
|
||||
} else {
|
||||
lint_zero_width(cx, span, start);
|
||||
start = None;
|
||||
}
|
||||
}
|
||||
lint_zero_width(cx, span, start);
|
||||
}
|
||||
|
||||
fn lint_zero_width(cx: &Context, span: Span, start: Option<usize>) {
|
||||
start.map(|index| {
|
||||
span_lint(cx, ZERO_WIDTH_SPACE, Span {
|
||||
lo: span.lo + BytePos(index as u32),
|
||||
hi: span.lo + BytePos(index as u32),
|
||||
expn_id: span.expn_id,
|
||||
}, "Zero-width space detected. Consider using \\u{200B}")
|
||||
});
|
||||
start.map(|index| {
|
||||
span_lint(cx, ZERO_WIDTH_SPACE, Span {
|
||||
lo: span.lo + BytePos(index as u32),
|
||||
hi: span.lo + BytePos(index as u32),
|
||||
expn_id: span.expn_id,
|
||||
}, "Zero-width space detected. Consider using \\u{200B}")
|
||||
});
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ pub fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool {
|
||||
// no span for the callee = external macro
|
||||
info.callee.span.map_or(true, |span| {
|
||||
// no snippet = external macro or compiler-builtin expansion
|
||||
cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code|
|
||||
cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code|
|
||||
// macro doesn't start with "macro_rules"
|
||||
// = compiler plugin
|
||||
!code.starts_with("macro_rules")
|
||||
@ -26,7 +26,7 @@ pub fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool {
|
||||
|
||||
/// invokes in_macro with the expansion info of the given span
|
||||
pub fn in_external_macro(cx: &Context, span: Span) -> bool {
|
||||
cx.sess().codemap().with_expn_info(span.expn_id,
|
||||
cx.sess().codemap().with_expn_info(span.expn_id,
|
||||
|info| in_macro(cx, info))
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ pub fn get_parent_expr<'c>(cx: &'c Context, e: &Expr) -> Option<&'c Expr> {
|
||||
let node_id : NodeId = e.id;
|
||||
let parent_id : NodeId = map.get_parent_node(node_id);
|
||||
if node_id == parent_id { return None; }
|
||||
map.find(parent_id).and_then(|node|
|
||||
map.find(parent_id).and_then(|node|
|
||||
if let NodeExpr(parent) = node { Some(parent) } else { None } )
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ pub fn span_lint(cx: &Context, lint: &'static Lint, sp: Span, msg: &str) {
|
||||
cx.span_lint(lint, sp, msg);
|
||||
}
|
||||
|
||||
pub fn span_help_and_lint(cx: &Context, lint: &'static Lint, span: Span,
|
||||
pub fn span_help_and_lint(cx: &Context, lint: &'static Lint, span: Span,
|
||||
msg: &str, help: &str) {
|
||||
span_lint(cx, lint, span, msg);
|
||||
if cx.current_level(lint) != Level::Allow {
|
||||
|
86
tests/compile-fail/approx_const.rs
Normal file → Executable file
86
tests/compile-fail/approx_const.rs
Normal file → Executable file
@ -4,53 +4,53 @@
|
||||
#[deny(approx_constant)]
|
||||
#[allow(unused)]
|
||||
fn main() {
|
||||
let my_e = 2.7182; //~ERROR
|
||||
let almost_e = 2.718; //~ERROR
|
||||
let no_e = 2.71;
|
||||
|
||||
let my_1_frac_pi = 0.3183; //~ERROR
|
||||
let no_1_frac_pi = 0.31;
|
||||
let my_e = 2.7182; //~ERROR
|
||||
let almost_e = 2.718; //~ERROR
|
||||
let no_e = 2.71;
|
||||
|
||||
let my_frac_1_sqrt_2 = 0.70710678; //~ERROR
|
||||
let almost_frac_1_sqrt_2 = 0.70711; //~ERROR
|
||||
let my_frac_1_sqrt_2 = 0.707;
|
||||
|
||||
let my_frac_2_pi = 0.63661977; //~ERROR
|
||||
let no_frac_2_pi = 0.636;
|
||||
|
||||
let my_frac_2_sq_pi = 1.128379; //~ERROR
|
||||
let no_frac_2_sq_pi = 1.128;
|
||||
let my_1_frac_pi = 0.3183; //~ERROR
|
||||
let no_1_frac_pi = 0.31;
|
||||
|
||||
let my_frac_2_pi = 1.57079632679; //~ERROR
|
||||
let no_frac_2_pi = 1.5705;
|
||||
|
||||
let my_frac_3_pi = 1.04719755119; //~ERROR
|
||||
let no_frac_3_pi = 1.047;
|
||||
|
||||
let my_frac_4_pi = 0.785398163397; //~ERROR
|
||||
let no_frac_4_pi = 0.785;
|
||||
let my_frac_1_sqrt_2 = 0.70710678; //~ERROR
|
||||
let almost_frac_1_sqrt_2 = 0.70711; //~ERROR
|
||||
let my_frac_1_sqrt_2 = 0.707;
|
||||
|
||||
let my_frac_6_pi = 0.523598775598; //~ERROR
|
||||
let no_frac_6_pi = 0.523;
|
||||
let my_frac_2_pi = 0.63661977; //~ERROR
|
||||
let no_frac_2_pi = 0.636;
|
||||
|
||||
let my_frac_8_pi = 0.3926990816987; //~ERROR
|
||||
let no_frac_8_pi = 0.392;
|
||||
let my_frac_2_sq_pi = 1.128379; //~ERROR
|
||||
let no_frac_2_sq_pi = 1.128;
|
||||
|
||||
let my_ln_10 = 2.302585092994046; //~ERROR
|
||||
let no_ln_10 = 2.303;
|
||||
|
||||
let my_ln_2 = 0.6931471805599453; //~ERROR
|
||||
let no_ln_2 = 0.693;
|
||||
let my_frac_2_pi = 1.57079632679; //~ERROR
|
||||
let no_frac_2_pi = 1.5705;
|
||||
|
||||
let my_log10_e = 0.43429448190325176; //~ERROR
|
||||
let no_log10_e = 0.434;
|
||||
|
||||
let my_log2_e = 1.4426950408889634; //~ERROR
|
||||
let no_log2_e = 1.442;
|
||||
|
||||
let my_pi = 3.1415; //~ERROR
|
||||
let almost_pi = 3.141;
|
||||
|
||||
let my_sq2 = 1.4142; //~ERROR
|
||||
let no_sq2 = 1.414;
|
||||
let my_frac_3_pi = 1.04719755119; //~ERROR
|
||||
let no_frac_3_pi = 1.047;
|
||||
|
||||
let my_frac_4_pi = 0.785398163397; //~ERROR
|
||||
let no_frac_4_pi = 0.785;
|
||||
|
||||
let my_frac_6_pi = 0.523598775598; //~ERROR
|
||||
let no_frac_6_pi = 0.523;
|
||||
|
||||
let my_frac_8_pi = 0.3926990816987; //~ERROR
|
||||
let no_frac_8_pi = 0.392;
|
||||
|
||||
let my_ln_10 = 2.302585092994046; //~ERROR
|
||||
let no_ln_10 = 2.303;
|
||||
|
||||
let my_ln_2 = 0.6931471805599453; //~ERROR
|
||||
let no_ln_2 = 0.693;
|
||||
|
||||
let my_log10_e = 0.43429448190325176; //~ERROR
|
||||
let no_log10_e = 0.434;
|
||||
|
||||
let my_log2_e = 1.4426950408889634; //~ERROR
|
||||
let no_log2_e = 1.442;
|
||||
|
||||
let my_pi = 3.1415; //~ERROR
|
||||
let almost_pi = 3.141;
|
||||
|
||||
let my_sq2 = 1.4142; //~ERROR
|
||||
let no_sq2 = 1.414;
|
||||
}
|
||||
|
18
tests/compile-fail/attrs.rs
Normal file → Executable file
18
tests/compile-fail/attrs.rs
Normal file → Executable file
@ -5,29 +5,29 @@
|
||||
|
||||
#[inline(always)] //~ERROR You have declared #[inline(always)] on test_attr_lint.
|
||||
fn test_attr_lint() {
|
||||
assert!(true)
|
||||
assert!(true)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn false_positive_expr() {
|
||||
unreachable!()
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn false_positive_stmt() {
|
||||
unreachable!();
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn empty_and_false_positive_stmt() {
|
||||
;
|
||||
unreachable!();
|
||||
;
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
test_attr_lint();
|
||||
if false { false_positive_expr() }
|
||||
if false { false_positive_stmt() }
|
||||
if false { empty_and_false_positive_stmt() }
|
||||
test_attr_lint();
|
||||
if false { false_positive_expr() }
|
||||
if false { false_positive_stmt() }
|
||||
if false { empty_and_false_positive_stmt() }
|
||||
}
|
||||
|
74
tests/compile-fail/bit_masks.rs
Normal file → Executable file
74
tests/compile-fail/bit_masks.rs
Normal file → Executable file
@ -7,47 +7,47 @@ const EVEN_MORE_REDIRECTION : i64 = THREE_BITS;
|
||||
#[deny(bad_bit_mask)]
|
||||
#[allow(ineffective_bit_mask, identity_op)]
|
||||
fn main() {
|
||||
let x = 5;
|
||||
|
||||
x & 0 == 0; //~ERROR &-masking with zero
|
||||
x & 1 == 1; //ok, distinguishes bit 0
|
||||
x & 1 == 0; //ok, compared with zero
|
||||
x & 2 == 1; //~ERROR
|
||||
x | 0 == 0; //ok, equals x == 0 (maybe warn?)
|
||||
x | 1 == 3; //ok, equals x == 2 || x == 3
|
||||
x | 3 == 3; //ok, equals x <= 3
|
||||
x | 3 == 2; //~ERROR
|
||||
let x = 5;
|
||||
|
||||
x & 1 > 1; //~ERROR
|
||||
x & 2 > 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0
|
||||
x & 2 < 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0
|
||||
x | 1 > 1; // ok (if a bit silly), equals x > 1
|
||||
x | 2 > 1; //~ERROR
|
||||
x | 2 <= 2; // ok (if a bit silly), equals x <= 2
|
||||
|
||||
// this also now works with constants
|
||||
x & THREE_BITS == 8; //~ERROR
|
||||
x | EVEN_MORE_REDIRECTION < 7; //~ERROR
|
||||
|
||||
0 & x == 0; //~ERROR
|
||||
1 | x > 1;
|
||||
|
||||
// and should now also match uncommon usage
|
||||
1 < 2 | x; //~ERROR
|
||||
2 == 3 | x; //~ERROR
|
||||
1 == x & 2; //~ERROR
|
||||
|
||||
x | 1 > 2; // no error, because we allowed ineffective bit masks
|
||||
ineffective();
|
||||
x & 0 == 0; //~ERROR &-masking with zero
|
||||
x & 1 == 1; //ok, distinguishes bit 0
|
||||
x & 1 == 0; //ok, compared with zero
|
||||
x & 2 == 1; //~ERROR
|
||||
x | 0 == 0; //ok, equals x == 0 (maybe warn?)
|
||||
x | 1 == 3; //ok, equals x == 2 || x == 3
|
||||
x | 3 == 3; //ok, equals x <= 3
|
||||
x | 3 == 2; //~ERROR
|
||||
|
||||
x & 1 > 1; //~ERROR
|
||||
x & 2 > 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0
|
||||
x & 2 < 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0
|
||||
x | 1 > 1; // ok (if a bit silly), equals x > 1
|
||||
x | 2 > 1; //~ERROR
|
||||
x | 2 <= 2; // ok (if a bit silly), equals x <= 2
|
||||
|
||||
// this also now works with constants
|
||||
x & THREE_BITS == 8; //~ERROR
|
||||
x | EVEN_MORE_REDIRECTION < 7; //~ERROR
|
||||
|
||||
0 & x == 0; //~ERROR
|
||||
1 | x > 1;
|
||||
|
||||
// and should now also match uncommon usage
|
||||
1 < 2 | x; //~ERROR
|
||||
2 == 3 | x; //~ERROR
|
||||
1 == x & 2; //~ERROR
|
||||
|
||||
x | 1 > 2; // no error, because we allowed ineffective bit masks
|
||||
ineffective();
|
||||
}
|
||||
|
||||
#[deny(ineffective_bit_mask)]
|
||||
#[allow(bad_bit_mask)]
|
||||
fn ineffective() {
|
||||
let x = 5;
|
||||
|
||||
x | 1 > 2; //~ERROR
|
||||
x | 1 < 3; //~ERROR
|
||||
x | 1 <= 3; //~ERROR
|
||||
x | 1 >= 2; //~ERROR
|
||||
let x = 5;
|
||||
|
||||
x | 1 > 2; //~ERROR
|
||||
x | 1 < 3; //~ERROR
|
||||
x | 1 <= 3; //~ERROR
|
||||
x | 1 >= 2; //~ERROR
|
||||
}
|
||||
|
2
tests/compile-fail/box_vec.rs
Normal file → Executable file
2
tests/compile-fail/box_vec.rs
Normal file → Executable file
@ -8,7 +8,7 @@ pub fn test(foo: Box<Vec<bool>>) { //~ ERROR You seem to be trying to use Box<Ve
|
||||
}
|
||||
|
||||
pub fn test2(foo: Box<Fn(Vec<u32>)>) { // pass if #31 is fixed
|
||||
foo(vec![1, 2, 3])
|
||||
foo(vec![1, 2, 3])
|
||||
}
|
||||
|
||||
fn main(){
|
||||
|
28
tests/compile-fail/cmp_nan.rs
Normal file → Executable file
28
tests/compile-fail/cmp_nan.rs
Normal file → Executable file
@ -4,19 +4,19 @@
|
||||
#[deny(cmp_nan)]
|
||||
#[allow(float_cmp)]
|
||||
fn main() {
|
||||
let x = 5f32;
|
||||
x == std::f32::NAN; //~ERROR
|
||||
x != std::f32::NAN; //~ERROR
|
||||
x < std::f32::NAN; //~ERROR
|
||||
x > std::f32::NAN; //~ERROR
|
||||
x <= std::f32::NAN; //~ERROR
|
||||
x >= std::f32::NAN; //~ERROR
|
||||
let x = 5f32;
|
||||
x == std::f32::NAN; //~ERROR
|
||||
x != std::f32::NAN; //~ERROR
|
||||
x < std::f32::NAN; //~ERROR
|
||||
x > std::f32::NAN; //~ERROR
|
||||
x <= std::f32::NAN; //~ERROR
|
||||
x >= std::f32::NAN; //~ERROR
|
||||
|
||||
let y = 0f64;
|
||||
y == std::f64::NAN; //~ERROR
|
||||
y != std::f64::NAN; //~ERROR
|
||||
y < std::f64::NAN; //~ERROR
|
||||
y > std::f64::NAN; //~ERROR
|
||||
y <= std::f64::NAN; //~ERROR
|
||||
y >= std::f64::NAN; //~ERROR
|
||||
let y = 0f64;
|
||||
y == std::f64::NAN; //~ERROR
|
||||
y != std::f64::NAN; //~ERROR
|
||||
y < std::f64::NAN; //~ERROR
|
||||
y > std::f64::NAN; //~ERROR
|
||||
y <= std::f64::NAN; //~ERROR
|
||||
y >= std::f64::NAN; //~ERROR
|
||||
}
|
||||
|
34
tests/compile-fail/cmp_owned.rs
Normal file → Executable file
34
tests/compile-fail/cmp_owned.rs
Normal file → Executable file
@ -3,21 +3,21 @@
|
||||
|
||||
#[deny(cmp_owned)]
|
||||
fn main() {
|
||||
let x = "oh";
|
||||
|
||||
#[allow(str_to_string)]
|
||||
fn with_to_string(x : &str) {
|
||||
x != "foo".to_string(); //~ERROR this creates an owned instance
|
||||
}
|
||||
with_to_string(x);
|
||||
|
||||
x != "foo".to_owned(); //~ERROR this creates an owned instance
|
||||
|
||||
#[allow(deprecated)] // for from_str
|
||||
fn old_timey(x : &str) {
|
||||
x != String::from_str("foo"); //~ERROR this creates an owned instance
|
||||
}
|
||||
old_timey(x);
|
||||
|
||||
x != String::from("foo"); //~ERROR this creates an owned instance
|
||||
let x = "oh";
|
||||
|
||||
#[allow(str_to_string)]
|
||||
fn with_to_string(x : &str) {
|
||||
x != "foo".to_string(); //~ERROR this creates an owned instance
|
||||
}
|
||||
with_to_string(x);
|
||||
|
||||
x != "foo".to_owned(); //~ERROR this creates an owned instance
|
||||
|
||||
#[allow(deprecated)] // for from_str
|
||||
fn old_timey(x : &str) {
|
||||
x != String::from_str("foo"); //~ERROR this creates an owned instance
|
||||
}
|
||||
old_timey(x);
|
||||
|
||||
x != String::from("foo"); //~ERROR this creates an owned instance
|
||||
}
|
||||
|
12
tests/compile-fail/collapsible_if.rs
Normal file → Executable file
12
tests/compile-fail/collapsible_if.rs
Normal file → Executable file
@ -34,10 +34,10 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
if x == "hello" {
|
||||
print!("Hello ");
|
||||
if y == "world" {
|
||||
println!("world!")
|
||||
}
|
||||
}
|
||||
if x == "hello" {
|
||||
print!("Hello ");
|
||||
if y == "world" {
|
||||
println!("world!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
40
tests/compile-fail/eq_op.rs
Normal file → Executable file
40
tests/compile-fail/eq_op.rs
Normal file → Executable file
@ -2,35 +2,35 @@
|
||||
#![plugin(clippy)]
|
||||
|
||||
fn id<X>(x: X) -> X {
|
||||
x
|
||||
x
|
||||
}
|
||||
|
||||
#[deny(eq_op)]
|
||||
#[allow(identity_op)]
|
||||
fn main() {
|
||||
// simple values and comparisons
|
||||
1 == 1; //~ERROR
|
||||
"no" == "no"; //~ERROR
|
||||
// even though I agree that no means no ;-)
|
||||
false != false; //~ERROR
|
||||
1.5 < 1.5; //~ERROR
|
||||
1u64 >= 1u64; //~ERROR
|
||||
|
||||
// casts, methods, parenthesis
|
||||
(1 as u64) & (1 as u64); //~ERROR
|
||||
1 ^ ((((((1)))))); //~ERROR
|
||||
id((1)) | id(1); //~ERROR
|
||||
|
||||
// unary and binary operators
|
||||
(-(2) < -(2)); //~ERROR
|
||||
// simple values and comparisons
|
||||
1 == 1; //~ERROR
|
||||
"no" == "no"; //~ERROR
|
||||
// even though I agree that no means no ;-)
|
||||
false != false; //~ERROR
|
||||
1.5 < 1.5; //~ERROR
|
||||
1u64 >= 1u64; //~ERROR
|
||||
|
||||
// casts, methods, parenthesis
|
||||
(1 as u64) & (1 as u64); //~ERROR
|
||||
1 ^ ((((((1)))))); //~ERROR
|
||||
id((1)) | id(1); //~ERROR
|
||||
|
||||
// unary and binary operators
|
||||
(-(2) < -(2)); //~ERROR
|
||||
((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
|
||||
//~^ ERROR
|
||||
//~^^ ERROR
|
||||
//~^^^ ERROR
|
||||
(1 * 2) + (3 * 4) == 1 * 2 + 3 * 4; //~ERROR
|
||||
|
||||
// various other things
|
||||
([1] != [1]); //~ERROR
|
||||
(1 * 2) + (3 * 4) == 1 * 2 + 3 * 4; //~ERROR
|
||||
|
||||
// various other things
|
||||
([1] != [1]); //~ERROR
|
||||
((1, 2) != (1, 2)); //~ERROR
|
||||
[1].len() == [1].len(); //~ERROR
|
||||
vec![1, 2, 3] == vec![1, 2, 3]; //no error yet, as we don't match macros
|
||||
|
40
tests/compile-fail/float_cmp.rs
Normal file → Executable file
40
tests/compile-fail/float_cmp.rs
Normal file → Executable file
@ -7,29 +7,29 @@ const ZERO : f32 = 0.0;
|
||||
const ONE : f32 = ZERO + 1.0;
|
||||
|
||||
fn twice<T>(x : T) -> T where T : Add<T, Output = T>, T : Copy {
|
||||
x + x
|
||||
x + x
|
||||
}
|
||||
|
||||
#[deny(float_cmp)]
|
||||
#[allow(unused)]
|
||||
fn main() {
|
||||
ZERO == 0f32; //~ERROR
|
||||
ZERO == 0.0; //~ERROR
|
||||
ZERO + ZERO != 1.0; //~ERROR
|
||||
|
||||
ONE != 0.0; //~ERROR
|
||||
twice(ONE) != ONE; //~ERROR
|
||||
ONE as f64 != 0.0; //~ERROR
|
||||
|
||||
let x : f64 = 1.0;
|
||||
|
||||
x == 1.0; //~ERROR
|
||||
x != 0f64; //~ERROR
|
||||
|
||||
twice(x) != twice(ONE as f64); //~ERROR
|
||||
|
||||
x < 0.0;
|
||||
x > 0.0;
|
||||
x <= 0.0;
|
||||
x >= 0.0;
|
||||
ZERO == 0f32; //~ERROR
|
||||
ZERO == 0.0; //~ERROR
|
||||
ZERO + ZERO != 1.0; //~ERROR
|
||||
|
||||
ONE != 0.0; //~ERROR
|
||||
twice(ONE) != ONE; //~ERROR
|
||||
ONE as f64 != 0.0; //~ERROR
|
||||
|
||||
let x : f64 = 1.0;
|
||||
|
||||
x == 1.0; //~ERROR
|
||||
x != 0f64; //~ERROR
|
||||
|
||||
twice(x) != twice(ONE as f64); //~ERROR
|
||||
|
||||
x < 0.0;
|
||||
x > 0.0;
|
||||
x <= 0.0;
|
||||
x >= 0.0;
|
||||
}
|
||||
|
28
tests/compile-fail/identity_op.rs
Normal file → Executable file
28
tests/compile-fail/identity_op.rs
Normal file → Executable file
@ -7,18 +7,18 @@ const ZERO : i64 = 0;
|
||||
|
||||
#[deny(identity_op)]
|
||||
fn main() {
|
||||
let x = 0;
|
||||
|
||||
x + 0; //~ERROR
|
||||
0 + x; //~ERROR
|
||||
x - ZERO; //~ERROR
|
||||
x | (0); //~ERROR
|
||||
((ZERO)) | x; //~ERROR
|
||||
|
||||
x * 1; //~ERROR
|
||||
1 * x; //~ERROR
|
||||
x / ONE; //~ERROR
|
||||
|
||||
x & NEG_ONE; //~ERROR
|
||||
-1 & x; //~ERROR
|
||||
let x = 0;
|
||||
|
||||
x + 0; //~ERROR
|
||||
0 + x; //~ERROR
|
||||
x - ZERO; //~ERROR
|
||||
x | (0); //~ERROR
|
||||
((ZERO)) | x; //~ERROR
|
||||
|
||||
x * 1; //~ERROR
|
||||
1 * x; //~ERROR
|
||||
x / ONE; //~ERROR
|
||||
|
||||
x & NEG_ONE; //~ERROR
|
||||
-1 & x; //~ERROR
|
||||
}
|
||||
|
120
tests/compile-fail/len_zero.rs
Normal file → Executable file
120
tests/compile-fail/len_zero.rs
Normal file → Executable file
@ -5,98 +5,98 @@ struct One;
|
||||
|
||||
#[deny(len_without_is_empty)]
|
||||
impl One {
|
||||
fn len(self: &Self) -> isize { //~ERROR Item 'One' has a '.len(_: &Self)'
|
||||
1
|
||||
}
|
||||
fn len(self: &Self) -> isize { //~ERROR Item 'One' has a '.len(_: &Self)'
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
#[deny(len_without_is_empty)]
|
||||
trait TraitsToo {
|
||||
fn len(self: &Self) -> isize; //~ERROR Trait 'TraitsToo' has a '.len(_:
|
||||
fn len(self: &Self) -> isize; //~ERROR Trait 'TraitsToo' has a '.len(_:
|
||||
}
|
||||
|
||||
impl TraitsToo for One {
|
||||
fn len(self: &Self) -> isize {
|
||||
0
|
||||
}
|
||||
fn len(self: &Self) -> isize {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
struct HasIsEmpty;
|
||||
|
||||
#[deny(len_without_is_empty)]
|
||||
impl HasIsEmpty {
|
||||
fn len(self: &Self) -> isize {
|
||||
1
|
||||
}
|
||||
fn len(self: &Self) -> isize {
|
||||
1
|
||||
}
|
||||
|
||||
fn is_empty(self: &Self) -> bool {
|
||||
false
|
||||
}
|
||||
fn is_empty(self: &Self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
struct Wither;
|
||||
|
||||
#[deny(len_without_is_empty)]
|
||||
trait WithIsEmpty {
|
||||
fn len(self: &Self) -> isize;
|
||||
fn is_empty(self: &Self) -> bool;
|
||||
fn len(self: &Self) -> isize;
|
||||
fn is_empty(self: &Self) -> bool;
|
||||
}
|
||||
|
||||
impl WithIsEmpty for Wither {
|
||||
fn len(self: &Self) -> isize {
|
||||
1
|
||||
}
|
||||
fn len(self: &Self) -> isize {
|
||||
1
|
||||
}
|
||||
|
||||
fn is_empty(self: &Self) -> bool {
|
||||
false
|
||||
}
|
||||
fn is_empty(self: &Self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
struct HasWrongIsEmpty;
|
||||
|
||||
#[deny(len_without_is_empty)]
|
||||
impl HasWrongIsEmpty {
|
||||
fn len(self: &Self) -> isize { //~ERROR Item 'HasWrongIsEmpty' has a '.len(_: &Self)'
|
||||
1
|
||||
}
|
||||
|
||||
#[allow(dead_code, unused)]
|
||||
fn is_empty(self: &Self, x : u32) -> bool {
|
||||
false
|
||||
}
|
||||
fn len(self: &Self) -> isize { //~ERROR Item 'HasWrongIsEmpty' has a '.len(_: &Self)'
|
||||
1
|
||||
}
|
||||
|
||||
#[allow(dead_code, unused)]
|
||||
fn is_empty(self: &Self, x : u32) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[deny(len_zero)]
|
||||
fn main() {
|
||||
let x = [1, 2];
|
||||
if x.len() == 0 { //~ERROR Consider replacing the len comparison
|
||||
println!("This should not happen!");
|
||||
}
|
||||
|
||||
let y = One;
|
||||
if y.len() == 0 { //no error because One does not have .is_empty()
|
||||
println!("This should not happen either!");
|
||||
}
|
||||
|
||||
let z : &TraitsToo = &y;
|
||||
if z.len() > 0 { //no error, because TraitsToo has no .is_empty() method
|
||||
println!("Nor should this!");
|
||||
}
|
||||
|
||||
let hie = HasIsEmpty;
|
||||
if hie.len() == 0 { //~ERROR Consider replacing the len comparison
|
||||
println!("Or this!");
|
||||
}
|
||||
assert!(!hie.is_empty());
|
||||
|
||||
let wie : &WithIsEmpty = &Wither;
|
||||
if wie.len() == 0 { //~ERROR Consider replacing the len comparison
|
||||
println!("Or this!");
|
||||
}
|
||||
assert!(!wie.is_empty());
|
||||
|
||||
let hwie = HasWrongIsEmpty;
|
||||
if hwie.len() == 0 { //no error as HasWrongIsEmpty does not have .is_empty()
|
||||
println!("Or this!");
|
||||
}
|
||||
let x = [1, 2];
|
||||
if x.len() == 0 { //~ERROR Consider replacing the len comparison
|
||||
println!("This should not happen!");
|
||||
}
|
||||
|
||||
let y = One;
|
||||
if y.len() == 0 { //no error because One does not have .is_empty()
|
||||
println!("This should not happen either!");
|
||||
}
|
||||
|
||||
let z : &TraitsToo = &y;
|
||||
if z.len() > 0 { //no error, because TraitsToo has no .is_empty() method
|
||||
println!("Nor should this!");
|
||||
}
|
||||
|
||||
let hie = HasIsEmpty;
|
||||
if hie.len() == 0 { //~ERROR Consider replacing the len comparison
|
||||
println!("Or this!");
|
||||
}
|
||||
assert!(!hie.is_empty());
|
||||
|
||||
let wie : &WithIsEmpty = &Wither;
|
||||
if wie.len() == 0 { //~ERROR Consider replacing the len comparison
|
||||
println!("Or this!");
|
||||
}
|
||||
assert!(!wie.is_empty());
|
||||
|
||||
let hwie = HasWrongIsEmpty;
|
||||
if hwie.len() == 0 { //no error as HasWrongIsEmpty does not have .is_empty()
|
||||
println!("Or this!");
|
||||
}
|
||||
}
|
||||
|
36
tests/compile-fail/mut_mut.rs
Normal file → Executable file
36
tests/compile-fail/mut_mut.rs
Normal file → Executable file
@ -6,29 +6,29 @@
|
||||
|
||||
#[deny(mut_mut)]
|
||||
fn fun(x : &mut &mut u32) -> bool { //~ERROR
|
||||
**x > 0
|
||||
**x > 0
|
||||
}
|
||||
|
||||
macro_rules! mut_ptr {
|
||||
($p:expr) => { &mut $p }
|
||||
}
|
||||
($p:expr) => { &mut $p }
|
||||
}
|
||||
|
||||
#[deny(mut_mut)]
|
||||
#[allow(unused_mut, unused_variables)]
|
||||
fn main() {
|
||||
let mut x = &mut &mut 1u32; //~ERROR
|
||||
{
|
||||
let mut y = &mut x; //~ERROR
|
||||
}
|
||||
|
||||
if fun(x) {
|
||||
let y : &mut &mut &mut u32 = &mut &mut &mut 2;
|
||||
//~^ ERROR
|
||||
//~^^ ERROR
|
||||
//~^^^ ERROR
|
||||
//~^^^^ ERROR
|
||||
***y + **x;
|
||||
}
|
||||
|
||||
let mut z = mut_ptr!(&mut 3u32); //~ERROR
|
||||
let mut x = &mut &mut 1u32; //~ERROR
|
||||
{
|
||||
let mut y = &mut x; //~ERROR
|
||||
}
|
||||
|
||||
if fun(x) {
|
||||
let y : &mut &mut &mut u32 = &mut &mut &mut 2;
|
||||
//~^ ERROR
|
||||
//~^^ ERROR
|
||||
//~^^^ ERROR
|
||||
//~^^^^ ERROR
|
||||
***y + **x;
|
||||
}
|
||||
|
||||
let mut z = mut_ptr!(&mut 3u32); //~ERROR
|
||||
}
|
||||
|
12
tests/compile-fail/needless_bool.rs
Normal file → Executable file
12
tests/compile-fail/needless_bool.rs
Normal file → Executable file
@ -3,10 +3,10 @@
|
||||
|
||||
#[deny(needless_bool)]
|
||||
fn main() {
|
||||
let x = true;
|
||||
if x { true } else { true }; //~ERROR
|
||||
if x { false } else { false }; //~ERROR
|
||||
if x { true } else { false }; //~ERROR
|
||||
if x { false } else { true }; //~ERROR
|
||||
if x { x } else { false }; // would also be questionable, but we don't catch this yet
|
||||
let x = true;
|
||||
if x { true } else { true }; //~ERROR
|
||||
if x { false } else { false }; //~ERROR
|
||||
if x { true } else { false }; //~ERROR
|
||||
if x { false } else { true }; //~ERROR
|
||||
if x { x } else { false }; // would also be questionable, but we don't catch this yet
|
||||
}
|
||||
|
2
tests/compile-fail/precedence.rs
Normal file → Executable file
2
tests/compile-fail/precedence.rs
Normal file → Executable file
@ -4,7 +4,7 @@
|
||||
#[deny(precedence)]
|
||||
#[allow(eq_op)]
|
||||
fn main() {
|
||||
format!("{} vs. {}", 1 << 2 + 3, (1 << 2) + 3); //~ERROR
|
||||
format!("{} vs. {}", 1 << 2 + 3, (1 << 2) + 3); //~ERROR
|
||||
format!("{} vs. {}", 1 + 2 << 3, 1 + (2 << 3)); //~ERROR
|
||||
format!("{} vs. {}", 4 >> 1 + 1, (4 >> 1) + 1); //~ERROR
|
||||
format!("{} vs. {}", 1 + 3 >> 2, 1 + (3 >> 2)); //~ERROR
|
||||
|
10
tests/compile-fail/ptr_arg.rs
Normal file → Executable file
10
tests/compile-fail/ptr_arg.rs
Normal file → Executable file
@ -4,17 +4,17 @@
|
||||
#[deny(ptr_arg)]
|
||||
#[allow(unused)]
|
||||
fn do_vec(x: &Vec<i64>) { //~ERROR: Writing '&Vec<_>' instead of '&[_]'
|
||||
//Nothing here
|
||||
//Nothing here
|
||||
}
|
||||
|
||||
#[deny(ptr_arg)]
|
||||
#[allow(unused)]
|
||||
fn do_str(x: &String) { //~ERROR
|
||||
//Nothing here either
|
||||
//Nothing here either
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = vec![1i64, 2, 3];
|
||||
do_vec(&x);
|
||||
do_str(&"hello".to_owned());
|
||||
let x = vec![1i64, 2, 3];
|
||||
do_vec(&x);
|
||||
do_str(&"hello".to_owned());
|
||||
}
|
||||
|
10
tests/compile-fail/strings.rs
Normal file → Executable file
10
tests/compile-fail/strings.rs
Normal file → Executable file
@ -4,9 +4,9 @@
|
||||
#![deny(string_add_assign)]
|
||||
|
||||
fn main() {
|
||||
let x = "".to_owned();
|
||||
|
||||
for i in (1..3) {
|
||||
x = x + "."; //~ERROR
|
||||
}
|
||||
let x = "".to_owned();
|
||||
|
||||
for i in (1..3) {
|
||||
x = x + "."; //~ERROR
|
||||
}
|
||||
}
|
||||
|
16
tests/compile-fail/unicode.rs
Normal file → Executable file
16
tests/compile-fail/unicode.rs
Normal file → Executable file
@ -3,23 +3,23 @@
|
||||
|
||||
#[deny(zero_width_space)]
|
||||
fn zero() {
|
||||
print!("Here >< is a ZWS, and another");
|
||||
//~^ ERROR Zero-width space detected. Consider using \u{200B}
|
||||
//~^^ ERROR Zero-width space detected. Consider using \u{200B}
|
||||
print!("Here >< is a ZWS, and another");
|
||||
//~^ ERROR Zero-width space detected. Consider using \u{200B}
|
||||
//~^^ ERROR Zero-width space detected. Consider using \u{200B}
|
||||
}
|
||||
|
||||
//#[deny(unicode_canon)]
|
||||
fn canon() {
|
||||
print!("̀ah?"); //not yet ~ERROR Non-canonical unicode sequence detected. Consider using à
|
||||
print!("̀ah?"); //not yet ~ERROR Non-canonical unicode sequence detected. Consider using à
|
||||
}
|
||||
|
||||
//#[deny(ascii_only)]
|
||||
fn uni() {
|
||||
println!("Üben!"); //not yet ~ERROR Unicode literal detected. Consider using \u{FC}
|
||||
println!("Üben!"); //not yet ~ERROR Unicode literal detected. Consider using \u{FC}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
zero();
|
||||
uni();
|
||||
canon();
|
||||
zero();
|
||||
uni();
|
||||
canon();
|
||||
}
|
||||
|
@ -5,13 +5,13 @@ use std::env::var;
|
||||
|
||||
fn run_mode(mode: &'static str) {
|
||||
let mut config = compiletest::default_config();
|
||||
|
||||
|
||||
let cfg_mode = mode.parse().ok().expect("Invalid mode");
|
||||
config.target_rustcflags = Some("-L target/debug/".to_owned());
|
||||
if let Ok(name) = var::<&str>("TESTNAME") {
|
||||
let s : String = name.to_owned();
|
||||
config.filter = Some(s)
|
||||
}
|
||||
if let Ok(name) = var::<&str>("TESTNAME") {
|
||||
let s : String = name.to_owned();
|
||||
config.filter = Some(s)
|
||||
}
|
||||
|
||||
config.mode = cfg_mode;
|
||||
config.src_base = PathBuf::from(format!("tests/{}", mode));
|
||||
|
24
tests/mut_mut_macro.rs
Normal file → Executable file
24
tests/mut_mut_macro.rs
Normal file → Executable file
@ -10,22 +10,22 @@ use std::collections::HashMap;
|
||||
#[test]
|
||||
#[deny(mut_mut)]
|
||||
fn test_regex() {
|
||||
let pattern = regex!(r"^(?P<level>[#]+)\s(?P<title>.+)$");
|
||||
assert!(pattern.is_match("# headline"));
|
||||
let pattern = regex!(r"^(?P<level>[#]+)\s(?P<title>.+)$");
|
||||
assert!(pattern.is_match("# headline"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[deny(mut_mut)]
|
||||
#[allow(unused_variables, unused_mut)]
|
||||
fn test_lazy_static() {
|
||||
lazy_static! {
|
||||
static ref MUT_MAP : HashMap<usize, &'static str> = {
|
||||
let mut m = HashMap::new();
|
||||
let mut zero = &mut &mut "zero";
|
||||
m.insert(0, "zero");
|
||||
m
|
||||
};
|
||||
static ref MUT_COUNT : usize = MUT_MAP.len();
|
||||
}
|
||||
assert!(*MUT_COUNT == 1);
|
||||
lazy_static! {
|
||||
static ref MUT_MAP : HashMap<usize, &'static str> = {
|
||||
let mut m = HashMap::new();
|
||||
let mut zero = &mut &mut "zero";
|
||||
m.insert(0, "zero");
|
||||
m
|
||||
};
|
||||
static ref MUT_COUNT : usize = MUT_MAP.len();
|
||||
}
|
||||
assert!(*MUT_COUNT == 1);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user