Merge pull request #128 from birkenfeld/whitespace-cleanup

all: whitespace cleanup
This commit is contained in:
Manish Goregaokar 2015-08-12 00:36:21 +05:30
commit cadd9bb954
34 changed files with 852 additions and 852 deletions

View File

@ -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:
```

View File

@ -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
}

View File

@ -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()));
}
}
}
}

View File

@ -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
}
}

View File

@ -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 {

View File

@ -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
}

View File

@ -58,4 +58,3 @@ impl LintPass for EtaPass {
}
}
}

View File

@ -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

View File

@ -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,
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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 &[...]"))
}

View File

@ -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

View File

@ -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}")
});
}

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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();
}

View File

@ -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
View 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);
}