mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-27 15:11:30 +00:00
Merge branch 'pr-152'
Conflicts: README.md src/lib.rs src/strings.rs
This commit is contained in:
commit
1d64553bc6
22 changed files with 238 additions and 97 deletions
67
README.md
67
README.md
|
@ -6,36 +6,43 @@ A collection of lints that give helpful tips to newbies and catch oversights.
|
||||||
##Lints
|
##Lints
|
||||||
Lints included in this crate:
|
Lints included in this crate:
|
||||||
|
|
||||||
- `single_match`: Warns when a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used, and recommends `if let` instead.
|
name | default | meaning
|
||||||
- `box_vec`: Warns on usage of `Box<Vec<T>>`
|
---------------------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
- `linkedlist`: Warns on usage of `LinkedList`
|
approx_constant | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant
|
||||||
- `str_to_string`: Warns on usage of `str::to_string()`
|
bad_bit_mask | deny | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have)
|
||||||
- `toplevel_ref_arg`: Warns when a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`)
|
box_vec | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap
|
||||||
- `eq_op`: Warns on equal operands on both sides of a comparison or bitwise combination
|
cmp_nan | deny | comparisons to NAN (which will always return false, which is probably not intended)
|
||||||
- `bad_bit_mask`: Denies expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have)
|
cmp_owned | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()`
|
||||||
- `ineffective_bit_mask`: Warns on expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2`
|
collapsible_if | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }`
|
||||||
- `needless_bool` : Warns on if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }`
|
eq_op | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`)
|
||||||
- `ptr_arg`: Warns on fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively
|
float_cmp | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds)
|
||||||
- `approx_constant`: Warns if the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found and suggests to use the constant
|
identity_op | warn | using identity operations, e.g. `x + 0` or `y / 1`
|
||||||
- `cmp_nan`: Denies comparisons to NAN (which will always return false, which is probably not intended)
|
ineffective_bit_mask | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2`
|
||||||
- `float_cmp`: Warns on `==` or `!=` comparisons of floaty typed values. As floating-point operations usually involve rounding errors, it is always better to check for approximate equality within some small bounds
|
inline_always | warn | `#[inline(always)]` is a bad idea in most cases
|
||||||
- `precedence`: Warns on expressions where precedence may trip up the unwary reader of the source and suggests adding parenthesis, e.g. `x << 2 + y` will be parsed as `x << (2 + y)`
|
len_without_is_empty | warn | traits and impls that have `.len()` but not `.is_empty()`
|
||||||
- `redundant_closure`: Warns on usage of eta-reducible closures like `|a| foo(a)` (which can be written as just `foo`)
|
len_zero | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead
|
||||||
- `identity_op`: Warns on identity operations like `x + 0` or `y / 1` (which can be reduced to `x` and `y`, respectively)
|
let_and_return | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a function
|
||||||
- `mut_mut`: Warns on `&mut &mut` which is either a copy'n'paste error, or shows a fundamental misunderstanding of references
|
let_unit_value | warn | creating a let binding to a value of unit type, which usually can't be used afterwards
|
||||||
- `len_zero`: Warns on `_.len() == 0` and suggests using `_.is_empty()` (or similar comparisons with `>` or `!=`)
|
linkedlist | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a RingBuf
|
||||||
- `len_without_is_empty`: Warns on traits or impls that have a `.len()` but no `.is_empty()` method
|
modulo_one | warn | taking a number modulo 1, which always returns 0
|
||||||
- `cmp_owned`: Warns on creating owned instances for comparing with others, e.g. `x == "foo".to_string()`
|
mut_mut | warn | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references)
|
||||||
- `inline_always`: Warns on `#[inline(always)]`, because in most cases it is a bad idea
|
needless_bool | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }`
|
||||||
- `collapsible_if`: Warns on cases where two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }`
|
needless_lifetimes | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them
|
||||||
- `zero_width_space`: Warns on encountering a unicode zero-width space
|
needless_range_loop | warn | for-looping over a range of indices where an iterator over items would do
|
||||||
- `string_add_assign`: Warns on `x = x + ..` where `x` is a `String` and suggests using `push_str(..)` instead. Allowed by default.
|
needless_return | warn | using a return statement like `return expr;` where an expression would suffice
|
||||||
- `string_add`: Matches `x + ..` where `x` is a `String` and where `string_add_assign` doesn't warn. Allowed by default.
|
non_ascii_literal | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead
|
||||||
- `needless_return`: Warns on using `return expr;` when a simple `expr` would suffice.
|
option_unwrap_used | warn | using `Option.unwrap()`, which should at least get a better message using `expect()`
|
||||||
- `let_and_return`: Warns on doing `let x = expr; x` at the end of a function.
|
precedence | warn | expressions where precedence may trip up the unwary reader of the source; suggests adding parentheses, e.g. `x << 2 + y` will be parsed as `x << (2 + y)`
|
||||||
- `option_unwrap_used`: Warns when `Option.unwrap()` is used, and suggests `.expect()`.
|
ptr_arg | allow | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively
|
||||||
- `result_unwrap_used`: Warns when `Result.unwrap()` is used (silent by default).
|
redundant_closure | warn | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`)
|
||||||
- `modulo_one`: Warns on taking a number modulo 1, which always has a result of 0.
|
result_unwrap_used | allow | using `Result.unwrap()`, which might be better handled
|
||||||
|
single_match | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead
|
||||||
|
str_to_string | warn | using `to_string()` on a str, which should be `to_owned()`
|
||||||
|
string_add | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead
|
||||||
|
string_add_assign | allow | expressions of the form `x = x + ..` where x is a `String`
|
||||||
|
string_to_string | warn | calling `String.to_string()` which is a no-op
|
||||||
|
toplevel_ref_arg | warn | a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`)
|
||||||
|
zero_width_space | deny | using a zero-width space in a string literal, which is confusing
|
||||||
|
|
||||||
To use, add the following lines to your Cargo.toml:
|
To use, add the following lines to your Cargo.toml:
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,8 @@ use utils::span_lint;
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
pub APPROX_CONSTANT,
|
pub APPROX_CONSTANT,
|
||||||
Warn,
|
Warn,
|
||||||
"Warn if a user writes an approximate known constant in their code"
|
"the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) \
|
||||||
|
is found; suggests to use the constant"
|
||||||
}
|
}
|
||||||
|
|
||||||
const KNOWN_CONSTS : &'static [(f64, &'static str)] = &[(f64::E, "E"), (f64::FRAC_1_PI, "FRAC_1_PI"),
|
const KNOWN_CONSTS : &'static [(f64, &'static str)] = &[(f64::E, "E"), (f64::FRAC_1_PI, "FRAC_1_PI"),
|
||||||
|
|
|
@ -9,7 +9,7 @@ use syntax::parse::token::InternedString;
|
||||||
use utils::{in_macro, match_path, span_lint};
|
use utils::{in_macro, match_path, span_lint};
|
||||||
|
|
||||||
declare_lint! { pub INLINE_ALWAYS, Warn,
|
declare_lint! { pub INLINE_ALWAYS, Warn,
|
||||||
"#[inline(always)] is usually a bad idea."}
|
"`#[inline(always)]` is a bad idea in most cases" }
|
||||||
|
|
||||||
|
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
|
|
|
@ -11,15 +11,14 @@ use utils::span_lint;
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
pub BAD_BIT_MASK,
|
pub BAD_BIT_MASK,
|
||||||
Deny,
|
Deny,
|
||||||
"Deny the use of incompatible bit masks in comparisons, e.g. \
|
"expressions of the form `_ & mask == select` that will only ever return `true` or `false` \
|
||||||
'(a & 1) == 2'"
|
(because in the example `select` containing bits that `mask` doesn't have)"
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
pub INEFFECTIVE_BIT_MASK,
|
pub INEFFECTIVE_BIT_MASK,
|
||||||
Warn,
|
Warn,
|
||||||
"Warn on the use of an ineffective bit mask in comparisons, e.g. \
|
"expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2`"
|
||||||
'(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`.
|
||||||
|
|
|
@ -23,7 +23,8 @@ use utils::{in_macro, span_help_and_lint, snippet};
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
pub COLLAPSIBLE_IF,
|
pub COLLAPSIBLE_IF,
|
||||||
Warn,
|
Warn,
|
||||||
"Warn on if expressions that can be collapsed"
|
"two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` \
|
||||||
|
can be written as `if x && y { foo() }`"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
|
|
|
@ -8,7 +8,7 @@ use utils::span_lint;
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
pub EQ_OP,
|
pub EQ_OP,
|
||||||
Warn,
|
Warn,
|
||||||
"warn about comparing equal expressions (e.g. x == x)"
|
"equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`)"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
|
|
|
@ -11,7 +11,7 @@ pub struct EtaPass;
|
||||||
|
|
||||||
|
|
||||||
declare_lint!(pub REDUNDANT_CLOSURE, Warn,
|
declare_lint!(pub REDUNDANT_CLOSURE, Warn,
|
||||||
"Warn on usage of redundant closures, i.e. `|a| foo(a)`");
|
"using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`)");
|
||||||
|
|
||||||
impl LintPass for EtaPass {
|
impl LintPass for EtaPass {
|
||||||
fn get_lints(&self) -> LintArray {
|
fn get_lints(&self) -> LintArray {
|
||||||
|
|
|
@ -10,7 +10,7 @@ use syntax::codemap::Span;
|
||||||
use utils::{span_lint, snippet};
|
use utils::{span_lint, snippet};
|
||||||
|
|
||||||
declare_lint! { pub IDENTITY_OP, Warn,
|
declare_lint! { pub IDENTITY_OP, Warn,
|
||||||
"Warn on identity operations, e.g. '_ + 0'"}
|
"using identity operations, e.g. `x + 0` or `y / 1`" }
|
||||||
|
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
pub struct IdentityOp;
|
pub struct IdentityOp;
|
||||||
|
|
|
@ -12,10 +12,11 @@ use syntax::ast::*;
|
||||||
use utils::{span_lint, walk_ptrs_ty, snippet};
|
use utils::{span_lint, walk_ptrs_ty, snippet};
|
||||||
|
|
||||||
declare_lint!(pub LEN_ZERO, Warn,
|
declare_lint!(pub LEN_ZERO, Warn,
|
||||||
"Warn when .is_empty() could be used instead of checking .len()");
|
"checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \
|
||||||
|
could be used instead");
|
||||||
|
|
||||||
declare_lint!(pub LEN_WITHOUT_IS_EMPTY, Warn,
|
declare_lint!(pub LEN_WITHOUT_IS_EMPTY, Warn,
|
||||||
"Warn on traits and impls that have .len() but not .is_empty()");
|
"traits and impls that have `.len()` but not `.is_empty()`");
|
||||||
|
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
pub struct LenZero;
|
pub struct LenZero;
|
||||||
|
|
46
src/lib.rs
46
src/lib.rs
|
@ -64,35 +64,41 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
||||||
reg.register_lint_pass(box loops::LoopsPass as LintPassObject);
|
reg.register_lint_pass(box loops::LoopsPass as LintPassObject);
|
||||||
reg.register_lint_pass(box lifetimes::LifetimePass as LintPassObject);
|
reg.register_lint_pass(box lifetimes::LifetimePass as LintPassObject);
|
||||||
|
|
||||||
reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST,
|
reg.register_lint_group("clippy", vec![
|
||||||
misc::SINGLE_MATCH,
|
approx_const::APPROX_CONSTANT,
|
||||||
misc::TOPLEVEL_REF_ARG, eq_op::EQ_OP,
|
attrs::INLINE_ALWAYS,
|
||||||
bit_mask::BAD_BIT_MASK,
|
bit_mask::BAD_BIT_MASK,
|
||||||
bit_mask::INEFFECTIVE_BIT_MASK,
|
bit_mask::INEFFECTIVE_BIT_MASK,
|
||||||
ptr_arg::PTR_ARG,
|
collapsible_if::COLLAPSIBLE_IF,
|
||||||
needless_bool::NEEDLESS_BOOL,
|
eq_op::EQ_OP,
|
||||||
approx_const::APPROX_CONSTANT,
|
|
||||||
misc::CMP_NAN, misc::FLOAT_CMP,
|
|
||||||
misc::PRECEDENCE, misc::CMP_OWNED,
|
|
||||||
eta_reduction::REDUNDANT_CLOSURE,
|
eta_reduction::REDUNDANT_CLOSURE,
|
||||||
identity_op::IDENTITY_OP,
|
identity_op::IDENTITY_OP,
|
||||||
mut_mut::MUT_MUT,
|
|
||||||
len_zero::LEN_ZERO,
|
|
||||||
len_zero::LEN_WITHOUT_IS_EMPTY,
|
len_zero::LEN_WITHOUT_IS_EMPTY,
|
||||||
attrs::INLINE_ALWAYS,
|
len_zero::LEN_ZERO,
|
||||||
collapsible_if::COLLAPSIBLE_IF,
|
lifetimes::NEEDLESS_LIFETIMES,
|
||||||
unicode::ZERO_WIDTH_SPACE,
|
loops::NEEDLESS_RANGE_LOOP,
|
||||||
unicode::NON_ASCII_LITERAL,
|
|
||||||
strings::STRING_ADD_ASSIGN,
|
|
||||||
strings::STRING_ADD,
|
|
||||||
returns::NEEDLESS_RETURN,
|
|
||||||
misc::MODULO_ONE,
|
|
||||||
methods::OPTION_UNWRAP_USED,
|
methods::OPTION_UNWRAP_USED,
|
||||||
methods::RESULT_UNWRAP_USED,
|
methods::RESULT_UNWRAP_USED,
|
||||||
methods::STR_TO_STRING,
|
methods::STR_TO_STRING,
|
||||||
methods::STRING_TO_STRING,
|
methods::STRING_TO_STRING,
|
||||||
|
misc::CMP_NAN,
|
||||||
|
misc::CMP_OWNED,
|
||||||
|
misc::FLOAT_CMP,
|
||||||
|
misc::MODULO_ONE,
|
||||||
|
misc::PRECEDENCE,
|
||||||
|
misc::SINGLE_MATCH,
|
||||||
|
misc::TOPLEVEL_REF_ARG,
|
||||||
|
mut_mut::MUT_MUT,
|
||||||
|
needless_bool::NEEDLESS_BOOL,
|
||||||
|
ptr_arg::PTR_ARG,
|
||||||
|
returns::LET_AND_RETURN,
|
||||||
|
returns::NEEDLESS_RETURN,
|
||||||
|
strings::STRING_ADD,
|
||||||
|
strings::STRING_ADD_ASSIGN,
|
||||||
|
types::BOX_VEC,
|
||||||
types::LET_UNIT_VALUE,
|
types::LET_UNIT_VALUE,
|
||||||
lifetimes::NEEDLESS_LIFETIMES,
|
types::LINKEDLIST,
|
||||||
loops::NEEDLESS_RANGE_LOOP,
|
unicode::NON_ASCII_LITERAL,
|
||||||
|
unicode::ZERO_WIDTH_SPACE,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,8 @@ use std::collections::HashSet;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
declare_lint!(pub NEEDLESS_LIFETIMES, Warn,
|
declare_lint!(pub NEEDLESS_LIFETIMES, Warn,
|
||||||
"Warn on explicit lifetimes when elision rules would apply");
|
"using explicit lifetimes for references in function arguments when elision rules \
|
||||||
|
would allow omitting them");
|
||||||
|
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
pub struct LifetimePass;
|
pub struct LifetimePass;
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::collections::HashSet;
|
||||||
use utils::{span_lint, get_parent_expr};
|
use utils::{span_lint, get_parent_expr};
|
||||||
|
|
||||||
declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn,
|
declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn,
|
||||||
"Warn about looping over a range of indices if a normal iterator would do" }
|
"for-looping over a range of indices where an iterator over items would do" }
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct LoopsPass;
|
pub struct LoopsPass;
|
||||||
|
|
|
@ -8,13 +8,13 @@ use utils::{span_lint, match_def_path, walk_ptrs_ty};
|
||||||
pub struct MethodsPass;
|
pub struct MethodsPass;
|
||||||
|
|
||||||
declare_lint!(pub OPTION_UNWRAP_USED, Warn,
|
declare_lint!(pub OPTION_UNWRAP_USED, Warn,
|
||||||
"Warn on using unwrap() on an Option value");
|
"using `Option.unwrap()`, which should at least get a better message using `expect()`");
|
||||||
declare_lint!(pub RESULT_UNWRAP_USED, Allow,
|
declare_lint!(pub RESULT_UNWRAP_USED, Allow,
|
||||||
"Warn on using unwrap() on a Result value");
|
"using `Result.unwrap()`, which might be better handled");
|
||||||
declare_lint!(pub STR_TO_STRING, Warn,
|
declare_lint!(pub STR_TO_STRING, Warn,
|
||||||
"Warn when a String could use to_owned() instead of to_string()");
|
"using `to_string()` on a str, which should be `to_owned()`");
|
||||||
declare_lint!(pub STRING_TO_STRING, Warn,
|
declare_lint!(pub STRING_TO_STRING, Warn,
|
||||||
"Warn when calling String.to_string()");
|
"calling `String.to_string()` which is a no-op");
|
||||||
|
|
||||||
impl LintPass for MethodsPass {
|
impl LintPass for MethodsPass {
|
||||||
fn get_lints(&self) -> LintArray {
|
fn get_lints(&self) -> LintArray {
|
||||||
|
|
21
src/misc.rs
21
src/misc.rs
|
@ -16,7 +16,8 @@ pub struct MiscPass;
|
||||||
|
|
||||||
|
|
||||||
declare_lint!(pub SINGLE_MATCH, Warn,
|
declare_lint!(pub SINGLE_MATCH, Warn,
|
||||||
"Warn on usage of matches with a single nontrivial arm");
|
"a match statement with a single nontrivial arm (i.e, where the other arm \
|
||||||
|
is `_ => {}`) is used; recommends `if let` instead");
|
||||||
|
|
||||||
impl LintPass for MiscPass {
|
impl LintPass for MiscPass {
|
||||||
fn get_lints(&self) -> LintArray {
|
fn get_lints(&self) -> LintArray {
|
||||||
|
@ -59,7 +60,9 @@ impl LintPass for MiscPass {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
declare_lint!(pub TOPLEVEL_REF_ARG, Warn, "Warn about pattern matches with top-level `ref` bindings");
|
declare_lint!(pub TOPLEVEL_REF_ARG, Warn,
|
||||||
|
"a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not \
|
||||||
|
`fn foo((ref x, ref y): (u8, u8))`)");
|
||||||
|
|
||||||
#[allow(missing_copy_implementations)]
|
#[allow(missing_copy_implementations)]
|
||||||
pub struct TopLevelRefPass;
|
pub struct TopLevelRefPass;
|
||||||
|
@ -82,7 +85,8 @@ impl LintPass for TopLevelRefPass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint!(pub CMP_NAN, Deny, "Deny comparisons to std::f32::NAN or std::f64::NAN");
|
declare_lint!(pub CMP_NAN, Deny,
|
||||||
|
"comparisons to NAN (which will always return false, which is probably not intended)");
|
||||||
|
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
pub struct CmpNan;
|
pub struct CmpNan;
|
||||||
|
@ -114,7 +118,9 @@ fn check_nan(cx: &Context, path: &Path, span: Span) {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint!(pub FLOAT_CMP, Warn,
|
declare_lint!(pub FLOAT_CMP, Warn,
|
||||||
"Warn on ==/!= comparison of floaty values");
|
"using `==` or `!=` on float values (as floating-point operations \
|
||||||
|
usually involve rounding errors, it is always better to check for approximate \
|
||||||
|
equality within small bounds)");
|
||||||
|
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
pub struct FloatCmp;
|
pub struct FloatCmp;
|
||||||
|
@ -147,7 +153,8 @@ fn is_float(cx: &Context, expr: &Expr) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint!(pub PRECEDENCE, Warn,
|
declare_lint!(pub PRECEDENCE, Warn,
|
||||||
"Warn on mixing bit ops with integer arithmetic without parentheses");
|
"expressions where precedence may trip up the unwary reader of the source; \
|
||||||
|
suggests adding parentheses, e.g. `x << 2 + y` will be parsed as `x << (2 + y)`");
|
||||||
|
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
pub struct Precedence;
|
pub struct Precedence;
|
||||||
|
@ -190,7 +197,7 @@ fn is_arith_op(op : BinOp_) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint!(pub CMP_OWNED, Warn,
|
declare_lint!(pub CMP_OWNED, Warn,
|
||||||
"Warn on creating an owned string just for comparison");
|
"creating owned instances for comparing with others, e.g. `x == \"foo\".to_string()`");
|
||||||
|
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
pub struct CmpOwned;
|
pub struct CmpOwned;
|
||||||
|
@ -242,7 +249,7 @@ fn is_str_arg(cx: &Context, args: &[P<Expr>]) -> bool {
|
||||||
walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])).sty { true } else { false }
|
walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])).sty { true } else { false }
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint!(pub MODULO_ONE, Warn, "Warn on expressions that include % 1, which is always 0");
|
declare_lint!(pub MODULO_ONE, Warn, "taking a number modulo 1, which always returns 0");
|
||||||
|
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
pub struct ModuloOne;
|
pub struct ModuloOne;
|
||||||
|
|
|
@ -6,7 +6,8 @@ use syntax::codemap::{BytePos, ExpnInfo, Span};
|
||||||
use utils::{in_macro, span_lint};
|
use utils::{in_macro, span_lint};
|
||||||
|
|
||||||
declare_lint!(pub MUT_MUT, Warn,
|
declare_lint!(pub MUT_MUT, Warn,
|
||||||
"Warn on usage of double-mut refs, e.g. '&mut &mut ...'");
|
"usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, \
|
||||||
|
or shows a fundamental misunderstanding of references)");
|
||||||
|
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
pub struct MutMut;
|
pub struct MutMut;
|
||||||
|
|
|
@ -15,7 +15,8 @@ use utils::{de_p, span_lint};
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
pub NEEDLESS_BOOL,
|
pub NEEDLESS_BOOL,
|
||||||
Warn,
|
Warn,
|
||||||
"Warn on needless use of if x { true } else { false } (or vice versa)"
|
"if-statements with plain booleans in the then- and else-clause, e.g. \
|
||||||
|
`if p { true } else { false }`"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
|
|
|
@ -16,7 +16,8 @@ use utils::span_lint;
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
pub PTR_ARG,
|
pub PTR_ARG,
|
||||||
Allow,
|
Allow,
|
||||||
"Warn on declaration of a &Vec- or &String-typed method argument"
|
"fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` \
|
||||||
|
instead, respectively"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
|
|
|
@ -7,9 +7,10 @@ use rustc::lint::{Context, LintPass, LintArray, Level};
|
||||||
use utils::{span_lint, snippet, match_path};
|
use utils::{span_lint, snippet, match_path};
|
||||||
|
|
||||||
declare_lint!(pub NEEDLESS_RETURN, Warn,
|
declare_lint!(pub NEEDLESS_RETURN, Warn,
|
||||||
"Warn on using a return statement where an expression would be enough");
|
"using a return statement like `return expr;` where an expression would suffice");
|
||||||
declare_lint!(pub LET_AND_RETURN, Warn,
|
declare_lint!(pub LET_AND_RETURN, Warn,
|
||||||
"Warn on creating a let-binding and then immediately returning it");
|
"creating a let-binding and then immediately returning it like `let x = expr; x` at \
|
||||||
|
the end of a function");
|
||||||
|
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
pub struct ReturnPass;
|
pub struct ReturnPass;
|
||||||
|
|
|
@ -20,7 +20,7 @@ declare_lint! {
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
pub STRING_ADD,
|
pub STRING_ADD,
|
||||||
Allow,
|
Allow,
|
||||||
"expressions of the form `x + ..` where x is a `String"
|
"using `x = x + ..` where x is a `String`; suggests using `push_str()` instead"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
|
|
@ -12,9 +12,10 @@ use utils::{in_macro, snippet, span_lint, span_help_and_lint};
|
||||||
pub struct TypePass;
|
pub struct TypePass;
|
||||||
|
|
||||||
declare_lint!(pub BOX_VEC, Warn,
|
declare_lint!(pub BOX_VEC, Warn,
|
||||||
"Warn on usage of Box<Vec<T>>");
|
"usage of `Box<Vec<T>>`, vector elements are already on the heap");
|
||||||
declare_lint!(pub LINKEDLIST, Warn,
|
declare_lint!(pub LINKEDLIST, Warn,
|
||||||
"Warn on usage of LinkedList");
|
"usage of LinkedList, usually a vector is faster, or a more specialized data \
|
||||||
|
structure like a RingBuf");
|
||||||
|
|
||||||
/// Matches a type with a provided string, and returns its type parameters if successful
|
/// Matches a type with a provided string, and returns its type parameters if successful
|
||||||
pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]> {
|
pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]> {
|
||||||
|
@ -81,7 +82,7 @@ impl LintPass for TypePass {
|
||||||
pub struct LetPass;
|
pub struct LetPass;
|
||||||
|
|
||||||
declare_lint!(pub LET_UNIT_VALUE, Warn,
|
declare_lint!(pub LET_UNIT_VALUE, Warn,
|
||||||
"Warn on let-binding a value of unit type");
|
"creating a let binding to a value of unit type, which usually can't be used afterwards");
|
||||||
|
|
||||||
|
|
||||||
fn check_let_unit(cx: &Context, decl: &Decl, info: Option<&ExpnInfo>) {
|
fn check_let_unit(cx: &Context, decl: &Decl, info: Option<&ExpnInfo>) {
|
||||||
|
|
|
@ -3,8 +3,11 @@ use syntax::ast::*;
|
||||||
use syntax::codemap::{BytePos, Span};
|
use syntax::codemap::{BytePos, Span};
|
||||||
use utils::span_lint;
|
use utils::span_lint;
|
||||||
|
|
||||||
declare_lint!{ pub ZERO_WIDTH_SPACE, Deny, "Zero-width space is confusing" }
|
declare_lint!{ pub ZERO_WIDTH_SPACE, Deny,
|
||||||
declare_lint!{ pub NON_ASCII_LITERAL, Allow, "Lint literal non-ASCII chars in literals" }
|
"using a zero-width space in a string literal, which is confusing" }
|
||||||
|
declare_lint!{ pub NON_ASCII_LITERAL, Allow,
|
||||||
|
"using any literal non-ASCII chars in a string literal; suggests \
|
||||||
|
using the \\u escape instead" }
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct Unicode;
|
pub struct Unicode;
|
||||||
|
|
110
util/update_lints.py
Normal file
110
util/update_lints.py
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
# Generate a Markdown table of all lints, and put it in README.md.
|
||||||
|
# With -n option, only print the new table to stdout.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
declare_lint_re = re.compile(r'''
|
||||||
|
declare_lint! \s* [{(] \s*
|
||||||
|
pub \s+ (?P<name>[A-Z_]+) \s*,\s*
|
||||||
|
(?P<level>Forbid|Deny|Warn|Allow) \s*,\s*
|
||||||
|
" (?P<desc>(?:[^"\\]+|\\.)*) " \s* [})]
|
||||||
|
''', re.X | re.S)
|
||||||
|
|
||||||
|
nl_escape_re = re.compile(r'\\\n\s*')
|
||||||
|
|
||||||
|
|
||||||
|
def collect(lints, fn):
|
||||||
|
"""Collect all lints from a file.
|
||||||
|
|
||||||
|
Adds entries to the lints list as `(module, name, level, desc)`.
|
||||||
|
"""
|
||||||
|
with open(fn) as fp:
|
||||||
|
code = fp.read()
|
||||||
|
for match in declare_lint_re.finditer(code):
|
||||||
|
# remove \-newline escapes from description string
|
||||||
|
desc = nl_escape_re.sub('', match.group('desc'))
|
||||||
|
lints.append((os.path.splitext(os.path.basename(fn))[0],
|
||||||
|
match.group('name').lower(),
|
||||||
|
match.group('level').lower(),
|
||||||
|
desc.replace('\\"', '"')))
|
||||||
|
|
||||||
|
|
||||||
|
def write_tbl(lints, fp):
|
||||||
|
"""Write lint table in Markdown format."""
|
||||||
|
# first and third column widths
|
||||||
|
w_name = max(len(l[1]) for l in lints)
|
||||||
|
w_desc = max(len(l[3]) for l in lints)
|
||||||
|
# header and underline
|
||||||
|
fp.write('%-*s | default | meaning\n' % (w_name, 'name'))
|
||||||
|
fp.write('%s-|-%s-|-%s\n' % ('-' * w_name, '-' * 7, '-' * w_desc))
|
||||||
|
# one table row per lint
|
||||||
|
for (_, name, default, meaning) in sorted(lints, key=lambda l: l[1]):
|
||||||
|
fp.write('%-*s | %-7s | %s\n' % (w_name, name, default, meaning))
|
||||||
|
|
||||||
|
|
||||||
|
def write_group(lints, fp):
|
||||||
|
"""Write lint group (list of all lints in the form module::NAME)."""
|
||||||
|
for (module, name, _, _) in sorted(lints):
|
||||||
|
fp.write(' %s::%s,\n' % (module, name.upper()))
|
||||||
|
|
||||||
|
|
||||||
|
def replace_region(fn, region_start, region_end, callback,
|
||||||
|
replace_start=True):
|
||||||
|
"""Replace a region in a file delimited by two lines matching regexes.
|
||||||
|
|
||||||
|
A callback is called to write the new region. If `replace_start` is true,
|
||||||
|
the start delimiter line is replaced as well. The end delimiter line is
|
||||||
|
never replaced.
|
||||||
|
"""
|
||||||
|
# read current content
|
||||||
|
with open(fn) as fp:
|
||||||
|
lines = list(fp)
|
||||||
|
|
||||||
|
# replace old region with new region
|
||||||
|
with open(fn, 'w') as fp:
|
||||||
|
in_old_region = False
|
||||||
|
for line in lines:
|
||||||
|
if in_old_region:
|
||||||
|
if re.search(region_end, line):
|
||||||
|
in_old_region = False
|
||||||
|
fp.write(line)
|
||||||
|
elif re.search(region_start, line):
|
||||||
|
if not replace_start:
|
||||||
|
fp.write(line)
|
||||||
|
# old region starts here
|
||||||
|
in_old_region = True
|
||||||
|
callback(fp)
|
||||||
|
else:
|
||||||
|
fp.write(line)
|
||||||
|
|
||||||
|
|
||||||
|
def main(print_only=False):
|
||||||
|
lints = []
|
||||||
|
|
||||||
|
# check directory
|
||||||
|
if not os.path.isfile('src/lib.rs'):
|
||||||
|
print('Error: call this script from clippy checkout directory!')
|
||||||
|
return
|
||||||
|
|
||||||
|
# collect all lints from source files
|
||||||
|
for root, dirs, files in os.walk('src'):
|
||||||
|
for fn in files:
|
||||||
|
if fn.endswith('.rs'):
|
||||||
|
collect(lints, os.path.join(root, fn))
|
||||||
|
|
||||||
|
if print_only:
|
||||||
|
write_tbl(lints, sys.stdout)
|
||||||
|
return
|
||||||
|
|
||||||
|
# replace table in README.md
|
||||||
|
replace_region('README.md', r'^name +\|', '^$', lambda fp: write_tbl(lints, fp))
|
||||||
|
|
||||||
|
# same for "clippy" lint collection
|
||||||
|
replace_region('src/lib.rs', r'reg.register_lint_group\("clippy"', r'\]\);',
|
||||||
|
lambda fp: write_group(lints, fp), replace_start=False)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main(print_only='-n' in sys.argv)
|
Loading…
Reference in a new issue