Merge remote-tracking branch 'origin/master' into examples

This commit is contained in:
Oliver Schneider 2016-09-19 15:38:38 +02:00
commit c89c5d21c1
No known key found for this signature in database
GPG Key ID: 56D6EEA0FC67AC46
54 changed files with 1744 additions and 686 deletions

View File

@ -1,7 +1,35 @@
# Change Log
All notable changes to this project will be documented in this file.
## 0.0.84 — TBD
## 0.0.90 — 2016-09-09
* Rustup to *rustc 1.13.0-nightly (f1f40f850 2016-09-09)*
## 0.0.89 — 2016-09-06
* Rustup to *rustc 1.13.0-nightly (cbe4de78e 2016-09-05)*
## 0.0.88 — 2016-09-04
* Rustup to *rustc 1.13.0-nightly (70598e04f 2016-09-03)*
* The following lints are not new but were only usable through the `clippy`
lint groups: [`filter_next`], [`for_loop_over_option`],
[`for_loop_over_result`] and [`match_overlapping_arm`]. You should now be
able to `#[allow/deny]` them individually and they are available directly
through [`cargo clippy`].
## 0.0.87 — 2016-08-31
* Rustup to *rustc 1.13.0-nightly (eac41469d 2016-08-30)*
* New lints: [`builtin_type_shadow`]
* Fix FP in [`zero_prefixed_literal`] and `0b`/`0o`
## 0.0.86 — 2016-08-28
* Rustup to *rustc 1.13.0-nightly (a23064af5 2016-08-27)*
* New lints: [`missing_docs_in_private_items`], [`zero_prefixed_literal`]
## 0.0.85 — 2016-08-19
* Fix ICE with [`useless_attribute`]
* [`useless_attribute`] ignores [`unused_imports`] on `use` statements
## 0.0.84 — 2016-08-18
* Rustup to *rustc 1.13.0-nightly (aef6971ca 2016-08-17)*
## 0.0.83 — 2016-08-17
* Rustup to *rustc 1.12.0-nightly (1bf5fa326 2016-08-16)*
@ -166,6 +194,7 @@ All notable changes to this project will be documented in this file.
[`bool_comparison`]: https://github.com/Manishearth/rust-clippy/wiki#bool_comparison
[`box_vec`]: https://github.com/Manishearth/rust-clippy/wiki#box_vec
[`boxed_local`]: https://github.com/Manishearth/rust-clippy/wiki#boxed_local
[`builtin_type_shadow`]: https://github.com/Manishearth/rust-clippy/wiki#builtin_type_shadow
[`cast_possible_truncation`]: https://github.com/Manishearth/rust-clippy/wiki#cast_possible_truncation
[`cast_possible_wrap`]: https://github.com/Manishearth/rust-clippy/wiki#cast_possible_wrap
[`cast_precision_loss`]: https://github.com/Manishearth/rust-clippy/wiki#cast_precision_loss
@ -175,12 +204,14 @@ All notable changes to this project will be documented in this file.
[`clone_double_ref`]: https://github.com/Manishearth/rust-clippy/wiki#clone_double_ref
[`clone_on_copy`]: https://github.com/Manishearth/rust-clippy/wiki#clone_on_copy
[`cmp_nan`]: https://github.com/Manishearth/rust-clippy/wiki#cmp_nan
[`cmp_null`]: https://github.com/Manishearth/rust-clippy/wiki#cmp_null
[`cmp_owned`]: https://github.com/Manishearth/rust-clippy/wiki#cmp_owned
[`collapsible_if`]: https://github.com/Manishearth/rust-clippy/wiki#collapsible_if
[`crosspointer_transmute`]: https://github.com/Manishearth/rust-clippy/wiki#crosspointer_transmute
[`cyclomatic_complexity`]: https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity
[`deprecated_semver`]: https://github.com/Manishearth/rust-clippy/wiki#deprecated_semver
[`derive_hash_xor_eq`]: https://github.com/Manishearth/rust-clippy/wiki#derive_hash_xor_eq
[`diverging_sub_expression`]: https://github.com/Manishearth/rust-clippy/wiki#diverging_sub_expression
[`doc_markdown`]: https://github.com/Manishearth/rust-clippy/wiki#doc_markdown
[`double_neg`]: https://github.com/Manishearth/rust-clippy/wiki#double_neg
[`drop_ref`]: https://github.com/Manishearth/rust-clippy/wiki#drop_ref
@ -232,6 +263,7 @@ All notable changes to this project will be documented in this file.
[`mem_forget`]: https://github.com/Manishearth/rust-clippy/wiki#mem_forget
[`min_max`]: https://github.com/Manishearth/rust-clippy/wiki#min_max
[`misrefactored_assign_op`]: https://github.com/Manishearth/rust-clippy/wiki#misrefactored_assign_op
[`missing_docs_in_private_items`]: https://github.com/Manishearth/rust-clippy/wiki#missing_docs_in_private_items
[`mixed_case_hex_literals`]: https://github.com/Manishearth/rust-clippy/wiki#mixed_case_hex_literals
[`module_inception`]: https://github.com/Manishearth/rust-clippy/wiki#module_inception
[`modulo_one`]: https://github.com/Manishearth/rust-clippy/wiki#modulo_one
@ -323,5 +355,6 @@ All notable changes to this project will be documented in this file.
[`wrong_self_convention`]: https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention
[`wrong_transmute`]: https://github.com/Manishearth/rust-clippy/wiki#wrong_transmute
[`zero_divided_by_zero`]: https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero
[`zero_prefixed_literal`]: https://github.com/Manishearth/rust-clippy/wiki#zero_prefixed_literal
[`zero_width_space`]: https://github.com/Manishearth/rust-clippy/wiki#zero_width_space
<!-- end autogenerated links to wiki -->

View File

@ -1,6 +1,6 @@
[package]
name = "clippy"
version = "0.0.83"
version = "0.0.90"
authors = [
"Manish Goregaokar <manishsmail@gmail.com>",
"Andre Bogus <bogusandre@gmail.com>",
@ -25,7 +25,7 @@ test = false
[dependencies]
# begin automatic update
clippy_lints = { version = "0.0.83", path = "clippy_lints" }
clippy_lints = { version = "0.0.90", path = "clippy_lints" }
# end automatic update
[dev-dependencies]

355
README.md
View File

@ -15,181 +15,6 @@ Table of contents:
* [*clippy-service*](#link-with-clippy-service)
* [License](#license)
## Lints
There are 166 lints included in this crate:
name | default | triggers on
---------------------------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------
[absurd_extreme_comparisons](https://github.com/Manishearth/rust-clippy/wiki#absurd_extreme_comparisons) | warn | a comparison with a maximum or minimum value that is always true or false
[almost_swapped](https://github.com/Manishearth/rust-clippy/wiki#almost_swapped) | warn | `foo = bar; bar = foo` sequence
[approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::fXX::consts`)
[assign_op_pattern](https://github.com/Manishearth/rust-clippy/wiki#assign_op_pattern) | warn | assigning the result of an operation on a variable to that same variable
[assign_ops](https://github.com/Manishearth/rust-clippy/wiki#assign_ops) | allow | any compound assignment operation
[bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false`
[blacklisted_name](https://github.com/Manishearth/rust-clippy/wiki#blacklisted_name) | warn | usage of a blacklisted/placeholder name
[block_in_if_condition_expr](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr) | warn | braces that can be eliminated in conditions, e.g `if { true } ...`
[block_in_if_condition_stmt](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_stmt) | warn | complex blocks in conditions, e.g. `if { let x = true; x } ...`
[bool_comparison](https://github.com/Manishearth/rust-clippy/wiki#bool_comparison) | warn | comparing a variable to a boolean, e.g. `if x == true`
[box_vec](https://github.com/Manishearth/rust-clippy/wiki#box_vec) | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap
[boxed_local](https://github.com/Manishearth/rust-clippy/wiki#boxed_local) | warn | using `Box<T>` where unnecessary
[cast_possible_truncation](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_truncation) | allow | casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`
[cast_possible_wrap](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_wrap) | allow | casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX`
[cast_precision_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_precision_loss) | allow | casts that cause loss of precision, e.g `x as f32` where `x: u64`
[cast_sign_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_sign_loss) | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32`
[char_lit_as_u8](https://github.com/Manishearth/rust-clippy/wiki#char_lit_as_u8) | warn | casting a character literal to u8
[chars_next_cmp](https://github.com/Manishearth/rust-clippy/wiki#chars_next_cmp) | warn | using `.chars().next()` to check if a string starts with a char
[clone_double_ref](https://github.com/Manishearth/rust-clippy/wiki#clone_double_ref) | warn | using `clone` on `&&T`
[clone_on_copy](https://github.com/Manishearth/rust-clippy/wiki#clone_on_copy) | warn | using `clone` on a `Copy` type
[cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN, which will always return false, probably not intended
[cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()`
[collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | `if`s that can be collapsed (e.g. `if x { if y { ... } }` and `else { if x { ... } }`)
[crosspointer_transmute](https://github.com/Manishearth/rust-clippy/wiki#crosspointer_transmute) | warn | transmutes that have to or from types that are a pointer to the other
[cyclomatic_complexity](https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity) | warn | functions that should be split up into multiple functions
[deprecated_semver](https://github.com/Manishearth/rust-clippy/wiki#deprecated_semver) | warn | use of `#[deprecated(since = "x")]` where x is not semver
[derive_hash_xor_eq](https://github.com/Manishearth/rust-clippy/wiki#derive_hash_xor_eq) | warn | deriving `Hash` but implementing `PartialEq` explicitly
[doc_markdown](https://github.com/Manishearth/rust-clippy/wiki#doc_markdown) | warn | presence of `_`, `::` or camel-case outside backticks in documentation
[double_neg](https://github.com/Manishearth/rust-clippy/wiki#double_neg) | warn | `--x`, which is a double negation of `x` and not a pre-decrement as in C/C++
[drop_ref](https://github.com/Manishearth/rust-clippy/wiki#drop_ref) | warn | calls to `std::mem::drop` with a reference instead of an owned value
[duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | function arguments having names which only differ by an underscore
[empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}`, which should block or sleep
[enum_clike_unportable_variant](https://github.com/Manishearth/rust-clippy/wiki#enum_clike_unportable_variant) | warn | C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`
[enum_glob_use](https://github.com/Manishearth/rust-clippy/wiki#enum_glob_use) | allow | use items that import all variants of an enum
[enum_variant_names](https://github.com/Manishearth/rust-clippy/wiki#enum_variant_names) | warn | enums where all variants share a prefix/postfix
[eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`)
[eval_order_dependence](https://github.com/Manishearth/rust-clippy/wiki#eval_order_dependence) | warn | whether a variable read occurs before a write depends on sub-expression evaluation order
[expl_impl_clone_on_copy](https://github.com/Manishearth/rust-clippy/wiki#expl_impl_clone_on_copy) | warn | implementing `Clone` explicitly on `Copy` types
[explicit_counter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop) | warn | for-looping with an explicit counter when `_.enumerate()` would do
[explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do
[extend_from_slice](https://github.com/Manishearth/rust-clippy/wiki#extend_from_slice) | warn | `.extend_from_slice(_)` is a faster way to extend a Vec by a slice
[filter_map](https://github.com/Manishearth/rust-clippy/wiki#filter_map) | allow | using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call
[filter_next](https://github.com/Manishearth/rust-clippy/wiki#filter_next) | warn | using `filter(p).next()`, which is more succinctly expressed as `.find(p)`
[float_arithmetic](https://github.com/Manishearth/rust-clippy/wiki#float_arithmetic) | allow | any floating-point arithmetic statement
[float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values instead of comparing difference with an epsilon
[for_kv_map](https://github.com/Manishearth/rust-clippy/wiki#for_kv_map) | warn | looping on a map using `iter` when `keys` or `values` would do
[for_loop_over_option](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_option) | warn | for-looping over an `Option`, which is more clearly expressed as an `if let`
[for_loop_over_result](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_result) | warn | for-looping over a `Result`, which is more clearly expressed as an `if let`
[identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1`
[if_not_else](https://github.com/Manishearth/rust-clippy/wiki#if_not_else) | allow | `if` branches that could be swapped so no negation operation is necessary on the condition
[if_same_then_else](https://github.com/Manishearth/rust-clippy/wiki#if_same_then_else) | warn | if with the same *then* and *else* blocks
[ifs_same_cond](https://github.com/Manishearth/rust-clippy/wiki#ifs_same_cond) | warn | consecutive `ifs` with the same condition
[indexing_slicing](https://github.com/Manishearth/rust-clippy/wiki#indexing_slicing) | allow | indexing/slicing usage
[ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2`
[inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | use of `#[inline(always)]`
[integer_arithmetic](https://github.com/Manishearth/rust-clippy/wiki#integer_arithmetic) | allow | any integer arithmetic statement
[invalid_regex](https://github.com/Manishearth/rust-clippy/wiki#invalid_regex) | deny | invalid regular expressions
[invalid_upcast_comparisons](https://github.com/Manishearth/rust-clippy/wiki#invalid_upcast_comparisons) | allow | a comparison involving an upcast which is always true or false
[items_after_statements](https://github.com/Manishearth/rust-clippy/wiki#items_after_statements) | allow | blocks where an item comes after a statement
[iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended
[iter_nth](https://github.com/Manishearth/rust-clippy/wiki#iter_nth) | warn | using `.iter().nth()` on a standard library type with O(1) element access
[len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits and impls that have `.len()` but not `.is_empty()`
[len_zero](https://github.com/Manishearth/rust-clippy/wiki#len_zero) | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead
[let_and_return](https://github.com/Manishearth/rust-clippy/wiki#let_and_return) | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block
[let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards
[linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque
[logic_bug](https://github.com/Manishearth/rust-clippy/wiki#logic_bug) | warn | boolean expressions that contain terminals which can be eliminated
[manual_swap](https://github.com/Manishearth/rust-clippy/wiki#manual_swap) | warn | manual swap of two variables
[many_single_char_names](https://github.com/Manishearth/rust-clippy/wiki#many_single_char_names) | warn | too many single character bindings
[map_clone](https://github.com/Manishearth/rust-clippy/wiki#map_clone) | warn | using `.map(|x| x.clone())` to clone an iterator or option's contents
[map_entry](https://github.com/Manishearth/rust-clippy/wiki#map_entry) | warn | use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`
[match_bool](https://github.com/Manishearth/rust-clippy/wiki#match_bool) | warn | a match on a boolean expression instead of an `if..else` block
[match_overlapping_arm](https://github.com/Manishearth/rust-clippy/wiki#match_overlapping_arm) | warn | a match with overlapping arms
[match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match or `if let` with all arms prefixed with `&` instead of deref-ing the match expression
[match_same_arms](https://github.com/Manishearth/rust-clippy/wiki#match_same_arms) | warn | `match` with identical arm bodies
[mem_forget](https://github.com/Manishearth/rust-clippy/wiki#mem_forget) | allow | `mem::forget` usage on `Drop` types, likely to cause memory leaks
[min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant
[misrefactored_assign_op](https://github.com/Manishearth/rust-clippy/wiki#misrefactored_assign_op) | warn | having a variable on both sides of an assign op
[mixed_case_hex_literals](https://github.com/Manishearth/rust-clippy/wiki#mixed_case_hex_literals) | warn | hex literals whose letter digits are not consistently upper- or lowercased
[module_inception](https://github.com/Manishearth/rust-clippy/wiki#module_inception) | warn | modules that have the same name as their parent module
[modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0
[mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...`
[mutex_atomic](https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic) | warn | using a mutex where an atomic value could be used instead
[mutex_integer](https://github.com/Manishearth/rust-clippy/wiki#mutex_integer) | allow | using a mutex for an integer type
[needless_bool](https://github.com/Manishearth/rust-clippy/wiki#needless_bool) | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }`
[needless_borrow](https://github.com/Manishearth/rust-clippy/wiki#needless_borrow) | warn | taking a reference that is going to be automatically dereferenced
[needless_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes) | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them
[needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do
[needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice
[needless_update](https://github.com/Manishearth/rust-clippy/wiki#needless_update) | warn | using `Foo { ..base }` when there are no missing fields
[neg_multiply](https://github.com/Manishearth/rust-clippy/wiki#neg_multiply) | warn | multiplying integers with -1
[new_ret_no_self](https://github.com/Manishearth/rust-clippy/wiki#new_ret_no_self) | warn | not returning `Self` in a `new` method
[new_without_default](https://github.com/Manishearth/rust-clippy/wiki#new_without_default) | warn | `fn new() -> Self` method without `Default` implementation
[new_without_default_derive](https://github.com/Manishearth/rust-clippy/wiki#new_without_default_derive) | warn | `fn new() -> Self` without `#[derive]`able `Default` implementation
[no_effect](https://github.com/Manishearth/rust-clippy/wiki#no_effect) | warn | statements with no effect
[non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal instead of using the `\\u` escape
[nonminimal_bool](https://github.com/Manishearth/rust-clippy/wiki#nonminimal_bool) | allow | boolean expressions that can be written more concisely
[nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file
[not_unsafe_ptr_arg_deref](https://github.com/Manishearth/rust-clippy/wiki#not_unsafe_ptr_arg_deref) | warn | public functions dereferencing raw pointer arguments but not marked `unsafe`
[ok_expect](https://github.com/Manishearth/rust-clippy/wiki#ok_expect) | warn | using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result
[option_map_unwrap_or](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or) | warn | using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)`
[option_map_unwrap_or_else](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or_else) | warn | using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`
[option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()`
[or_fun_call](https://github.com/Manishearth/rust-clippy/wiki#or_fun_call) | warn | using any `*or` method with a function call, which suggests `*or_else`
[out_of_bounds_indexing](https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing) | deny | out of bounds constant indexing
[overflow_check_conditional](https://github.com/Manishearth/rust-clippy/wiki#overflow_check_conditional) | warn | overflow checks inspired by C which are likely to panic
[panic_params](https://github.com/Manishearth/rust-clippy/wiki#panic_params) | warn | missing parameters in `panic!` calls
[precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | operations where precedence may be unclear
[print_stdout](https://github.com/Manishearth/rust-clippy/wiki#print_stdout) | allow | printing on stdout
[print_with_newline](https://github.com/Manishearth/rust-clippy/wiki#print_with_newline) | warn | using `print!()` with a format string that ends in a newline
[ptr_arg](https://github.com/Manishearth/rust-clippy/wiki#ptr_arg) | warn | arguments of the type `&Vec<...>` (instead of `&[...]`) or `&String` (instead of `&str`)
[range_step_by_zero](https://github.com/Manishearth/rust-clippy/wiki#range_step_by_zero) | warn | using `Range::step_by(0)`, which produces an infinite iterator
[range_zip_with_len](https://github.com/Manishearth/rust-clippy/wiki#range_zip_with_len) | warn | zipping iterator with a range when `enumerate()` would do
[redundant_closure](https://github.com/Manishearth/rust-clippy/wiki#redundant_closure) | warn | redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`)
[redundant_closure_call](https://github.com/Manishearth/rust-clippy/wiki#redundant_closure_call) | warn | throwaway closures called in the expression they are defined
[redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern
[regex_macro](https://github.com/Manishearth/rust-clippy/wiki#regex_macro) | warn | use of `regex!(_)` instead of `Regex::new(_)`
[result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled
[reverse_range_loop](https://github.com/Manishearth/rust-clippy/wiki#reverse_range_loop) | warn | iteration over an empty range, such as `10..0` or `5..5`
[search_is_some](https://github.com/Manishearth/rust-clippy/wiki#search_is_some) | warn | using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`
[serde_api_misuse](https://github.com/Manishearth/rust-clippy/wiki#serde_api_misuse) | warn | various things that will negatively affect your serde experience
[shadow_reuse](https://github.com/Manishearth/rust-clippy/wiki#shadow_reuse) | allow | rebinding a name to an expression that re-uses the original value, e.g. `let x = x + 1`
[shadow_same](https://github.com/Manishearth/rust-clippy/wiki#shadow_same) | allow | rebinding a name to itself, e.g. `let mut x = &mut x`
[shadow_unrelated](https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated) | allow | rebinding a name without even using the original value
[should_implement_trait](https://github.com/Manishearth/rust-clippy/wiki#should_implement_trait) | warn | defining a method that should be implementing a std trait
[similar_names](https://github.com/Manishearth/rust-clippy/wiki#similar_names) | allow | similarly named items and bindings
[single_char_pattern](https://github.com/Manishearth/rust-clippy/wiki#single_char_pattern) | warn | using a single-character str where a char could be used, e.g. `_.split("x")`
[single_match](https://github.com/Manishearth/rust-clippy/wiki#single_match) | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) instead of `if let`
[single_match_else](https://github.com/Manishearth/rust-clippy/wiki#single_match_else) | allow | a match statement with a two arms where the second arm's pattern is a wildcard instead of `if let`
[string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add) | allow | using `x + ..` where x is a `String` instead of `push_str()`
[string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign) | allow | using `x = x + ..` where x is a `String` instead of `push_str()`
[string_lit_as_bytes](https://github.com/Manishearth/rust-clippy/wiki#string_lit_as_bytes) | warn | calling `as_bytes` on a string literal instead of using a byte string literal
[stutter](https://github.com/Manishearth/rust-clippy/wiki#stutter) | allow | type names prefixed/postfixed with their containing module's name
[suspicious_assignment_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_assignment_formatting) | warn | suspicious formatting of `*=`, `-=` or `!=`
[suspicious_else_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_else_formatting) | warn | suspicious formatting of `else if`
[temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries
[temporary_cstring_as_ptr](https://github.com/Manishearth/rust-clippy/wiki#temporary_cstring_as_ptr) | warn | getting the inner pointer of a temporary `CString`
[too_many_arguments](https://github.com/Manishearth/rust-clippy/wiki#too_many_arguments) | warn | functions with too many arguments
[toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | an entire binding declared as `ref`, in a function argument or a `let` statement
[transmute_ptr_to_ref](https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref) | warn | transmutes from a pointer to a reference type
[trivial_regex](https://github.com/Manishearth/rust-clippy/wiki#trivial_regex) | warn | trivial regular expressions
[type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types that might be better factored into `type` definitions
[unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see [unicode tr15](http://www.unicode.org/reports/tr15/) for further information)
[unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values
[unnecessary_mut_passed](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed) | warn | an argument passed as a mutable reference although the callee only demands an immutable reference
[unnecessary_operation](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_operation) | warn | outer expressions with no effect
[unneeded_field_pattern](https://github.com/Manishearth/rust-clippy/wiki#unneeded_field_pattern) | warn | struct fields bound to a wildcard instead of using `..`
[unsafe_removed_from_name](https://github.com/Manishearth/rust-clippy/wiki#unsafe_removed_from_name) | warn | `unsafe` removed from API names on import
[unseparated_literal_suffix](https://github.com/Manishearth/rust-clippy/wiki#unseparated_literal_suffix) | allow | literals whose suffix is not separated by an underscore
[unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop
[unused_label](https://github.com/Manishearth/rust-clippy/wiki#unused_label) | warn | unused labels
[unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions
[use_debug](https://github.com/Manishearth/rust-clippy/wiki#use_debug) | allow | use of `Debug`-based formatting
[used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | allow | using a binding which is prefixed with an underscore
[useless_attribute](https://github.com/Manishearth/rust-clippy/wiki#useless_attribute) | warn | use of lint attributes on `extern crate` items
[useless_format](https://github.com/Manishearth/rust-clippy/wiki#useless_format) | warn | useless use of `format!`
[useless_let_if_seq](https://github.com/Manishearth/rust-clippy/wiki#useless_let_if_seq) | warn | unidiomatic `let mut` declaration followed by initialization in `if`
[useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types or could be a cast/coercion
[useless_vec](https://github.com/Manishearth/rust-clippy/wiki#useless_vec) | warn | useless `vec!`
[while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }`, which can be written as a `while let` loop
[while_let_on_iterator](https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator) | warn | using a while-let loop instead of a for loop on an iterator
[wrong_pub_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention) | allow | defining a public method named with an established prefix (like "into_") that takes `self` with the wrong convention
[wrong_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention) | warn | defining a method named with an established prefix (like "into_") that takes `self` with the wrong convention
[wrong_transmute](https://github.com/Manishearth/rust-clippy/wiki#wrong_transmute) | warn | transmutes that are confusing at best, undefined behaviour at worst and always useless
[zero_divided_by_zero](https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero) | warn | usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN
[zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing
More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/issues) if you have ideas!
## Usage
As a general rule clippy will only work with the *latest* Rust nightly for now.
@ -347,6 +172,186 @@ Both projects are independent and maintained by different people
You can check out this great service at [clippy.bashy.io](https://clippy.bashy.io/).
## Lints
There are 171 lints included in this crate:
name | default | triggers on
---------------------------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------
[absurd_extreme_comparisons](https://github.com/Manishearth/rust-clippy/wiki#absurd_extreme_comparisons) | warn | a comparison with a maximum or minimum value that is always true or false
[almost_swapped](https://github.com/Manishearth/rust-clippy/wiki#almost_swapped) | warn | `foo = bar; bar = foo` sequence
[approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::fXX::consts`)
[assign_op_pattern](https://github.com/Manishearth/rust-clippy/wiki#assign_op_pattern) | warn | assigning the result of an operation on a variable to that same variable
[assign_ops](https://github.com/Manishearth/rust-clippy/wiki#assign_ops) | allow | any compound assignment operation
[bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false`
[blacklisted_name](https://github.com/Manishearth/rust-clippy/wiki#blacklisted_name) | warn | usage of a blacklisted/placeholder name
[block_in_if_condition_expr](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr) | warn | braces that can be eliminated in conditions, e.g `if { true } ...`
[block_in_if_condition_stmt](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_stmt) | warn | complex blocks in conditions, e.g. `if { let x = true; x } ...`
[bool_comparison](https://github.com/Manishearth/rust-clippy/wiki#bool_comparison) | warn | comparing a variable to a boolean, e.g. `if x == true`
[box_vec](https://github.com/Manishearth/rust-clippy/wiki#box_vec) | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap
[boxed_local](https://github.com/Manishearth/rust-clippy/wiki#boxed_local) | warn | using `Box<T>` where unnecessary
[builtin_type_shadow](https://github.com/Manishearth/rust-clippy/wiki#builtin_type_shadow) | warn | shadowing a builtin type
[cast_possible_truncation](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_truncation) | allow | casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`
[cast_possible_wrap](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_wrap) | allow | casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX`
[cast_precision_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_precision_loss) | allow | casts that cause loss of precision, e.g `x as f32` where `x: u64`
[cast_sign_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_sign_loss) | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32`
[char_lit_as_u8](https://github.com/Manishearth/rust-clippy/wiki#char_lit_as_u8) | warn | casting a character literal to u8
[chars_next_cmp](https://github.com/Manishearth/rust-clippy/wiki#chars_next_cmp) | warn | using `.chars().next()` to check if a string starts with a char
[clone_double_ref](https://github.com/Manishearth/rust-clippy/wiki#clone_double_ref) | warn | using `clone` on `&&T`
[clone_on_copy](https://github.com/Manishearth/rust-clippy/wiki#clone_on_copy) | warn | using `clone` on a `Copy` type
[cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN, which will always return false, probably not intended
[cmp_null](https://github.com/Manishearth/rust-clippy/wiki#cmp_null) | warn | comparing a pointer to a null pointer, suggesting to use `.is_null()` instead.
[cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()`
[collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | `if`s that can be collapsed (e.g. `if x { if y { ... } }` and `else { if x { ... } }`)
[crosspointer_transmute](https://github.com/Manishearth/rust-clippy/wiki#crosspointer_transmute) | warn | transmutes that have to or from types that are a pointer to the other
[cyclomatic_complexity](https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity) | warn | functions that should be split up into multiple functions
[deprecated_semver](https://github.com/Manishearth/rust-clippy/wiki#deprecated_semver) | warn | use of `#[deprecated(since = "x")]` where x is not semver
[derive_hash_xor_eq](https://github.com/Manishearth/rust-clippy/wiki#derive_hash_xor_eq) | warn | deriving `Hash` but implementing `PartialEq` explicitly
[diverging_sub_expression](https://github.com/Manishearth/rust-clippy/wiki#diverging_sub_expression) | warn | whether an expression contains a diverging sub expression
[doc_markdown](https://github.com/Manishearth/rust-clippy/wiki#doc_markdown) | warn | presence of `_`, `::` or camel-case outside backticks in documentation
[double_neg](https://github.com/Manishearth/rust-clippy/wiki#double_neg) | warn | `--x`, which is a double negation of `x` and not a pre-decrement as in C/C++
[drop_ref](https://github.com/Manishearth/rust-clippy/wiki#drop_ref) | warn | calls to `std::mem::drop` with a reference instead of an owned value
[duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | function arguments having names which only differ by an underscore
[empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}`, which should block or sleep
[enum_clike_unportable_variant](https://github.com/Manishearth/rust-clippy/wiki#enum_clike_unportable_variant) | warn | C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`
[enum_glob_use](https://github.com/Manishearth/rust-clippy/wiki#enum_glob_use) | allow | use items that import all variants of an enum
[enum_variant_names](https://github.com/Manishearth/rust-clippy/wiki#enum_variant_names) | warn | enums where all variants share a prefix/postfix
[eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`)
[eval_order_dependence](https://github.com/Manishearth/rust-clippy/wiki#eval_order_dependence) | warn | whether a variable read occurs before a write depends on sub-expression evaluation order
[expl_impl_clone_on_copy](https://github.com/Manishearth/rust-clippy/wiki#expl_impl_clone_on_copy) | warn | implementing `Clone` explicitly on `Copy` types
[explicit_counter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop) | warn | for-looping with an explicit counter when `_.enumerate()` would do
[explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do
[extend_from_slice](https://github.com/Manishearth/rust-clippy/wiki#extend_from_slice) | warn | `.extend_from_slice(_)` is a faster way to extend a Vec by a slice
[filter_map](https://github.com/Manishearth/rust-clippy/wiki#filter_map) | allow | using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call
[filter_next](https://github.com/Manishearth/rust-clippy/wiki#filter_next) | warn | using `filter(p).next()`, which is more succinctly expressed as `.find(p)`
[float_arithmetic](https://github.com/Manishearth/rust-clippy/wiki#float_arithmetic) | allow | any floating-point arithmetic statement
[float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values instead of comparing difference with an epsilon
[for_kv_map](https://github.com/Manishearth/rust-clippy/wiki#for_kv_map) | warn | looping on a map using `iter` when `keys` or `values` would do
[for_loop_over_option](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_option) | warn | for-looping over an `Option`, which is more clearly expressed as an `if let`
[for_loop_over_result](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_result) | warn | for-looping over a `Result`, which is more clearly expressed as an `if let`
[identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1`
[if_not_else](https://github.com/Manishearth/rust-clippy/wiki#if_not_else) | allow | `if` branches that could be swapped so no negation operation is necessary on the condition
[if_same_then_else](https://github.com/Manishearth/rust-clippy/wiki#if_same_then_else) | warn | if with the same *then* and *else* blocks
[ifs_same_cond](https://github.com/Manishearth/rust-clippy/wiki#ifs_same_cond) | warn | consecutive `ifs` with the same condition
[indexing_slicing](https://github.com/Manishearth/rust-clippy/wiki#indexing_slicing) | allow | indexing/slicing usage
[ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2`
[inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | use of `#[inline(always)]`
[integer_arithmetic](https://github.com/Manishearth/rust-clippy/wiki#integer_arithmetic) | allow | any integer arithmetic statement
[invalid_regex](https://github.com/Manishearth/rust-clippy/wiki#invalid_regex) | deny | invalid regular expressions
[invalid_upcast_comparisons](https://github.com/Manishearth/rust-clippy/wiki#invalid_upcast_comparisons) | allow | a comparison involving an upcast which is always true or false
[items_after_statements](https://github.com/Manishearth/rust-clippy/wiki#items_after_statements) | allow | blocks where an item comes after a statement
[iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended
[iter_nth](https://github.com/Manishearth/rust-clippy/wiki#iter_nth) | warn | using `.iter().nth()` on a standard library type with O(1) element access
[len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits or impls with a public `len` method but no corresponding `is_empty` method
[len_zero](https://github.com/Manishearth/rust-clippy/wiki#len_zero) | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead
[let_and_return](https://github.com/Manishearth/rust-clippy/wiki#let_and_return) | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block
[let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards
[linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque
[logic_bug](https://github.com/Manishearth/rust-clippy/wiki#logic_bug) | warn | boolean expressions that contain terminals which can be eliminated
[manual_swap](https://github.com/Manishearth/rust-clippy/wiki#manual_swap) | warn | manual swap of two variables
[many_single_char_names](https://github.com/Manishearth/rust-clippy/wiki#many_single_char_names) | warn | too many single character bindings
[map_clone](https://github.com/Manishearth/rust-clippy/wiki#map_clone) | warn | using `.map(|x| x.clone())` to clone an iterator or option's contents
[map_entry](https://github.com/Manishearth/rust-clippy/wiki#map_entry) | warn | use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`
[match_bool](https://github.com/Manishearth/rust-clippy/wiki#match_bool) | warn | a match on a boolean expression instead of an `if..else` block
[match_overlapping_arm](https://github.com/Manishearth/rust-clippy/wiki#match_overlapping_arm) | warn | a match with overlapping arms
[match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match or `if let` with all arms prefixed with `&` instead of deref-ing the match expression
[match_same_arms](https://github.com/Manishearth/rust-clippy/wiki#match_same_arms) | warn | `match` with identical arm bodies
[mem_forget](https://github.com/Manishearth/rust-clippy/wiki#mem_forget) | allow | `mem::forget` usage on `Drop` types, likely to cause memory leaks
[min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant
[misrefactored_assign_op](https://github.com/Manishearth/rust-clippy/wiki#misrefactored_assign_op) | warn | having a variable on both sides of an assign op
[missing_docs_in_private_items](https://github.com/Manishearth/rust-clippy/wiki#missing_docs_in_private_items) | allow | detects missing documentation for public and private members
[mixed_case_hex_literals](https://github.com/Manishearth/rust-clippy/wiki#mixed_case_hex_literals) | warn | hex literals whose letter digits are not consistently upper- or lowercased
[module_inception](https://github.com/Manishearth/rust-clippy/wiki#module_inception) | warn | modules that have the same name as their parent module
[modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0
[mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...`
[mutex_atomic](https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic) | warn | using a mutex where an atomic value could be used instead
[mutex_integer](https://github.com/Manishearth/rust-clippy/wiki#mutex_integer) | allow | using a mutex for an integer type
[needless_bool](https://github.com/Manishearth/rust-clippy/wiki#needless_bool) | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }`
[needless_borrow](https://github.com/Manishearth/rust-clippy/wiki#needless_borrow) | warn | taking a reference that is going to be automatically dereferenced
[needless_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes) | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them
[needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do
[needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice
[needless_update](https://github.com/Manishearth/rust-clippy/wiki#needless_update) | warn | using `Foo { ..base }` when there are no missing fields
[neg_multiply](https://github.com/Manishearth/rust-clippy/wiki#neg_multiply) | warn | multiplying integers with -1
[new_ret_no_self](https://github.com/Manishearth/rust-clippy/wiki#new_ret_no_self) | warn | not returning `Self` in a `new` method
[new_without_default](https://github.com/Manishearth/rust-clippy/wiki#new_without_default) | warn | `fn new() -> Self` method without `Default` implementation
[new_without_default_derive](https://github.com/Manishearth/rust-clippy/wiki#new_without_default_derive) | warn | `fn new() -> Self` without `#[derive]`able `Default` implementation
[no_effect](https://github.com/Manishearth/rust-clippy/wiki#no_effect) | warn | statements with no effect
[non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal instead of using the `\\u` escape
[nonminimal_bool](https://github.com/Manishearth/rust-clippy/wiki#nonminimal_bool) | allow | boolean expressions that can be written more concisely
[nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file
[not_unsafe_ptr_arg_deref](https://github.com/Manishearth/rust-clippy/wiki#not_unsafe_ptr_arg_deref) | warn | public functions dereferencing raw pointer arguments but not marked `unsafe`
[ok_expect](https://github.com/Manishearth/rust-clippy/wiki#ok_expect) | warn | using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result
[option_map_unwrap_or](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or) | warn | using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)`
[option_map_unwrap_or_else](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or_else) | warn | using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`
[option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()`
[or_fun_call](https://github.com/Manishearth/rust-clippy/wiki#or_fun_call) | warn | using any `*or` method with a function call, which suggests `*or_else`
[out_of_bounds_indexing](https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing) | deny | out of bounds constant indexing
[overflow_check_conditional](https://github.com/Manishearth/rust-clippy/wiki#overflow_check_conditional) | warn | overflow checks inspired by C which are likely to panic
[panic_params](https://github.com/Manishearth/rust-clippy/wiki#panic_params) | warn | missing parameters in `panic!` calls
[precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | operations where precedence may be unclear
[print_stdout](https://github.com/Manishearth/rust-clippy/wiki#print_stdout) | allow | printing on stdout
[print_with_newline](https://github.com/Manishearth/rust-clippy/wiki#print_with_newline) | warn | using `print!()` with a format string that ends in a newline
[ptr_arg](https://github.com/Manishearth/rust-clippy/wiki#ptr_arg) | warn | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively
[range_step_by_zero](https://github.com/Manishearth/rust-clippy/wiki#range_step_by_zero) | warn | using `Range::step_by(0)`, which produces an infinite iterator
[range_zip_with_len](https://github.com/Manishearth/rust-clippy/wiki#range_zip_with_len) | warn | zipping iterator with a range when `enumerate()` would do
[redundant_closure](https://github.com/Manishearth/rust-clippy/wiki#redundant_closure) | warn | redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`)
[redundant_closure_call](https://github.com/Manishearth/rust-clippy/wiki#redundant_closure_call) | warn | throwaway closures called in the expression they are defined
[redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern
[regex_macro](https://github.com/Manishearth/rust-clippy/wiki#regex_macro) | warn | use of `regex!(_)` instead of `Regex::new(_)`
[result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled
[reverse_range_loop](https://github.com/Manishearth/rust-clippy/wiki#reverse_range_loop) | warn | iteration over an empty range, such as `10..0` or `5..5`
[search_is_some](https://github.com/Manishearth/rust-clippy/wiki#search_is_some) | warn | using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`
[serde_api_misuse](https://github.com/Manishearth/rust-clippy/wiki#serde_api_misuse) | warn | various things that will negatively affect your serde experience
[shadow_reuse](https://github.com/Manishearth/rust-clippy/wiki#shadow_reuse) | allow | rebinding a name to an expression that re-uses the original value, e.g. `let x = x + 1`
[shadow_same](https://github.com/Manishearth/rust-clippy/wiki#shadow_same) | allow | rebinding a name to itself, e.g. `let mut x = &mut x`
[shadow_unrelated](https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated) | allow | rebinding a name without even using the original value
[should_implement_trait](https://github.com/Manishearth/rust-clippy/wiki#should_implement_trait) | warn | defining a method that should be implementing a std trait
[similar_names](https://github.com/Manishearth/rust-clippy/wiki#similar_names) | allow | similarly named items and bindings
[single_char_pattern](https://github.com/Manishearth/rust-clippy/wiki#single_char_pattern) | warn | using a single-character str where a char could be used, e.g. `_.split("x")`
[single_match](https://github.com/Manishearth/rust-clippy/wiki#single_match) | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) instead of `if let`
[single_match_else](https://github.com/Manishearth/rust-clippy/wiki#single_match_else) | allow | a match statement with a two arms where the second arm's pattern is a wildcard instead of `if let`
[string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add) | allow | using `x + ..` where x is a `String` instead of `push_str()`
[string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign) | allow | using `x = x + ..` where x is a `String` instead of `push_str()`
[string_lit_as_bytes](https://github.com/Manishearth/rust-clippy/wiki#string_lit_as_bytes) | warn | calling `as_bytes` on a string literal instead of using a byte string literal
[stutter](https://github.com/Manishearth/rust-clippy/wiki#stutter) | allow | type names prefixed/postfixed with their containing module's name
[suspicious_assignment_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_assignment_formatting) | warn | suspicious formatting of `*=`, `-=` or `!=`
[suspicious_else_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_else_formatting) | warn | suspicious formatting of `else if`
[temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries
[temporary_cstring_as_ptr](https://github.com/Manishearth/rust-clippy/wiki#temporary_cstring_as_ptr) | warn | getting the inner pointer of a temporary `CString`
[too_many_arguments](https://github.com/Manishearth/rust-clippy/wiki#too_many_arguments) | warn | functions with too many arguments
[toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | an entire binding declared as `ref`, in a function argument or a `let` statement
[transmute_ptr_to_ref](https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref) | warn | transmutes from a pointer to a reference type
[trivial_regex](https://github.com/Manishearth/rust-clippy/wiki#trivial_regex) | warn | trivial regular expressions
[type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types that might be better factored into `type` definitions
[unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see [unicode tr15](http://www.unicode.org/reports/tr15/) for further information)
[unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values
[unnecessary_mut_passed](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed) | warn | an argument passed as a mutable reference although the callee only demands an immutable reference
[unnecessary_operation](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_operation) | warn | outer expressions with no effect
[unneeded_field_pattern](https://github.com/Manishearth/rust-clippy/wiki#unneeded_field_pattern) | warn | struct fields bound to a wildcard instead of using `..`
[unsafe_removed_from_name](https://github.com/Manishearth/rust-clippy/wiki#unsafe_removed_from_name) | warn | `unsafe` removed from API names on import
[unseparated_literal_suffix](https://github.com/Manishearth/rust-clippy/wiki#unseparated_literal_suffix) | allow | literals whose suffix is not separated by an underscore
[unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop
[unused_label](https://github.com/Manishearth/rust-clippy/wiki#unused_label) | warn | unused labels
[unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions
[use_debug](https://github.com/Manishearth/rust-clippy/wiki#use_debug) | allow | use of `Debug`-based formatting
[used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | allow | using a binding which is prefixed with an underscore
[useless_attribute](https://github.com/Manishearth/rust-clippy/wiki#useless_attribute) | warn | use of lint attributes on `extern crate` items
[useless_format](https://github.com/Manishearth/rust-clippy/wiki#useless_format) | warn | useless use of `format!`
[useless_let_if_seq](https://github.com/Manishearth/rust-clippy/wiki#useless_let_if_seq) | warn | unidiomatic `let mut` declaration followed by initialization in `if`
[useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types or could be a cast/coercion
[useless_vec](https://github.com/Manishearth/rust-clippy/wiki#useless_vec) | warn | useless `vec!`
[while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }`, which can be written as a `while let` loop
[while_let_on_iterator](https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator) | warn | using a while-let loop instead of a for loop on an iterator
[wrong_pub_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention) | allow | defining a public method named with an established prefix (like "into_") that takes `self` with the wrong convention
[wrong_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention) | warn | defining a method named with an established prefix (like "into_") that takes `self` with the wrong convention
[wrong_transmute](https://github.com/Manishearth/rust-clippy/wiki#wrong_transmute) | warn | transmutes that are confusing at best, undefined behaviour at worst and always useless
[zero_divided_by_zero](https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero) | warn | usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN
[zero_prefixed_literal](https://github.com/Manishearth/rust-clippy/wiki#zero_prefixed_literal) | warn | integer literals starting with `0`
[zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing
More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/issues) if you have ideas!
## License
Licensed under [MPL](https://www.mozilla.org/MPL/2.0/).

View File

@ -1,7 +1,7 @@
[package]
name = "clippy_lints"
# begin automatic update
version = "0.0.83"
version = "0.0.90"
# end automatic update
authors = [
"Manish Goregaokar <manishsmail@gmail.com>",

View File

@ -4,7 +4,7 @@ use reexport::*;
use rustc::lint::*;
use rustc::hir::*;
use semver::Version;
use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind};
use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
use syntax::codemap::Span;
use utils::{in_macro, match_path, span_lint, span_lint_and_then, snippet_opt};
use utils::paths;
@ -89,11 +89,13 @@ impl LateLintPass for AttrPass {
return;
}
for item in items {
if let MetaItemKind::NameValue(ref name, ref lit) = item.node {
if name == &"since" {
check_semver(cx, item.span, lit);
}
}
if_let_chain! {[
let NestedMetaItemKind::MetaItem(ref mi) = item.node,
let MetaItemKind::NameValue(ref name, ref lit) = mi.node,
name == &"since",
], {
check_semver(cx, item.span, lit);
}}
}
}
}
@ -106,17 +108,27 @@ impl LateLintPass for AttrPass {
ItemExternCrate(_) |
ItemUse(_) => {
for attr in &item.attrs {
if let MetaItemKind::List(ref name, _) = attr.node.value.node {
if let MetaItemKind::List(ref name, ref lint_list) = attr.node.value.node {
match &**name {
"allow" | "warn" | "deny" | "forbid" => {
span_lint_and_then(cx, USELESS_ATTRIBUTE, attr.span,
"useless lint attribute",
|db| {
if let Some(mut sugg) = snippet_opt(cx, attr.span) {
sugg.insert(1, '!');
db.span_suggestion(attr.span, "if you just forgot a `!`, use", sugg);
// whitelist `unused_imports`
for lint in lint_list {
if is_word(lint, "unused_imports") {
if let ItemUse(_) = item.node {
return;
}
}
});
}
if let Some(mut sugg) = snippet_opt(cx, attr.span) {
if sugg.len() > 1 {
span_lint_and_then(cx, USELESS_ATTRIBUTE, attr.span,
"useless lint attribute",
|db| {
sugg.insert(1, '!');
db.span_suggestion(attr.span, "if you just forgot a `!`, use", sugg);
});
}
}
},
_ => {},
}
@ -202,10 +214,7 @@ fn check_attrs(cx: &LateContext, span: Span, name: &Name, attrs: &[Attribute]) {
if values.len() != 1 || inline != &"inline" {
continue;
}
if let MetaItemKind::Word(ref always) = values[0].node {
if always != &"always" {
continue;
}
if is_word(&values[0], "always") {
span_lint(cx,
INLINE_ALWAYS,
attr.span,
@ -227,3 +236,13 @@ fn check_semver(cx: &LateContext, span: Span, lit: &Lit) {
span,
"the since field must contain a semver-compliant version");
}
fn is_word(nmi: &NestedMetaItem, expected: &str) -> bool {
if let NestedMetaItemKind::MetaItem(ref mi) = nmi.node {
if let MetaItemKind::Word(ref word) = mi.node {
return word == expected;
}
}
false
}

View File

@ -106,7 +106,8 @@ fn check_hash_peq<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, span: Span, trait_re
let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
// Only care about `impl PartialEq<Foo> for Foo`
if trait_ref.input_types()[0] == ty {
// For `impl PartialEq<B> for A, input_types is [A, B]
if trait_ref.substs.type_at(1) == ty {
let mess = if peq_is_automatically_derived {
"you are implementing `Hash` explicitly but have derived `PartialEq`"
} else {
@ -139,10 +140,11 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref
return; // ty is not Copy
}
// Some types are not Clone by default but could be cloned `by hand` if necessary
match ty.sty {
TypeVariants::TyEnum(def, substs) |
TypeVariants::TyStruct(def, substs) => {
TypeVariants::TyAdt(def, _) if def.is_union() => return,
// Some types are not Clone by default but could be cloned “by hand” if necessary
TypeVariants::TyAdt(def, substs) => {
for variant in &def.variants {
for field in &variant.fields {
match field.ty(cx.tcx, substs).sty {

View File

@ -47,8 +47,32 @@ declare_lint! {
"type names prefixed/postfixed with their containing module's name"
}
/// **What it does:** Checks for modules that have the same name as their parent module
///
/// **Why is this bad?** A typical beginner mistake is to have `mod foo;` and again `mod foo { .. }` in `foo.rs`.
/// The expectation is that items inside the inner `mod foo { .. }` are then available
/// through `foo::x`, but they are only available through `foo::foo::x`.
/// If this is done on purpose, it would be better to choose a more representative module name.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// // lib.rs
/// mod foo;
/// // foo.rs
/// mod foo {
/// ...
/// }
/// ```
declare_lint! {
pub MODULE_INCEPTION,
Warn,
"modules that have the same name as their parent module"
}
pub struct EnumVariantNames {
modules: Vec<String>,
modules: Vec<(InternedString, String)>,
threshold: u64,
}
@ -60,7 +84,7 @@ impl EnumVariantNames {
impl LintPass for EnumVariantNames {
fn get_lints(&self) -> LintArray {
lint_array!(ENUM_VARIANT_NAMES, STUTTER)
lint_array!(ENUM_VARIANT_NAMES, STUTTER, MODULE_INCEPTION)
}
}
@ -170,18 +194,25 @@ impl EarlyLintPass for EnumVariantNames {
let item_name = item.ident.name.as_str();
let item_name_chars = item_name.chars().count();
let item_camel = to_camel_case(&item_name);
if item.vis == Visibility::Public && !in_macro(cx, item.span) {
if let Some(mod_camel) = self.modules.last() {
if !in_macro(cx, item.span) {
if let Some(&(ref mod_name, ref mod_camel)) = self.modules.last() {
// constants don't have surrounding modules
if !mod_camel.is_empty() {
let matching = partial_match(mod_camel, &item_camel);
let rmatching = partial_rmatch(mod_camel, &item_camel);
let nchars = mod_camel.chars().count();
if matching == nchars {
span_lint(cx, STUTTER, item.span, &format!("Item name ({}) starts with its containing module's name ({})", item_camel, mod_camel));
if mod_name == &item_name {
if let ItemKind::Mod(..) = item.node {
span_lint(cx, MODULE_INCEPTION, item.span, "module has the same name as its containing module");
}
}
if rmatching == nchars {
span_lint(cx, STUTTER, item.span, &format!("Item name ({}) ends with its containing module's name ({})", item_camel, mod_camel));
if item.vis == Visibility::Public {
let matching = partial_match(mod_camel, &item_camel);
let rmatching = partial_rmatch(mod_camel, &item_camel);
let nchars = mod_camel.chars().count();
if matching == nchars {
span_lint(cx, STUTTER, item.span, "item name starts with its containing module's name");
}
if rmatching == nchars {
span_lint(cx, STUTTER, item.span, "item name ends with its containing module's name");
}
}
}
}
@ -189,6 +220,6 @@ impl EarlyLintPass for EnumVariantNames {
if let ItemKind::Enum(ref def, _) = item.node {
check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span);
}
self.modules.push(item_camel);
self.modules.push((item_name, item_camel));
}
}

View File

@ -144,7 +144,7 @@ impl<'a, 'tcx: 'a+'gcx, 'gcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx, 'g
}
}
fn borrow(&mut self, borrow_id: NodeId, _: Span, cmt: cmt<'tcx>, _: ty::Region, _: ty::BorrowKind,
fn borrow(&mut self, borrow_id: NodeId, _: Span, cmt: cmt<'tcx>, _: &ty::Region, _: ty::BorrowKind,
loan_cause: LoanCause) {
if let Categorization::Local(lid) = cmt.cat {

View File

@ -1,8 +1,9 @@
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit::{Visitor, walk_expr};
use rustc::hir::*;
use rustc::ty;
use rustc::lint::*;
use utils::{get_parent_expr, span_note_and_lint};
use utils::{get_parent_expr, span_note_and_lint, span_lint};
/// **What it does:** Checks for a read and a write to the same variable where
/// whether the read occurs before or after the write depends on the evaluation
@ -26,12 +27,32 @@ declare_lint! {
"whether a variable read occurs before a write depends on sub-expression evaluation order"
}
/// **What it does:** Checks for diverging calls that are not match arms or statements.
///
/// **Why is this bad?** It is often confusing to read. In addition, the
/// sub-expression evaluation order for Rust is not well documented.
///
/// **Known problems:** Someone might want to use `some_bool || panic!()` as a shorthand.
///
/// **Example:**
/// ```rust
/// let a = b() || panic!() || c();
/// // `c()` is dead, `panic!()` is only called if `b()` returns `false`
/// let x = (a, b, c, panic!());
/// // can simply be replaced by `panic!()`
/// ```
declare_lint! {
pub DIVERGING_SUB_EXPRESSION,
Warn,
"whether an expression contains a diverging sub expression"
}
#[derive(Copy,Clone)]
pub struct EvalOrderDependence;
impl LintPass for EvalOrderDependence {
fn get_lints(&self) -> LintArray {
lint_array!(EVAL_ORDER_DEPENDENCE)
lint_array!(EVAL_ORDER_DEPENDENCE, DIVERGING_SUB_EXPRESSION)
}
}
@ -56,6 +77,80 @@ impl LateLintPass for EvalOrderDependence {
_ => {}
}
}
fn check_stmt(&mut self, cx: &LateContext, stmt: &Stmt) {
match stmt.node {
StmtExpr(ref e, _) | StmtSemi(ref e, _) => DivergenceVisitor(cx).maybe_walk_expr(e),
StmtDecl(ref d, _) => {
if let DeclLocal(ref local) = d.node {
if let Local { init: Some(ref e), .. } = **local {
DivergenceVisitor(cx).visit_expr(e);
}
}
},
}
}
}
struct DivergenceVisitor<'a, 'tcx: 'a>(&'a LateContext<'a, 'tcx>);
impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
fn maybe_walk_expr(&mut self, e: &Expr) {
match e.node {
ExprClosure(..) => {},
ExprMatch(ref e, ref arms, _) => {
self.visit_expr(e);
for arm in arms {
if let Some(ref guard) = arm.guard {
self.visit_expr(guard);
}
// make sure top level arm expressions aren't linted
walk_expr(self, &*arm.body);
}
}
_ => walk_expr(self, e),
}
}
fn report_diverging_sub_expr(&mut self, e: &Expr) {
span_lint(
self.0,
DIVERGING_SUB_EXPRESSION,
e.span,
"sub-expression diverges",
);
}
}
impl<'a, 'tcx, 'v> Visitor<'v> for DivergenceVisitor<'a, 'tcx> {
fn visit_expr(&mut self, e: &'v Expr) {
match e.node {
ExprAgain(_) |
ExprBreak(_) |
ExprRet(_) => self.report_diverging_sub_expr(e),
ExprCall(ref func, _) => match self.0.tcx.expr_ty(func).sty {
ty::TyFnDef(_, _, fn_ty) |
ty::TyFnPtr(fn_ty) => if let ty::TyNever = self.0.tcx.erase_late_bound_regions(&fn_ty.sig).output.sty {
self.report_diverging_sub_expr(e);
},
_ => {},
},
ExprMethodCall(..) => {
let method_call = ty::MethodCall::expr(e.id);
let borrowed_table = self.0.tcx.tables.borrow();
let method_type = borrowed_table.method_map.get(&method_call).expect("This should never happen.");
let result_ty = method_type.ty.fn_ret();
if let ty::TyNever = self.0.tcx.erase_late_bound_regions(&result_ty).sty {
self.report_diverging_sub_expr(e);
}
},
_ => {
// do not lint expressions referencing objects of type `!`, as that required a diverging expression to begin with
},
}
self.maybe_walk_expr(e);
}
fn visit_block(&mut self, _: &'v Block) {
// don't continue over blocks, LateLintPass already does that
}
}
/// Walks up the AST from the the given write expression (`vis.write_expr`)

View File

@ -42,13 +42,13 @@ declare_lint! {
/// **Example:**
/// ```rust
/// impl X {
/// fn len(&self) -> usize { .. }
/// pub fn len(&self) -> usize { .. }
/// }
/// ```
declare_lint! {
pub LEN_WITHOUT_IS_EMPTY,
Warn,
"traits and impls that have `.len()` but not `.is_empty()`"
"traits or impls with a public `len` method but no corresponding `is_empty` method"
}
#[derive(Copy,Clone)]
@ -99,13 +99,12 @@ fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[TraitItem]) {
}
if !trait_items.iter().any(|i| is_named_self(i, "is_empty")) {
for i in trait_items {
if is_named_self(i, "len") {
if let Some(i) = trait_items.iter().find(|i| is_named_self(i, "len")) {
if cx.access_levels.is_exported(i.id) {
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",
&format!("trait `{}` has a `len` method but no `is_empty` method",
item.name));
}
}
@ -122,19 +121,26 @@ fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItem]) {
}
}
if !impl_items.iter().any(|i| is_named_self(i, "is_empty")) {
for i in impl_items {
if is_named_self(i, "len") {
let ty = cx.tcx.node_id_to_type(item.id);
let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(i, "is_empty")) {
if cx.access_levels.is_exported(is_empty.id) {
return;
} else {
"a private"
}
} else {
"no corresponding"
};
span_lint(cx,
LEN_WITHOUT_IS_EMPTY,
i.span,
&format!("item `{}` has a `.len(_: &Self)` method, but no `.is_empty(_: &Self)` method. \
Consider adding one",
ty));
return;
}
if let Some(i) = impl_items.iter().find(|i| is_named_self(i, "len")) {
if cx.access_levels.is_exported(i.id) {
let ty = cx.tcx.node_id_to_type(item.id);
span_lint(cx,
LEN_WITHOUT_IS_EMPTY,
i.span,
&format!("item `{}` has a public `len` method but {} `is_empty` method",
ty,
is_empty));
}
}
}
@ -208,8 +214,7 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool {
.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(id, _) |
ty::TyStruct(id, _) => has_is_empty_impl(cx, &id.did),
ty::TyAdt(id, _) => has_is_empty_impl(cx, &id.did),
ty::TyArray(..) | ty::TyStr => true,
_ => false,
}

View File

@ -8,9 +8,8 @@
#![feature(rustc_private)]
#![feature(slice_patterns)]
#![feature(stmt_expr_attributes)]
#![feature(type_macros)]
#![allow(indexing_slicing, shadow_reuse, unknown_lints)]
#![allow(indexing_slicing, shadow_reuse, unknown_lints, missing_docs_in_private_items)]
#[macro_use]
extern crate syntax;
@ -96,7 +95,7 @@ pub mod methods;
pub mod minmax;
pub mod misc;
pub mod misc_early;
pub mod module_inception;
pub mod missing_doc;
pub mod mut_mut;
pub mod mut_reference;
pub mod mutex_atomic;
@ -112,7 +111,7 @@ pub mod overflow_check_conditional;
pub mod panic;
pub mod precedence;
pub mod print;
pub mod ptr_arg;
pub mod ptr;
pub mod ranges;
pub mod regex;
pub mod returns;
@ -172,21 +171,19 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
reg.register_late_lint_pass(box serde::Serde);
reg.register_early_lint_pass(box utils::internal_lints::Clippy);
reg.register_late_lint_pass(box utils::internal_lints::LintWithoutLintPass::default());
reg.register_late_lint_pass(box types::TypePass);
reg.register_late_lint_pass(box booleans::NonminimalBool);
reg.register_early_lint_pass(box module_inception::Pass);
reg.register_late_lint_pass(box misc::TopLevelRefPass);
reg.register_late_lint_pass(box misc::CmpNan);
reg.register_late_lint_pass(box eq_op::EqOp);
reg.register_early_lint_pass(box enum_variants::EnumVariantNames::new(conf.enum_variant_name_threshold));
reg.register_late_lint_pass(box enum_glob_use::EnumGlobUse);
reg.register_late_lint_pass(box enum_clike::UnportableVariant);
reg.register_late_lint_pass(box bit_mask::BitMask);
reg.register_late_lint_pass(box ptr_arg::PtrArg);
reg.register_late_lint_pass(box ptr::PointerPass);
reg.register_late_lint_pass(box needless_bool::NeedlessBool);
reg.register_late_lint_pass(box needless_bool::BoolComparison);
reg.register_late_lint_pass(box approx_const::Pass);
reg.register_late_lint_pass(box misc::FloatCmp);
reg.register_late_lint_pass(box misc::Pass);
reg.register_early_lint_pass(box precedence::Precedence);
reg.register_late_lint_pass(box eta_reduction::EtaPass);
reg.register_late_lint_pass(box identity_op::IdentityOp);
@ -194,11 +191,9 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
reg.register_late_lint_pass(box mut_mut::MutMut);
reg.register_late_lint_pass(box mut_reference::UnnecessaryMutPassed);
reg.register_late_lint_pass(box len_zero::LenZero);
reg.register_late_lint_pass(box misc::CmpOwned);
reg.register_late_lint_pass(box attrs::AttrPass);
reg.register_early_lint_pass(box collapsible_if::CollapsibleIf);
reg.register_late_lint_pass(box block_in_if_condition::BlockInIfCondition);
reg.register_late_lint_pass(box misc::ModuloOne);
reg.register_late_lint_pass(box unicode::Unicode);
reg.register_late_lint_pass(box strings::StringAdd);
reg.register_early_lint_pass(box returns::ReturnPass);
@ -213,7 +208,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
reg.register_late_lint_pass(box types::CastPass);
reg.register_late_lint_pass(box types::TypeComplexityPass::new(conf.type_complexity_threshold));
reg.register_late_lint_pass(box matches::MatchPass);
reg.register_late_lint_pass(box misc::PatternPass);
reg.register_late_lint_pass(box minmax::MinMaxPass);
reg.register_late_lint_pass(box open_options::NonSensical);
reg.register_late_lint_pass(box zero_div_zero::Pass);
@ -227,7 +221,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
reg.register_late_lint_pass(box cyclomatic_complexity::CyclomaticComplexity::new(conf.cyclomatic_complexity_threshold));
reg.register_late_lint_pass(box escape::Pass{too_large_for_stack: conf.too_large_for_stack});
reg.register_early_lint_pass(box misc_early::MiscEarly);
reg.register_late_lint_pass(box misc::UsedUnderscoreBinding);
reg.register_late_lint_pass(box array_indexing::ArrayIndexing);
reg.register_late_lint_pass(box panic::Pass);
reg.register_late_lint_pass(box strings::StringLitAsBytes);
@ -260,6 +253,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
reg.register_late_lint_pass(box assign_ops::AssignOps);
reg.register_late_lint_pass(box let_if_seq::LetIfSeq);
reg.register_late_lint_pass(box eval_order_dependence::EvalOrderDependence);
reg.register_late_lint_pass(box missing_doc::MissingDoc::new());
reg.register_lint_group("clippy_restrictions", vec![
arithmetic::FLOAT_ARITHMETIC,
@ -282,6 +276,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
methods::WRONG_PUB_SELF_CONVENTION,
misc::USED_UNDERSCORE_BINDING,
misc_early::UNSEPARATED_LITERAL_SUFFIX,
missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
mut_mut::MUT_MUT,
mutex_atomic::MUTEX_INTEGER,
non_expressive_names::SIMILAR_NAMES,
@ -301,6 +296,11 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
unicode::UNICODE_NOT_NFC,
]);
reg.register_lint_group("clippy_internal", vec![
utils::internal_lints::CLIPPY_LINTS_INTERNAL,
utils::internal_lints::LINT_WITHOUT_LINT_PASS,
]);
reg.register_lint_group("clippy", vec![
approx_const::APPROX_CONSTANT,
array_indexing::OUT_OF_BOUNDS_INDEXING,
@ -327,9 +327,11 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
entry::MAP_ENTRY,
enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT,
enum_variants::ENUM_VARIANT_NAMES,
enum_variants::MODULE_INCEPTION,
eq_op::EQ_OP,
escape::BOXED_LOCAL,
eta_reduction::REDUNDANT_CLOSURE,
eval_order_dependence::DIVERGING_SUB_EXPRESSION,
eval_order_dependence::EVAL_ORDER_DEPENDENCE,
format::USELESS_FORMAT,
formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
@ -382,12 +384,13 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
misc::MODULO_ONE,
misc::REDUNDANT_PATTERN,
misc::TOPLEVEL_REF_ARG,
misc_early::BUILTIN_TYPE_SHADOW,
misc_early::DOUBLE_NEG,
misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
misc_early::MIXED_CASE_HEX_LITERALS,
misc_early::REDUNDANT_CLOSURE_CALL,
misc_early::UNNEEDED_FIELD_PATTERN,
module_inception::MODULE_INCEPTION,
misc_early::ZERO_PREFIXED_LITERAL,
mut_reference::UNNECESSARY_MUT_PASSED,
mutex_atomic::MUTEX_ATOMIC,
needless_bool::BOOL_COMPARISON,
@ -405,7 +408,8 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
panic::PANIC_PARAMS,
precedence::PRECEDENCE,
print::PRINT_WITH_NEWLINE,
ptr_arg::PTR_ARG,
ptr::CMP_NULL,
ptr::PTR_ARG,
ranges::RANGE_STEP_BY_ZERO,
ranges::RANGE_ZIP_WITH_LEN,
regex::INVALID_REGEX,

View File

@ -14,9 +14,9 @@ use std::collections::HashMap;
use syntax::ast;
use utils::sugg;
use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, multispan_sugg, in_external_macro,
span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, higher,
walk_ptrs_ty};
use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, multispan_sugg,
in_external_macro, is_refutable, span_help_and_lint, is_integer_literal,
get_enclosing_block, span_lint_and_then, higher, walk_ptrs_ty};
use utils::paths;
/// **What it does:** Checks for looping over the range of `0..len` of some
@ -276,6 +276,8 @@ impl LintPass for Pass {
lint_array!(NEEDLESS_RANGE_LOOP,
EXPLICIT_ITER_LOOP,
ITER_NEXT_LOOP,
FOR_LOOP_OVER_RESULT,
FOR_LOOP_OVER_OPTION,
WHILE_LET_LOOP,
UNUSED_COLLECT,
REVERSE_RANGE_LOOP,
@ -352,6 +354,7 @@ impl LateLintPass for Pass {
if method_name.node.as_str() == "next" &&
match_trait_method(cx, match_expr, &paths::ITERATOR) &&
lhs_constructor.name.as_str() == "Some" &&
!is_refutable(cx, &pat_args[0]) &&
!is_iterator_used_after_while_let(cx, iter_expr) {
let iterator = snippet(cx, method_args[0].span, "_");
let loop_var = snippet(cx, pat_args[0].span, "_");

View File

@ -22,7 +22,7 @@ use utils::sugg::Sugg;
/// **Example:**
/// ```rust
/// match x {
/// Some(ref foo) -> bar(foo),
/// Some(ref foo) => bar(foo),
/// _ => ()
/// }
/// ```
@ -43,7 +43,7 @@ declare_lint! {
/// **Example:**
/// ```rust
/// match x {
/// Some(ref foo) -> bar(foo),
/// Some(ref foo) => bar(foo),
/// _ => bar(other_ref),
/// }
/// ```
@ -125,7 +125,7 @@ pub struct MatchPass;
impl LintPass for MatchPass {
fn get_lints(&self) -> LintArray {
lint_array!(SINGLE_MATCH, MATCH_REF_PATS, MATCH_BOOL, SINGLE_MATCH_ELSE)
lint_array!(SINGLE_MATCH, MATCH_REF_PATS, MATCH_BOOL, SINGLE_MATCH_ELSE, MATCH_OVERLAPPING_ARM)
}
}

View File

@ -2,7 +2,6 @@ use rustc::hir;
use rustc::lint::*;
use rustc::middle::const_val::ConstVal;
use rustc::middle::const_qualif::ConstQualif;
use rustc::ty::subst::TypeSpace;
use rustc::ty;
use rustc_const_eval::EvalHint::ExprTypeChecked;
use rustc_const_eval::eval_const_expr_partial;
@ -380,9 +379,7 @@ declare_lint! {
/// **Known problems:** Does not catch multi-byte unicode characters.
///
/// **Example:**
/// ```rust
/// _.split("x")` could be `_.split('x')
/// ```
/// `_.split("x")` could be `_.split('x')
declare_lint! {
pub SINGLE_CHAR_PATTERN,
Warn,
@ -462,6 +459,7 @@ impl LintPass for Pass {
SINGLE_CHAR_PATTERN,
SEARCH_IS_SOME,
TEMPORARY_CSTRING_AS_PTR,
FILTER_NEXT,
FILTER_MAP,
ITER_NTH)
}
@ -796,7 +794,7 @@ fn derefs_to_slice(cx: &LateContext, expr: &hir::Expr, ty: ty::Ty) -> Option<sug
fn may_slice(cx: &LateContext, ty: ty::Ty) -> bool {
match ty.sty {
ty::TySlice(_) => true,
ty::TyStruct(..) => match_type(cx, ty, &paths::VEC),
ty::TyAdt(..) => match_type(cx, ty, &paths::VEC),
ty::TyArray(_, size) => size < 32,
ty::TyRef(_, ty::TypeAndMut { ty: inner, .. }) |
ty::TyBox(inner) => may_slice(cx, inner),
@ -1081,15 +1079,15 @@ fn lint_single_char_pattern(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr)
/// Given a `Result<T, E>` type, return its error type (`E`).
fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> {
if !match_type(cx, ty, &paths::RESULT) {
return None;
}
if let ty::TyEnum(_, substs) = ty.sty {
if let Some(err_ty) = substs.types.opt_get(TypeSpace, 1) {
return Some(err_ty);
if let ty::TyAdt(_, substs) = ty.sty {
if match_type(cx, ty, &paths::RESULT) {
substs.types().nth(1)
} else {
None
}
} else {
None
}
None
}
/// This checks whether a given type is known to implement Debug.

View File

@ -40,16 +40,134 @@ declare_lint! {
"an entire binding declared as `ref`, in a function argument or a `let` statement"
}
#[allow(missing_copy_implementations)]
pub struct TopLevelRefPass;
/// **What it does:** Checks for comparisons to NaN.
///
/// **Why is this bad?** NaN does not compare meaningfully to anything not
/// even itself so those comparisons are simply wrong.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// x == NAN
/// ```
declare_lint! {
pub CMP_NAN,
Deny,
"comparisons to NAN, which will always return false, probably not intended"
}
impl LintPass for TopLevelRefPass {
/// **What it does:** Checks for (in-)equality comparisons on floating-point
/// values (apart from zero), except in functions called `*eq*` (which probably
/// implement equality for a type involving floats).
///
/// **Why is this bad?** Floating point calculations are usually imprecise, so
/// asking if two values are *exactly* equal is asking for trouble. For a good
/// guide on what to do, see [the floating point
/// guide](http://www.floating-point-gui.de/errors/comparison).
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// y == 1.23f64
/// y != x // where both are floats
/// ```
declare_lint! {
pub FLOAT_CMP,
Warn,
"using `==` or `!=` on float values instead of comparing difference with an epsilon"
}
/// **What it does:** Checks for conversions to owned values just for the sake
/// of a comparison.
///
/// **Why is this bad?** The comparison can operate on a reference, so creating
/// an owned value effectively throws it away directly afterwards, which is
/// needlessly consuming code and heap space.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// x.to_owned() == y
/// ```
declare_lint! {
pub CMP_OWNED,
Warn,
"creating owned instances for comparing with others, e.g. `x == \"foo\".to_string()`"
}
/// **What it does:** Checks for getting the remainder of a division by one.
///
/// **Why is this bad?** The result can only ever be zero. No one will write
/// such code deliberately, unless trying to win an Underhanded Rust
/// Contest. Even for that contest, it's probably a bad idea. Use something more
/// underhanded.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// x % 1
/// ```
declare_lint! {
pub MODULO_ONE,
Warn,
"taking a number modulo 1, which always returns 0"
}
/// **What it does:** Checks for patterns in the form `name @ _`.
///
/// **Why is this bad?** It's almost always more readable to just use direct bindings.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// match v {
/// Some(x) => (),
/// y @ _ => (), // easier written as `y`,
/// }
/// ```
declare_lint! {
pub REDUNDANT_PATTERN,
Warn,
"using `name @ _` in a pattern"
}
/// **What it does:** Checks for the use of bindings with a single leading underscore.
///
/// **Why is this bad?** A single leading underscore is usually used to indicate
/// that a binding will not be used. Using such a binding breaks this
/// expectation.
///
/// **Known problems:** The lint does not work properly with desugaring and
/// macro, it has been allowed in the mean time.
///
/// **Example:**
/// ```rust
/// let _x = 0;
/// let y = _x + 1; // Here we are using `_x`, even though it has a leading underscore.
/// // We should rename `_x` to `x`
/// ```
declare_lint! {
pub USED_UNDERSCORE_BINDING,
Allow,
"using a binding which is prefixed with an underscore"
}
#[derive(Copy, Clone)]
pub struct Pass;
impl LintPass for Pass {
fn get_lints(&self) -> LintArray {
lint_array!(TOPLEVEL_REF_ARG)
lint_array!(TOPLEVEL_REF_ARG, CMP_NAN, FLOAT_CMP, CMP_OWNED, MODULO_ONE, REDUNDANT_PATTERN,
USED_UNDERSCORE_BINDING)
}
}
impl LateLintPass for TopLevelRefPass {
impl LateLintPass for Pass {
fn check_fn(&mut self, cx: &LateContext, k: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) {
if let FnKind::Closure(_) = k {
// Does not apply to closures
@ -64,6 +182,7 @@ impl LateLintPass for TopLevelRefPass {
}
}
}
fn check_stmt(&mut self, cx: &LateContext, s: &Stmt) {
if_let_chain! {[
let StmtDecl(ref d, _) = s.node,
@ -97,44 +216,98 @@ impl LateLintPass for TopLevelRefPass {
);
}}
}
}
/// **What it does:** Checks for comparisons to NaN.
///
/// **Why is this bad?** NaN does not compare meaningfully to anything not
/// even itself so those comparisons are simply wrong.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// x == NAN
/// ```
declare_lint! {
pub CMP_NAN,
Deny,
"comparisons to NAN, which will always return false, probably not intended"
}
#[derive(Copy,Clone)]
pub struct CmpNan;
impl LintPass for CmpNan {
fn get_lints(&self) -> LintArray {
lint_array!(CMP_NAN)
}
}
impl LateLintPass for CmpNan {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
if let ExprBinary(ref cmp, ref left, ref right) = expr.node {
if cmp.node.is_comparison() {
let op = cmp.node;
if op.is_comparison() {
if let ExprPath(_, ref path) = left.node {
check_nan(cx, path, expr.span);
}
if let ExprPath(_, ref path) = right.node {
check_nan(cx, path, expr.span);
}
check_to_owned(cx, left, right, true, cmp.span);
check_to_owned(cx, right, left, false, cmp.span)
}
if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) {
if is_allowed(cx, left) || is_allowed(cx, right) {
return;
}
if let Some(name) = get_item_name(cx, expr) {
let name = name.as_str();
if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") ||
name.ends_with("_eq") {
return;
}
}
span_lint_and_then(cx,
FLOAT_CMP,
expr.span,
"strict comparison of f32 or f64",
|db| {
let lhs = Sugg::hir(cx, left, "..");
let rhs = Sugg::hir(cx, right, "..");
db.span_suggestion(expr.span,
"consider comparing them within some error",
format!("({}).abs() < error", lhs - rhs));
db.span_note(expr.span, "std::f32::EPSILON and std::f64::EPSILON are available.");
});
} else if op == BiRem && is_integer_literal(right, 1) {
span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0");
}
}
if in_attributes_expansion(cx, expr) {
// Don't lint things expanded by #[derive(...)], etc
return;
}
let binding = match expr.node {
ExprPath(_, ref path) => {
let binding = path.segments
.last()
.expect("path should always have at least one segment")
.name
.as_str();
if binding.starts_with('_') &&
!binding.starts_with("__") &&
binding != "_result" && // FIXME: #944
is_used(cx, expr) &&
// don't lint if the declaration is in a macro
non_macro_local(cx, &cx.tcx.expect_def(expr.id)) {
Some(binding)
} else {
None
}
}
ExprField(_, spanned) => {
let name = spanned.node.as_str();
if name.starts_with('_') && !name.starts_with("__") {
Some(name)
} else {
None
}
}
_ => None,
};
if let Some(binding) = binding {
span_lint(cx,
USED_UNDERSCORE_BINDING,
expr.span,
&format!("used binding `{}` which is prefixed with an underscore. A leading \
underscore signals that a binding will not be used.", binding));
}
}
fn check_pat(&mut self, cx: &LateContext, pat: &Pat) {
if let PatKind::Binding(_, ref ident, Some(ref right)) = pat.node {
if right.node == PatKind::Wild {
span_lint(cx,
REDUNDANT_PATTERN,
pat.span,
&format!("the `{} @ _` pattern can be written as just `{}`",
ident.node,
ident.node));
}
}
}
@ -151,70 +324,6 @@ fn check_nan(cx: &LateContext, path: &Path, span: Span) {
});
}
/// **What it does:** Checks for (in-)equality comparisons on floating-point
/// values (apart from zero), except in functions called `*eq*` (which probably
/// implement equality for a type involving floats).
///
/// **Why is this bad?** Floating point calculations are usually imprecise, so
/// asking if two values are *exactly* equal is asking for trouble. For a good
/// guide on what to do, see [the floating point
/// guide](http://www.floating-point-gui.de/errors/comparison).
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// y == 1.23f64
/// y != x // where both are floats
/// ```
declare_lint! {
pub FLOAT_CMP,
Warn,
"using `==` or `!=` on float values instead of comparing difference with an epsilon"
}
#[derive(Copy,Clone)]
pub struct FloatCmp;
impl LintPass for FloatCmp {
fn get_lints(&self) -> LintArray {
lint_array!(FLOAT_CMP)
}
}
impl LateLintPass for FloatCmp {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
if let ExprBinary(ref cmp, ref left, ref right) = expr.node {
let op = cmp.node;
if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) {
if is_allowed(cx, left) || is_allowed(cx, right) {
return;
}
if let Some(name) = get_item_name(cx, expr) {
let name = name.as_str();
if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") ||
name.ends_with("_eq") {
return;
}
}
span_lint_and_then(cx,
FLOAT_CMP,
expr.span,
"strict comparison of f32 or f64",
|db| {
let lhs = Sugg::hir(cx, left, "..");
let rhs = Sugg::hir(cx, right, "..");
db.span_suggestion(expr.span,
"consider comparing them within some error",
format!("({}).abs() < error", lhs - rhs));
db.span_note(expr.span, "std::f32::EPSILON and std::f64::EPSILON are available.");
});
}
}
}
}
fn is_allowed(cx: &LateContext, expr: &Expr) -> bool {
let res = eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None);
if let Ok(ConstVal::Float(val)) = res {
@ -247,45 +356,6 @@ fn is_float(cx: &LateContext, expr: &Expr) -> bool {
matches!(walk_ptrs_ty(cx.tcx.expr_ty(expr)).sty, ty::TyFloat(_))
}
/// **What it does:** Checks for conversions to owned values just for the sake
/// of a comparison.
///
/// **Why is this bad?** The comparison can operate on a reference, so creating
/// an owned value effectively throws it away directly afterwards, which is
/// needlessly consuming code and heap space.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// x.to_owned() == y
/// ```
declare_lint! {
pub CMP_OWNED,
Warn,
"creating owned instances for comparing with others, e.g. `x == \"foo\".to_string()`"
}
#[derive(Copy,Clone)]
pub struct CmpOwned;
impl LintPass for CmpOwned {
fn get_lints(&self) -> LintArray {
lint_array!(CMP_OWNED)
}
}
impl LateLintPass for CmpOwned {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
if let ExprBinary(ref cmp, ref left, ref right) = expr.node {
if cmp.node.is_comparison() {
check_to_owned(cx, left, right, true, cmp.span);
check_to_owned(cx, right, left, false, cmp.span)
}
}
}
}
fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr, left: bool, op: Span) {
let (arg_ty, snip) = match expr.node {
ExprMethodCall(Spanned { node: ref name, .. }, _, ref args) if args.len() == 1 => {
@ -346,165 +416,6 @@ fn is_str_arg(cx: &LateContext, args: &[P<Expr>]) -> bool {
matches!(walk_ptrs_ty(cx.tcx.expr_ty(&args[0])).sty, ty::TyStr)
}
/// **What it does:** Checks for getting the remainder of a division by one.
///
/// **Why is this bad?** The result can only ever be zero. No one will write
/// such code deliberately, unless trying to win an Underhanded Rust
/// Contest. Even for that contest, it's probably a bad idea. Use something more
/// underhanded.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// x % 1
/// ```
declare_lint! {
pub MODULO_ONE,
Warn,
"taking a number modulo 1, which always returns 0"
}
#[derive(Copy,Clone)]
pub struct ModuloOne;
impl LintPass for ModuloOne {
fn get_lints(&self) -> LintArray {
lint_array!(MODULO_ONE)
}
}
impl LateLintPass for ModuloOne {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
if let ExprBinary(ref cmp, _, ref right) = expr.node {
if let Spanned { node: BinOp_::BiRem, .. } = *cmp {
if is_integer_literal(right, 1) {
span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0");
}
}
}
}
}
/// **What it does:** Checks for patterns in the form `name @ _`.
///
/// **Why is this bad?** It's almost always more readable to just use direct bindings.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// match v {
/// Some(x) => (),
/// y @ _ => (), // easier written as `y`,
/// }
/// ```
declare_lint! {
pub REDUNDANT_PATTERN,
Warn,
"using `name @ _` in a pattern"
}
#[derive(Copy,Clone)]
pub struct PatternPass;
impl LintPass for PatternPass {
fn get_lints(&self) -> LintArray {
lint_array!(REDUNDANT_PATTERN)
}
}
impl LateLintPass for PatternPass {
fn check_pat(&mut self, cx: &LateContext, pat: &Pat) {
if let PatKind::Binding(_, ref ident, Some(ref right)) = pat.node {
if right.node == PatKind::Wild {
span_lint(cx,
REDUNDANT_PATTERN,
pat.span,
&format!("the `{} @ _` pattern can be written as just `{}`",
ident.node,
ident.node));
}
}
}
}
/// **What it does:** Checks for the use of bindings with a single leading underscore.
///
/// **Why is this bad?** A single leading underscore is usually used to indicate
/// that a binding will not be used. Using such a binding breaks this
/// expectation.
///
/// **Known problems:** The lint does not work properly with desugaring and
/// macro, it has been allowed in the mean time.
///
/// **Example:**
/// ```rust
/// let _x = 0;
/// let y = _x + 1; // Here we are using `_x`, even though it has a leading underscore.
/// // We should rename `_x` to `x`
/// ```
declare_lint! {
pub USED_UNDERSCORE_BINDING,
Allow,
"using a binding which is prefixed with an underscore"
}
#[derive(Copy, Clone)]
pub struct UsedUnderscoreBinding;
impl LintPass for UsedUnderscoreBinding {
fn get_lints(&self) -> LintArray {
lint_array!(USED_UNDERSCORE_BINDING)
}
}
impl LateLintPass for UsedUnderscoreBinding {
#[cfg_attr(rustfmt, rustfmt_skip)]
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
if in_attributes_expansion(cx, expr) {
// Don't lint things expanded by #[derive(...)], etc
return;
}
let binding = match expr.node {
ExprPath(_, ref path) => {
let binding = path.segments
.last()
.expect("path should always have at least one segment")
.name
.as_str();
if binding.starts_with('_') &&
!binding.starts_with("__") &&
binding != "_result" && // FIXME: #944
is_used(cx, expr) &&
// don't lint if the declaration is in a macro
non_macro_local(cx, &cx.tcx.expect_def(expr.id)) {
Some(binding)
} else {
None
}
}
ExprField(_, spanned) => {
let name = spanned.node.as_str();
if name.starts_with('_') && !name.starts_with("__") {
Some(name)
} else {
None
}
}
_ => None,
};
if let Some(binding) = binding {
span_lint(cx,
USED_UNDERSCORE_BINDING,
expr.span,
&format!("used binding `{}` which is prefixed with an underscore. A leading \
underscore signals that a binding will not be used.", binding));
}
}
}
/// Heuristic to see if an expression is used. Should be compatible with `unused_variables`'s idea
/// of what it means for an expression to be "used".
fn is_used(cx: &LateContext, expr: &Expr) -> bool {

View File

@ -4,7 +4,7 @@ use std::char;
use syntax::ast::*;
use syntax::codemap::Span;
use syntax::visit::FnKind;
use utils::{span_lint, span_help_and_lint, snippet, snippet_opt, span_lint_and_then};
use utils::{constants, span_lint, span_help_and_lint, snippet, snippet_opt, span_lint_and_then};
/// **What it does:** Checks for structure field patterns bound to wildcards.
///
@ -105,6 +105,63 @@ declare_lint! {
"literals whose suffix is not separated by an underscore"
}
/// **What it does:** Warns if an integral constant literal starts with `0`.
///
/// **Why is this bad?** In some languages (including the infamous C language and most of its
/// familly), this marks an octal constant. In Rust however, this is a decimal constant. This could
/// be confusing for both the writer and a reader of the constant.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// In Rust:
/// ```rust
/// fn main() {
/// let a = 0123;
/// println!("{}", a);
/// }
/// ```
///
/// prints `123`, while in C:
///
/// ```c
/// #include <stdio.h>
///
/// int main() {
/// int a = 0123;
/// printf("%d\n", a);
/// }
/// ```
///
/// prints `83` (as `83 == 0o123` while `123 == 0o173`).
declare_lint! {
pub ZERO_PREFIXED_LITERAL,
Warn,
"integer literals starting with `0`"
}
/// **What it does:** Warns if a generic shadows a built-in type.
///
/// **Why is this bad?** This gives surprising type errors.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// impl<u32> Foo<u32> {
/// fn impl_func(&self) -> u32 {
/// 42
/// }
/// }
/// ```
declare_lint! {
pub BUILTIN_TYPE_SHADOW,
Warn,
"shadowing a builtin type"
}
#[derive(Copy, Clone)]
pub struct MiscEarly;
@ -112,11 +169,24 @@ pub struct MiscEarly;
impl LintPass for MiscEarly {
fn get_lints(&self) -> LintArray {
lint_array!(UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT, REDUNDANT_CLOSURE_CALL,
DOUBLE_NEG, MIXED_CASE_HEX_LITERALS, UNSEPARATED_LITERAL_SUFFIX)
DOUBLE_NEG, MIXED_CASE_HEX_LITERALS, UNSEPARATED_LITERAL_SUFFIX,
ZERO_PREFIXED_LITERAL, BUILTIN_TYPE_SHADOW)
}
}
impl EarlyLintPass for MiscEarly {
fn check_generics(&mut self, cx: &EarlyContext, gen: &Generics) {
for ty in &gen.ty_params {
let name = ty.ident.name.as_str();
if constants::BUILTIN_TYPES.contains(&&*name) {
span_lint(cx,
BUILTIN_TYPE_SHADOW,
ty.span,
&format!("This generic shadows the built-in type `{}`", name));
}
}
}
fn check_pat(&mut self, cx: &EarlyContext, pat: &Pat) {
if let PatKind::Struct(ref npat, ref pfields, _) = pat.node {
let mut wilds = 0;
@ -220,7 +290,7 @@ impl EarlyLintPass for MiscEarly {
}
ExprKind::Lit(ref lit) => {
if_let_chain! {[
let LitKind::Int(..) = lit.node,
let LitKind::Int(value, ..) = lit.node,
let Some(src) = snippet_opt(cx, lit.span),
let Some(firstch) = src.chars().next(),
char::to_digit(firstch, 10).is_some()
@ -250,6 +320,17 @@ impl EarlyLintPass for MiscEarly {
span_lint(cx, MIXED_CASE_HEX_LITERALS, lit.span,
"inconsistent casing in hexadecimal literal");
}
} else if src.starts_with("0b") || src.starts_with("0o") {
/* nothing to do */
} else if value != 0 && src.starts_with('0') {
span_lint_and_then(cx,
ZERO_PREFIXED_LITERAL,
lit.span,
"this is a decimal constant",
|db| {
db.span_suggestion(lit.span, "if you mean to use a decimal constant, remove the `0` to remove confusion:", src[1..].to_string());
db.span_suggestion(lit.span, "if you mean to use an octal constant, use `0o`:", format!("0o{}", &src[1..]));
});
}
}}
if_let_chain! {[

View File

@ -0,0 +1,179 @@
/* This file incorporates work covered by the following copyright and
* permission notice:
* Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
* file at the top-level directory of this distribution and at
* http://rust-lang.org/COPYRIGHT.
*
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
* option. This file may not be copied, modified, or distributed
* except according to those terms.
*/
/* Note: More specifically this lint is largely inspired (aka copied) from *rustc*'s
* [`missing_doc`].
*
* [`missing_doc`]: https://github.com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin.rs#L246
*/
use rustc::hir;
use rustc::lint::*;
use rustc::ty;
use syntax::ast;
use syntax::attr;
use syntax::codemap::Span;
use utils::in_macro;
/// **What it does:** Warns if there is missing doc for any documentable item (public or private).
///
/// **Why is this bad?** Doc is good. *rustc* has a `MISSING_DOCS` allowed-by-default lint for
/// public members, but has no way to enforce documentation of private items. This lint fixes that.
///
/// **Known problems:** None.
declare_lint! {
pub MISSING_DOCS_IN_PRIVATE_ITEMS,
Allow,
"detects missing documentation for public and private members"
}
pub struct MissingDoc {
/// Stack of whether #[doc(hidden)] is set
/// at each level which has lint attributes.
doc_hidden_stack: Vec<bool>,
}
impl ::std::default::Default for MissingDoc {
fn default() -> MissingDoc {
MissingDoc::new()
}
}
impl MissingDoc {
pub fn new() -> MissingDoc {
MissingDoc {
doc_hidden_stack: vec![false],
}
}
fn doc_hidden(&self) -> bool {
*self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
}
fn check_missing_docs_attrs(&self,
cx: &LateContext,
attrs: &[ast::Attribute],
sp: Span,
desc: &'static str) {
// If we're building a test harness, then warning about
// documentation is probably not really relevant right now.
if cx.sess().opts.test {
return;
}
// `#[doc(hidden)]` disables missing_docs check.
if self.doc_hidden() {
return;
}
if in_macro(cx, sp) {
return;
}
let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc");
if !has_doc {
cx.span_lint(MISSING_DOCS_IN_PRIVATE_ITEMS, sp,
&format!("missing documentation for {}", desc));
}
}
}
impl LintPass for MissingDoc {
fn get_lints(&self) -> LintArray {
lint_array![MISSING_DOCS_IN_PRIVATE_ITEMS]
}
}
impl LateLintPass for MissingDoc {
fn enter_lint_attrs(&mut self, _: &LateContext, attrs: &[ast::Attribute]) {
let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| {
attr.check_name("doc") && match attr.meta_item_list() {
None => false,
Some(l) => attr::list_contains_name(&l[..], "hidden"),
}
});
self.doc_hidden_stack.push(doc_hidden);
}
fn exit_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) {
self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
}
fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) {
self.check_missing_docs_attrs(cx, &krate.attrs, krate.span, "crate");
}
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
let desc = match it.node {
hir::ItemConst(..) => "a constant",
hir::ItemEnum(..) => "an enum",
hir::ItemFn(..) => "a function",
hir::ItemMod(..) => "a module",
hir::ItemStatic(..) => "a static",
hir::ItemStruct(..) => "a struct",
hir::ItemTrait(..) => "a trait",
hir::ItemTy(..) => "a type alias",
hir::ItemUnion(..) => "a union",
hir::ItemDefaultImpl(..) |
hir::ItemExternCrate(..) |
hir::ItemForeignMod(..) |
hir::ItemImpl(..) |
hir::ItemUse(..) => return,
};
self.check_missing_docs_attrs(cx, &it.attrs, it.span, desc);
}
fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
let desc = match trait_item.node {
hir::ConstTraitItem(..) => "an associated constant",
hir::MethodTraitItem(..) => "a trait method",
hir::TypeTraitItem(..) => "an associated type",
};
self.check_missing_docs_attrs(cx, &trait_item.attrs, trait_item.span, desc);
}
fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) {
// If the method is an impl for a trait, don't doc.
let def_id = cx.tcx.map.local_def_id(impl_item.id);
match cx.tcx.impl_or_trait_items.borrow()
.get(&def_id)
.expect("missing method descriptor?!")
.container() {
ty::TraitContainer(_) => return,
ty::ImplContainer(cid) => {
if cx.tcx.impl_trait_ref(cid).is_some() {
return
}
}
}
let desc = match impl_item.node {
hir::ImplItemKind::Const(..) => "an associated constant",
hir::ImplItemKind::Method(..) => "a method",
hir::ImplItemKind::Type(_) => "an associated type",
};
self.check_missing_docs_attrs(cx, &impl_item.attrs, impl_item.span, desc);
}
fn check_struct_field(&mut self, cx: &LateContext, sf: &hir::StructField) {
if !sf.is_positional() {
self.check_missing_docs_attrs(cx, &sf.attrs, sf.span, "a struct field");
}
}
fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) {
self.check_missing_docs_attrs(cx, &v.node.attrs, v.span, "a variant");
}
}

View File

@ -1,50 +0,0 @@
use rustc::lint::*;
use syntax::ast::*;
use utils::span_lint;
/// **What it does:** Checks for modules that have the same name as their parent module
///
/// **Why is this bad?** A typical beginner mistake is to have `mod foo;` and again `mod foo { .. }` in `foo.rs`.
/// The expectation is that items inside the inner `mod foo { .. }` are then available
/// through `foo::x`, but they are only available through `foo::foo::x`.
/// If this is done on purpose, it would be better to choose a more representative module name.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// // lib.rs
/// mod foo;
/// // foo.rs
/// mod foo {
/// ...
/// }
/// ```
declare_lint! {
pub MODULE_INCEPTION,
Warn,
"modules that have the same name as their parent module"
}
pub struct Pass;
impl LintPass for Pass {
fn get_lints(&self) -> LintArray {
lint_array![MODULE_INCEPTION]
}
}
impl EarlyLintPass for Pass {
fn check_item(&mut self, cx: &EarlyContext, item: &Item) {
if let ItemKind::Mod(ref module) = item.node {
for sub_item in &module.items {
if let ItemKind::Mod(_) = sub_item.node {
if item.ident == sub_item.ident {
span_lint(cx, MODULE_INCEPTION, sub_item.span,
"module has the same name as its containing module");
}
}
}
}
}
}

View File

@ -3,7 +3,6 @@
//! This lint is **warn** by default
use rustc::lint::{LintPass, LintArray, LateLintPass, LateContext};
use rustc::ty::subst::ParamSpace;
use rustc::ty;
use rustc::hir::Expr;
use syntax::ast;
@ -58,9 +57,9 @@ pub struct MutexAtomic;
impl LateLintPass for MutexAtomic {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
let ty = cx.tcx.expr_ty(expr);
if let ty::TyStruct(_, subst) = ty.sty {
if let ty::TyAdt(_, subst) = ty.sty {
if match_type(cx, ty, &paths::MUTEX) {
let mutex_param = &subst.types.get(ParamSpace::TypeSpace, 0).sty;
let mutex_param = &subst.type_at(0).sty;
if let Some(atomic_name) = get_atomic_name(mutex_param) {
let msg = format!("Consider using an {} instead of a Mutex here. If you just want the locking \
behaviour and not the internal type, consider using Mutex<()>.",

View File

@ -1,5 +1,5 @@
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::ty::TyStruct;
use rustc::ty::TyAdt;
use rustc::hir::{Expr, ExprStruct};
use utils::span_lint;
@ -34,7 +34,7 @@ impl LateLintPass for Pass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
if let ExprStruct(_, ref fields, Some(ref base)) = expr.node {
let ty = cx.tcx.expr_ty(expr);
if let TyStruct(def, _) = ty.sty {
if let TyAdt(def, _) = ty.sty {
if fields.len() == def.struct_variant().fields.len() {
span_lint(cx,
NEEDLESS_UPDATE,

View File

@ -146,7 +146,7 @@ impl LateLintPass for NewWithoutDefault {
fn can_derive_default<'t, 'c>(ty: ty::Ty<'t>, cx: &LateContext<'c, 't>, default_trait_id: DefId) -> bool {
match ty.sty {
ty::TyStruct(adt_def, substs) => {
ty::TyAdt(adt_def, substs) if adt_def.is_struct() => {
for field in adt_def.all_fields() {
let f_ty = field.ty(cx.tcx, substs);
if !implements_trait(cx, f_ty, default_trait_id, Vec::new()) {

View File

@ -5,14 +5,14 @@ use rustc::hir::map::NodeItem;
use rustc::lint::*;
use rustc::ty;
use syntax::ast::NodeId;
use utils::{match_type, paths, span_lint};
use utils::{match_path, match_type, paths, span_lint};
/// **What it does:** Checks for function arguments of type `&String` or `&Vec`
/// unless the references are mutable.
/// **What it does:** This lint checks for function arguments of type `&String` or `&Vec` unless
/// the references are mutable.
///
/// **Why is this bad?** Requiring the argument to be of the specific size makes
/// the function less useful for no benefit; slices in the form of `&[T]` or
/// `&str` usually suffice and can be obtained from other types, too.
/// **Why is this bad?** Requiring the argument to be of the specific size makes the function less
/// useful for no benefit; slices in the form of `&[T]` or `&str` usually suffice and can be
/// obtained from other types, too.
///
/// **Known problems:** None.
///
@ -23,19 +23,38 @@ use utils::{match_type, paths, span_lint};
declare_lint! {
pub PTR_ARG,
Warn,
"arguments of the type `&Vec<...>` (instead of `&[...]`) or `&String` (instead of `&str`)"
"fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` \
instead, respectively"
}
#[derive(Copy,Clone)]
pub struct PtrArg;
/// **What it does:** This lint checks for equality comparisons with `ptr::null`
///
/// **Why is this bad?** It's easier and more readable to use the inherent `.is_null()`
/// method instead
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// if x == ptr::null { .. }
/// ```
declare_lint! {
pub CMP_NULL,
Warn,
"comparing a pointer to a null pointer, suggesting to use `.is_null()` instead."
}
impl LintPass for PtrArg {
#[derive(Copy,Clone)]
pub struct PointerPass;
impl LintPass for PointerPass {
fn get_lints(&self) -> LintArray {
lint_array!(PTR_ARG)
lint_array!(PTR_ARG, CMP_NULL)
}
}
impl LateLintPass for PtrArg {
impl LateLintPass for PointerPass {
fn check_item(&mut self, cx: &LateContext, item: &Item) {
if let ItemFn(ref decl, _, _, _, _, _) = item.node {
check_fn(cx, decl, item.id);
@ -58,6 +77,17 @@ impl LateLintPass for PtrArg {
check_fn(cx, &sig.decl, item.id);
}
}
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
if let ExprBinary(ref op, ref l, ref r) = expr.node {
if (op.node == BiEq || op.node == BiNe) && (is_null_path(l) || is_null_path(r)) {
span_lint(cx,
CMP_NULL,
expr.span,
"Comparing with null is better expressed by the .is_null() method");
}
}
}
}
fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) {
@ -81,3 +111,14 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) {
}
}
}
fn is_null_path(expr: &Expr) -> bool {
if let ExprCall(ref pathexp, ref args) = expr.node {
if args.is_empty() {
if let ExprPath(_, ref path) = pathexp.node {
return match_path(path, &paths::PTR_NULL) || match_path(path, &paths::PTR_NULL_MUT)
}
}
}
false
}

View File

@ -51,8 +51,8 @@ impl LateLintPass for UnsafeNameRemoval {
ViewPath_::ViewPathList(_, ref path_list_items) => {
for path_list_item in path_list_items.iter() {
let plid = path_list_item.node;
if let (Some(name), Some(rename)) = (plid.name(), plid.rename()) {
unsafe_to_safe_check(name, rename, cx, &item.span);
if let Some(rename) = plid.rename {
unsafe_to_safe_check(plid.name, rename, cx, &item.span);
};
}
}

View File

@ -1,14 +1,23 @@
//! Utility functions about comparison operators.
#![deny(missing_docs_in_private_items)]
use rustc::hir::{BinOp_, Expr};
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
/// Represent a normalized comparison operator.
pub enum Rel {
/// `<`
Lt,
/// `<=`
Le,
/// `==`
Eq,
/// `!=`
Ne,
}
/// Put the expression in the form `lhs < rhs` or `lhs <= rhs`.
/// Put the expression in the form `lhs < rhs`, `lhs <= rhs`, `lhs == rhs` or `lhs != rhs`.
pub fn normalize_comparison<'a>(op: BinOp_, lhs: &'a Expr, rhs: &'a Expr)
-> Option<(Rel, &'a Expr, &'a Expr)> {
match op {

View File

@ -1,12 +1,16 @@
//! Read configurations files.
#![deny(missing_docs_in_private_items)]
use std::{fmt, fs, io};
use std::io::Read;
use syntax::{ast, codemap, ptr};
use syntax::{ast, codemap};
use syntax::parse::token;
use toml;
/// Get the configuration file from arguments.
pub fn file(args: &[ptr::P<ast::MetaItem>]) -> Result<Option<token::InternedString>, (&'static str, codemap::Span)> {
for arg in args {
pub fn file(args: &[codemap::Spanned<ast::NestedMetaItemKind>]) -> Result<Option<token::InternedString>, (&'static str, codemap::Span)> {
for arg in args.iter().filter_map(|a| a.meta_item()) {
match arg.node {
ast::MetaItemKind::Word(ref name) |
ast::MetaItemKind::List(ref name, _) => {
@ -32,9 +36,20 @@ pub fn file(args: &[ptr::P<ast::MetaItem>]) -> Result<Option<token::InternedStri
/// Error from reading a configuration file.
#[derive(Debug)]
pub enum Error {
/// An I/O error.
Io(io::Error),
/// The file is not valid TOML.
Toml(Vec<toml::ParserError>),
Type(&'static str, &'static str, &'static str),
/// Type error.
Type(
/// The name of the key.
&'static str,
/// The expected type.
&'static str,
/// The type we got instead.
&'static str
),
/// There is an unknown key is the file.
UnknownKey(String),
}

View File

@ -0,0 +1,21 @@
//! This module contains some useful constants.
#![deny(missing_docs_in_private_items)]
/// List of the built-in types names.
///
/// See also [the reference][reference-types] for a list of such types.
///
/// [reference-types]: https://doc.rust-lang.org/reference.html#types
pub const BUILTIN_TYPES: &'static [&'static str] = &[
"i8", "u8",
"i16", "u16",
"i32", "u32",
"i64", "u64",
"isize", "usize",
"f32",
"f64",
"bool",
"str",
"char",
];

View File

@ -1,5 +1,7 @@
//! This module contains functions for retrieve the original AST from lowered `hir`.
#![deny(missing_docs_in_private_items)]
use rustc::hir;
use rustc::lint::LateContext;
use syntax::ast;
@ -33,14 +35,17 @@ pub fn binop(op: hir::BinOp_) -> ast::BinOpKind {
/// Represent a range akin to `ast::ExprKind::Range`.
#[derive(Debug, Copy, Clone)]
pub struct Range<'a> {
/// The lower bound of the range, or `None` for ranges such as `..X`.
pub start: Option<&'a hir::Expr>,
/// The upper bound of the range, or `None` for ranges such as `X..`.
pub end: Option<&'a hir::Expr>,
/// Whether the interval is open or closed.
pub limits: ast::RangeLimits,
}
/// Higher a `hir` range to something similar to `ast::ExprKind::Range`.
pub fn range(expr: &hir::Expr) -> Option<Range> {
// To be removed when ranges get stable.
/// Skip unstable blocks. To be removed when ranges get stable.
fn unwrap_unstable(expr: &hir::Expr) -> &hir::Expr {
if let hir::ExprBlock(ref block) = expr.node {
if block.rules == hir::BlockCheckMode::PushUnstableBlock || block.rules == hir::BlockCheckMode::PopUnstableBlock {
@ -53,6 +58,7 @@ pub fn range(expr: &hir::Expr) -> Option<Range> {
expr
}
/// Find the field named `name` in the field. Always return `Some` for convenience.
fn get_field<'a>(name: &str, fields: &'a [hir::Field]) -> Option<&'a hir::Expr> {
let expr = &fields.iter()
.find(|field| field.name.node.as_str() == name)

View File

@ -1,7 +1,12 @@
use rustc::lint::*;
use utils::span_lint;
use rustc::hir::*;
use rustc::hir::intravisit::{Visitor, walk_expr};
use utils::{paths, match_path, span_lint};
use syntax::parse::token::InternedString;
use syntax::ast::*;
use syntax::ast::{Name, NodeId, ItemKind, Crate as AstCrate};
use syntax::codemap::Span;
use std::collections::{HashSet, HashMap};
/// **What it does:** Checks for various things we like to keep tidy in clippy.
///
@ -17,6 +22,36 @@ declare_lint! {
}
/// **What it does:** Ensures every lint is associated to a `LintPass`.
///
/// **Why is this bad?** The compiler only knows lints via a `LintPass`. Without
/// putting a lint to a `LintPass::get_lints()`'s return, the compiler will not
/// know the name of the lint.
///
/// **Known problems:** Only checks for lints associated using the `lint_array!`
/// macro.
///
/// **Example:**
/// ```rust
/// declare_lint! { pub LINT_1, ... }
/// declare_lint! { pub LINT_2, ... }
/// declare_lint! { pub FORGOTTEN_LINT, ... }
/// // ...
/// pub struct Pass;
/// impl LintPass for Pass {
/// fn get_lints(&self) -> LintArray {
/// lint_array![LINT_1, LINT_2]
/// // missing FORGOTTEN_LINT
/// }
/// }
/// ```
declare_lint! {
pub LINT_WITHOUT_LINT_PASS,
Warn,
"declaring a lint without associating it in a LintPass"
}
#[derive(Copy, Clone)]
pub struct Clippy;
@ -27,7 +62,7 @@ impl LintPass for Clippy {
}
impl EarlyLintPass for Clippy {
fn check_crate(&mut self, cx: &EarlyContext, krate: &Crate) {
fn check_crate(&mut self, cx: &EarlyContext, krate: &AstCrate) {
if let Some(utils) = krate.module.items.iter().find(|item| item.ident.name.as_str() == "utils") {
if let ItemKind::Mod(ref utils_mod) = utils.node {
if let Some(paths) = utils_mod.items.iter().find(|item| item.ident.name.as_str() == "paths") {
@ -52,3 +87,87 @@ impl EarlyLintPass for Clippy {
}
}
}
#[derive(Clone, Debug, Default)]
pub struct LintWithoutLintPass {
declared_lints: HashMap<Name, Span>,
registered_lints: HashSet<Name>,
}
impl LintPass for LintWithoutLintPass {
fn get_lints(&self) -> LintArray {
lint_array!(LINT_WITHOUT_LINT_PASS)
}
}
impl LateLintPass for LintWithoutLintPass {
fn check_item(&mut self, _: &LateContext, item: &Item) {
if let ItemStatic(ref ty, MutImmutable, ref expr) = item.node {
if is_lint_ref_type(ty) {
self.declared_lints.insert(item.name, item.span);
} else if is_lint_array_type(ty) && item.vis == Visibility::Inherited && item.name.as_str() == "ARRAY" {
let mut collector = LintCollector { output: &mut self.registered_lints };
collector.visit_expr(expr);
}
}
}
fn check_crate_post(&mut self, cx: &LateContext, _: &Crate) {
for (lint_name, &lint_span) in &self.declared_lints {
// When using the `declare_lint!` macro, the original `lint_span`'s
// file points to "<rustc macros>".
// `compiletest-rs` thinks that's an error in a different file and
// just ignores it. This causes the test in compile-fail/lint_pass
// not able to capture the error.
// Therefore, we need to climb the macro expansion tree and find the
// actual span that invoked `declare_lint!`:
let lint_span = cx.sess().codemap().source_callsite(lint_span);
if !self.registered_lints.contains(lint_name) {
span_lint(cx,
LINT_WITHOUT_LINT_PASS,
lint_span,
&format!("the lint `{}` is not added to any `LintPass`", lint_name));
}
}
}
}
fn is_lint_ref_type(ty: &Ty) -> bool {
if let TyRptr(Some(_), MutTy { ty: ref inner, mutbl: MutImmutable }) = ty.node {
if let TyPath(None, ref path) = inner.node {
return match_path(path, &paths::LINT);
}
}
false
}
fn is_lint_array_type(ty: &Ty) -> bool {
if let TyPath(None, ref path) = ty.node {
match_path(path, &paths::LINT_ARRAY)
} else {
false
}
}
struct LintCollector<'a> {
output: &'a mut HashSet<Name>,
}
impl<'v, 'a: 'v> Visitor<'v> for LintCollector<'a> {
fn visit_expr(&mut self, expr: &'v Expr) {
walk_expr(self, expr);
}
fn visit_path(&mut self, path: &'v Path, _: NodeId) {
if path.segments.len() == 1 {
self.output.insert(path.segments[0].name);
}
}
}

View File

@ -22,6 +22,7 @@ use syntax::ptr::P;
pub mod cargo;
pub mod comparisons;
pub mod conf;
pub mod constants;
mod hir;
pub mod paths;
pub mod sugg;
@ -151,11 +152,10 @@ pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool {
apb.names == path
}
/// Check if type is struct or enum type with given def path.
/// Check if type is struct, enum or union type with given def path.
pub fn match_type(cx: &LateContext, ty: ty::Ty, path: &[&str]) -> bool {
match ty.sty {
ty::TyEnum(adt, _) |
ty::TyStruct(adt, _) => match_def_path(cx, adt.did, path),
ty::TyAdt(adt, _) => match_def_path(cx, adt.did, path),
_ => false,
}
}
@ -279,7 +279,7 @@ pub fn implements_trait<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>,
trait_id,
0,
ty,
ty_params);
&ty_params);
traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation)
})
@ -721,7 +721,43 @@ pub fn type_is_unsafe_function(ty: ty::Ty) -> bool {
}
}
pub fn is_copy<'a, 'ctx>(cx: &LateContext<'a, 'ctx>, ty: ty::Ty<'ctx>, env: NodeId) -> bool {
pub fn is_copy<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, env: NodeId) -> bool {
let env = ty::ParameterEnvironment::for_item(cx.tcx, env);
!ty.subst(cx.tcx, env.free_substs).moves_by_default(cx.tcx.global_tcx(), &env, DUMMY_SP)
}
/// Return whether a pattern is refutable.
pub fn is_refutable(cx: &LateContext, pat: &Pat) -> bool {
fn is_enum_variant(cx: &LateContext, did: NodeId) -> bool {
matches!(cx.tcx.def_map.borrow().get(&did).map(|d| d.full_def()), Some(def::Def::Variant(..)))
}
fn are_refutable<'a, I: Iterator<Item=&'a Pat>>(cx: &LateContext, mut i: I) -> bool {
i.any(|pat| is_refutable(cx, pat))
}
match pat.node {
PatKind::Binding(..) | PatKind::Wild => false,
PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => is_refutable(cx, pat),
PatKind::Lit(..) | PatKind::Range(..) => true,
PatKind::Path(..) => is_enum_variant(cx, pat.id),
PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
PatKind::Struct(_, ref fields, _) => {
if is_enum_variant(cx, pat.id) {
true
} else {
are_refutable(cx, fields.iter().map(|field| &*field.node.pat))
}
}
PatKind::TupleStruct(_, ref pats, _) => {
if is_enum_variant(cx, pat.id) {
true
} else {
are_refutable(cx, pats.iter().map(|pat| &**pat))
}
}
PatKind::Vec(ref head, ref middle, ref tail) => {
are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat))
}
}
}

View File

@ -26,11 +26,15 @@ pub const HASHSET: [&'static str; 5] = ["std", "collections", "hash", "set", "Ha
pub const IO_PRINT: [&'static str; 3] = ["std", "io", "_print"];
pub const ITERATOR: [&'static str; 4] = ["core", "iter", "iterator", "Iterator"];
pub const LINKED_LIST: [&'static str; 3] = ["collections", "linked_list", "LinkedList"];
pub const LINT: [&'static str; 3] = ["rustc", "lint", "Lint"];
pub const LINT_ARRAY: [&'static str; 3] = ["rustc", "lint", "LintArray"];
pub const MEM_FORGET: [&'static str; 3] = ["core", "mem", "forget"];
pub const MUTEX: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"];
pub const OPEN_OPTIONS: [&'static str; 3] = ["std", "fs", "OpenOptions"];
pub const OPS_MODULE: [&'static str; 2] = ["core", "ops"];
pub const OPTION: [&'static str; 3] = ["core", "option", "Option"];
pub const PTR_NULL: [&'static str; 2] = ["ptr", "null"];
pub const PTR_NULL_MUT: [&'static str; 2] = ["ptr", "null_mut"];
pub const RANGE: [&'static str; 3] = ["core", "ops", "Range"];
pub const RANGE_FROM: [&'static str; 3] = ["core", "ops", "RangeFrom"];
pub const RANGE_FROM_STD: [&'static str; 3] = ["std", "ops", "RangeFrom"];

View File

@ -1,3 +1,6 @@
//! Contains utility functions to generate suggestions.
#![deny(missing_docs_in_private_items)]
use rustc::hir;
use rustc::lint::{EarlyContext, LateContext, LintContext};
use rustc_errors;
@ -35,6 +38,7 @@ impl<'a> Display for Sugg<'a> {
#[allow(wrong_self_convention)] // ok, because of the function `as_ty` method
impl<'a> Sugg<'a> {
/// Prepare a suggestion from an expression.
pub fn hir_opt(cx: &LateContext, expr: &hir::Expr) -> Option<Sugg<'a>> {
snippet_opt(cx, expr.span).map(|snippet| {
let snippet = Cow::Owned(snippet);
@ -72,10 +76,12 @@ impl<'a> Sugg<'a> {
})
}
/// Convenience function around `hir_opt` for suggestions with a default text.
pub fn hir(cx: &LateContext, expr: &hir::Expr, default: &'a str) -> Sugg<'a> {
Self::hir_opt(cx, expr).unwrap_or_else(|| Sugg::NonParen(Cow::Borrowed(default)))
}
/// Prepare a suggestion from an expression.
pub fn ast(cx: &EarlyContext, expr: &ast::Expr, default: &'a str) -> Sugg<'a> {
use syntax::ast::RangeLimits;
@ -193,12 +199,16 @@ impl<'a> std::ops::Not for Sugg<'a> {
}
}
/// Helper type to display either `foo` or `(foo)`.
struct ParenHelper<T> {
/// Whether parenthesis are needed.
paren: bool,
/// The main thing to display.
wrapped: T,
}
impl<T> ParenHelper<T> {
/// Build a `ParenHelper`.
fn new(paren: bool, wrapped: T) -> Self {
ParenHelper {
paren: paren,
@ -230,14 +240,18 @@ pub fn make_unop(op: &str, expr: Sugg) -> Sugg<'static> {
/// Precedence of shift operator relative to other arithmetic operation is often confusing so
/// parenthesis will always be added for a mix of these.
pub fn make_assoc(op: AssocOp, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> {
/// Whether the operator is a shift operator `<<` or `>>`.
fn is_shift(op: &AssocOp) -> bool {
matches!(*op, AssocOp::ShiftLeft | AssocOp::ShiftRight)
}
/// Whether the operator is a arithmetic operator (`+`, `-`, `*`, `/`, `%`).
fn is_arith(op: &AssocOp) -> bool {
matches!(*op, AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus)
}
/// Whether the operator `op` needs parenthesis with the operator `other` in the direction
/// `dir`.
fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool {
other.precedence() < op.precedence() ||
(other.precedence() == op.precedence() &&
@ -298,10 +312,15 @@ pub fn make_binop(op: ast::BinOpKind, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> {
}
#[derive(PartialEq, Eq)]
/// Operator associativity.
enum Associativity {
/// The operator is both left-associative and right-associative.
Both,
/// The operator is left-associative.
Left,
/// The operator is not associative.
None,
/// The operator is right-associative.
Right,
}
@ -383,6 +402,7 @@ fn indentation<T: LintContext>(cx: &T, span: Span) -> Option<String> {
}
}
/// Convenience extension trait for `DiagnosticBuilder`.
pub trait DiagnosticBuilderExt<T: LintContext> {
/// Suggests to add an attribute to an item.
///

View File

@ -88,8 +88,8 @@ fn check_vec_macro(cx: &LateContext, vec_args: &higher::VecArgs, span: Span) {
/// Return the item type of the vector (ie. the `T` in `Vec<T>`).
fn vec_type(ty: ty::Ty) -> ty::Ty {
if let ty::TyStruct(_, substs) = ty.sty {
substs.types.get(ty::subst::ParamSpace::TypeSpace, 0)
if let ty::TyAdt(_, substs) = ty.sty {
substs.type_at(0)
} else {
panic!("The type of `vec!` is a not a struct?");
}

View File

@ -3,6 +3,7 @@
#![feature(rustc_private)]
#![allow(unknown_lints)]
#![feature(borrow_state)]
#![allow(missing_docs_in_private_items)]
extern crate rustc_plugin;
use rustc_plugin::Registry;

View File

@ -2,6 +2,8 @@
#![feature(box_syntax)]
#![feature(rustc_private)]
#![allow(unknown_lints, missing_docs_in_private_items)]
extern crate clippy_lints;
extern crate getopts;
extern crate rustc;
@ -70,7 +72,7 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls {
let old = std::mem::replace(&mut control.after_parse.callback, box |_| {});
control.after_parse.callback = Box::new(move |state| {
{
let mut registry = rustc_plugin::registry::Registry::new(state.session, state.krate.as_ref().expect("at this compilation stage the krate must be parsed"));
let mut registry = rustc_plugin::registry::Registry::new(state.session, state.krate.as_ref().expect("at this compilation stage the krate must be parsed").span);
registry.args_hidden = Some(Vec::new());
clippy_lints::register_plugins(&mut registry);

View File

@ -0,0 +1,11 @@
#![feature(plugin)]
#![plugin(clippy)]
#![deny(builtin_type_shadow)]
fn foo<u32>(a: u32) -> u32 { //~ERROR shadows the built-in type `u32`
42 //~ERROR E0308
// ^ rustc's type error
}
fn main() {
}

View File

@ -0,0 +1,19 @@
#![feature(plugin)]
#![plugin(clippy)]
#![deny(cmp_null)]
#![allow(unused_mut)]
use std::ptr;
fn main() {
let x = 0;
let p : *const usize = &x;
if p == ptr::null() { //~ERROR: Comparing with null
println!("This is surprising!");
}
let mut y = 0;
let mut m : *mut usize = &mut y;
if m == ptr::null_mut() { //~ERROR: Comparing with null
println!("This is surprising, too!");
}
}

View File

@ -1,9 +1,10 @@
#![feature(plugin)]
#![plugin(clippy)]
#![feature(untagged_unions)]
#![deny(warnings)]
#![allow(dead_code)]
#![allow(unused_variables)] // Temporary fix for rustc false positive. To be removed.
use std::hash::{Hash, Hasher};
@ -46,6 +47,20 @@ impl Clone for Qux {
fn clone(&self) -> Self { Qux }
}
// looks like unions don't support deriving Clone for now
#[derive(Copy)]
union Union {
a: u8,
}
impl Clone for Union {
fn clone(&self) -> Self {
Union {
a: 42,
}
}
}
// See #666
#[derive(Copy)]
struct Lt<'a> {

View File

@ -0,0 +1,37 @@
#![feature(plugin, never_type)]
#![plugin(clippy)]
#![deny(diverging_sub_expression)]
#[allow(empty_loop)]
fn diverge() -> ! { loop {} }
struct A;
impl A {
fn foo(&self) -> ! { diverge() }
}
#[allow(unused_variables, unnecessary_operation)]
fn main() {
let b = true;
b || diverge(); //~ ERROR sub-expression diverges
b || A.foo(); //~ ERROR sub-expression diverges
let y = (5, diverge(), 6); //~ ERROR sub-expression diverges
println!("{}", y.1);
}
#[allow(dead_code, unused_variables)]
fn foobar() {
loop {
let x = match 5 {
4 => return,
5 => continue,
6 => (println!("foo"), return), //~ ERROR sub-expression diverges
7 => (println!("bar"), continue), //~ ERROR sub-expression diverges
8 => break,
9 => diverge(),
3 => (println!("moo"), diverge()), //~ ERROR sub-expression diverges
_ => (println!("boo"), break), //~ ERROR sub-expression diverges
};
}
}

View File

@ -1,7 +1,7 @@
#![feature(plugin)]
#![plugin(clippy)]
#![deny(clippy, clippy_pedantic)]
#![allow(unused_imports, dead_code)]
#![allow(unused_imports, dead_code, missing_docs_in_private_items)]
use std::cmp::Ordering::*; //~ ERROR: don't use glob imports for enum variants

View File

@ -31,7 +31,7 @@ fn ok_box_trait(boxed_trait: &Box<Z>) {
fn warn_call() {
let x = box A; //~ ERROR local variable
x.foo();
x.foo();
}
fn warn_arg(x: Box<A>) { //~ ERROR local variable

View File

@ -2,6 +2,8 @@
#![plugin(clippy)]
#![deny(clippy, clippy_pedantic)]
#![allow(missing_docs_in_private_items)]
fn main() {
let _: Vec<_> = vec![5; 6].into_iter() //~ERROR called `filter(p).map(q)` on an `Iterator`
.filter(|&x| x == 0)

View File

@ -1,18 +1,45 @@
#![feature(plugin)]
#![plugin(clippy)]
struct One;
#![deny(len_without_is_empty, len_zero)]
#![allow(dead_code, unused)]
#[deny(len_without_is_empty)]
impl One {
fn len(self: &Self) -> isize { //~ERROR item `One` has a `.len(_: &Self)`
pub struct PubOne;
impl PubOne {
pub fn len(self: &Self) -> isize { //~ERROR item `PubOne` has a public `len` method but no corresponding `is_empty`
1
}
}
#[deny(len_without_is_empty)]
struct NotPubOne;
impl NotPubOne {
pub fn len(self: &Self) -> isize { // no error, len is pub but `NotPubOne` is not exported anyway
1
}
}
struct One;
impl One {
fn len(self: &Self) -> isize { // no error, len is private, see #1085
1
}
}
pub trait PubTraitsToo {
fn len(self: &Self) -> isize; //~ERROR trait `PubTraitsToo` has a `len` method but no `is_empty`
}
impl PubTraitsToo for One {
fn len(self: &Self) -> isize {
0
}
}
trait TraitsToo {
fn len(self: &Self) -> isize; //~ERROR trait `TraitsToo` has a `.len(_:
fn len(self: &Self) -> isize; // no error, len is private, see #1085
}
impl TraitsToo for One {
@ -21,11 +48,22 @@ impl TraitsToo for One {
}
}
struct HasIsEmpty;
struct HasPrivateIsEmpty;
impl HasPrivateIsEmpty {
pub fn len(self: &Self) -> isize {
1
}
fn is_empty(self: &Self) -> bool {
false
}
}
pub struct HasIsEmpty;
#[deny(len_without_is_empty)]
impl HasIsEmpty {
fn len(self: &Self) -> isize {
pub fn len(self: &Self) -> isize { //~ERROR item `HasIsEmpty` has a public `len` method but a private `is_empty`
1
}
@ -36,8 +74,7 @@ impl HasIsEmpty {
struct Wither;
#[deny(len_without_is_empty)]
trait WithIsEmpty {
pub trait WithIsEmpty {
fn len(self: &Self) -> isize;
fn is_empty(self: &Self) -> bool;
}
@ -52,21 +89,18 @@ impl WithIsEmpty for Wither {
}
}
struct HasWrongIsEmpty;
pub struct HasWrongIsEmpty;
#[deny(len_without_is_empty)]
impl HasWrongIsEmpty {
fn len(self: &Self) -> isize { //~ERROR item `HasWrongIsEmpty` has a `.len(_: &Self)`
pub fn len(self: &Self) -> isize { //~ERROR item `HasWrongIsEmpty` has a public `len` method but no corresponding `is_empty`
1
}
#[allow(dead_code, unused)]
fn is_empty(self: &Self, x : u32) -> bool {
pub fn is_empty(self: &Self, x : u32) -> bool {
false
}
}
#[deny(len_zero)]
fn main() {
let x = [1, 2];
if x.len() == 0 {

View File

@ -0,0 +1,27 @@
#![feature(plugin)]
#![feature(rustc_private)]
#![plugin(clippy)]
#![deny(lint_without_lint_pass)]
#[macro_use] extern crate rustc;
use rustc::lint::{LintPass, LintArray};
declare_lint! { GOOD_LINT, Warn, "good lint" }
declare_lint! { MISSING_LINT, Warn, "missing lint" }
//~^ ERROR: the lint `MISSING_LINT` is not added to any `LintPass`
pub struct Pass;
impl LintPass for Pass {
fn get_lints(&self) -> LintArray {
lint_array![GOOD_LINT]
}
}
fn main() {
let _ = MISSING_LINT;
}

View File

@ -2,6 +2,7 @@
#![plugin(clippy)]
#![deny(mixed_case_hex_literals)]
#![deny(unseparated_literal_suffix)]
#![deny(zero_prefixed_literal)]
#![allow(dead_code)]
fn main() {
@ -22,4 +23,16 @@ fn main() {
let fail5 = 1234isize; //~ERROR integer type suffix should be separated
let fail6 = 1234usize; //~ERROR integer type suffix should be separated
let fail7 = 1.5f32; //~ERROR float type suffix should be separated
let ok9 = 0;
let ok10 = 0_i64;
let fail8 = 0123;
//~^ERROR decimal constant
//~|HELP remove the `0`
//~|SUGGESTION = 123;
//~|HELP use `0o`
//~|SUGGESTION = 0o123;
let ok11 = 0o123;
let ok12 = 0b101010;
}

View File

@ -3,7 +3,7 @@
#![plugin(clippy)]
#![deny(clippy, clippy_pedantic)]
#![allow(blacklisted_name, unused, print_stdout, non_ascii_literal, new_without_default, new_without_default_derive)]
#![allow(blacklisted_name, unused, print_stdout, non_ascii_literal, new_without_default, new_without_default_derive, missing_docs_in_private_items)]
use std::collections::BTreeMap;
use std::collections::HashMap;

View File

@ -0,0 +1,202 @@
/* This file incorporates work covered by the following copyright and
* permission notice:
* Copyright 2013 The Rust Project Developers. See the COPYRIGHT
* file at the top-level directory of this distribution and at
* http://rust-lang.org/COPYRIGHT.
*
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
* option. This file may not be copied, modified, or distributed
* except according to those terms.
*/
#![feature(plugin)]
#![plugin(clippy)]
#![deny(missing_docs_in_private_items)]
// When denying at the crate level, be sure to not get random warnings from the
// injected intrinsics by the compiler.
#![allow(dead_code)]
#![feature(associated_type_defaults)]
//! Some garbage docs for the crate here
#![doc="More garbage"]
type Typedef = String; //~ ERROR: missing documentation for a type alias
pub type PubTypedef = String; //~ ERROR: missing documentation for a type alias
struct Foo { //~ ERROR: missing documentation for a struct
a: isize, //~ ERROR: missing documentation for a struct field
b: isize, //~ ERROR: missing documentation for a struct field
}
pub struct PubFoo { //~ ERROR: missing documentation for a struct
pub a: isize, //~ ERROR: missing documentation for a struct field
b: isize, //~ ERROR: missing documentation for a struct field
}
#[allow(missing_docs_in_private_items)]
pub struct PubFoo2 {
pub a: isize,
pub c: isize,
}
mod module_no_dox {} //~ ERROR: missing documentation for a module
pub mod pub_module_no_dox {} //~ ERROR: missing documentation for a module
/// dox
pub fn foo() {}
pub fn foo2() {} //~ ERROR: missing documentation for a function
fn foo3() {} //~ ERROR: missing documentation for a function
#[allow(missing_docs_in_private_items)] pub fn foo4() {}
/// dox
pub trait A {
/// dox
fn foo(&self);
/// dox
fn foo_with_impl(&self) {}
}
#[allow(missing_docs_in_private_items)]
trait B {
fn foo(&self);
fn foo_with_impl(&self) {}
}
pub trait C { //~ ERROR: missing documentation for a trait
fn foo(&self); //~ ERROR: missing documentation for a trait method
fn foo_with_impl(&self) {} //~ ERROR: missing documentation for a trait method
}
#[allow(missing_docs_in_private_items)]
pub trait D {
fn dummy(&self) { }
}
/// dox
pub trait E {
type AssociatedType; //~ ERROR: missing documentation for an associated type
type AssociatedTypeDef = Self; //~ ERROR: missing documentation for an associated type
/// dox
type DocumentedType;
/// dox
type DocumentedTypeDef = Self;
/// dox
fn dummy(&self) {}
}
impl Foo {
pub fn foo() {} //~ ERROR: missing documentation for a method
fn bar() {} //~ ERROR: missing documentation for a method
}
impl PubFoo {
pub fn foo() {} //~ ERROR: missing documentation for a method
/// dox
pub fn foo1() {}
fn foo2() {} //~ ERROR: missing documentation for a method
#[allow(missing_docs_in_private_items)] pub fn foo3() {}
}
#[allow(missing_docs_in_private_items)]
trait F {
fn a();
fn b(&self);
}
// should need to redefine documentation for implementations of traits
impl F for Foo {
fn a() {}
fn b(&self) {}
}
// It sure is nice if doc(hidden) implies allow(missing_docs), and that it
// applies recursively
#[doc(hidden)]
mod a {
pub fn baz() {}
pub mod b {
pub fn baz() {}
}
}
enum Baz { //~ ERROR: missing documentation for an enum
BazA { //~ ERROR: missing documentation for a variant
a: isize, //~ ERROR: missing documentation for a struct field
b: isize //~ ERROR: missing documentation for a struct field
},
BarB //~ ERROR: missing documentation for a variant
}
pub enum PubBaz { //~ ERROR: missing documentation for an enum
PubBazA { //~ ERROR: missing documentation for a variant
a: isize, //~ ERROR: missing documentation for a struct field
},
}
/// dox
pub enum PubBaz2 {
/// dox
PubBaz2A {
/// dox
a: isize,
},
}
#[allow(missing_docs_in_private_items)]
pub enum PubBaz3 {
PubBaz3A {
b: isize
},
}
#[doc(hidden)]
pub fn baz() {}
const FOO: u32 = 0; //~ ERROR: missing documentation for a const
/// dox
pub const FOO1: u32 = 0;
#[allow(missing_docs_in_private_items)]
pub const FOO2: u32 = 0;
#[doc(hidden)]
pub const FOO3: u32 = 0;
pub const FOO4: u32 = 0; //~ ERROR: missing documentation for a const
static BAR: u32 = 0; //~ ERROR: missing documentation for a static
/// dox
pub static BAR1: u32 = 0;
#[allow(missing_docs_in_private_items)]
pub static BAR2: u32 = 0;
#[doc(hidden)]
pub static BAR3: u32 = 0;
pub static BAR4: u32 = 0; //~ ERROR: missing documentation for a static
mod internal_impl { //~ ERROR: missing documentation for a module
/// dox
pub fn documented() {}
pub fn undocumented1() {} //~ ERROR: missing documentation for a function
pub fn undocumented2() {} //~ ERROR: missing documentation for a function
fn undocumented3() {} //~ ERROR: missing documentation for a function
/// dox
pub mod globbed {
/// dox
pub fn also_documented() {}
pub fn also_undocumented1() {} //~ ERROR: missing documentation for a function
fn also_undocumented2() {} //~ ERROR: missing documentation for a function
}
}
/// dox
pub mod public_interface {
pub use internal_impl::documented as foo;
pub use internal_impl::undocumented1 as bar;
pub use internal_impl::{documented, undocumented2};
pub use internal_impl::globbed::*;
}
fn main() {} //~ ERROR: missing documentation for a function

View File

@ -14,4 +14,11 @@ mod foo {
}
}
// No warning. See <https://github.com/Manishearth/rust-clippy/issues/1220>.
mod bar {
#[allow(module_inception)]
mod bar {
}
}
fn main() {}

View File

@ -4,6 +4,7 @@
#![deny(no_effect, unnecessary_operation)]
#![allow(dead_code)]
#![allow(path_statements)]
#![feature(untagged_unions)]
struct Unit;
struct Tuple(i32);
@ -15,6 +16,11 @@ enum Enum {
Struct { field: i32 },
}
union Union {
a: u8,
b: f64,
}
fn get_number() -> i32 { 0 }
fn get_struct() -> Struct { Struct { field: 0 } }
@ -30,6 +36,7 @@ fn main() {
Tuple(0); //~ERROR statement with no effect
Struct { field: 0 }; //~ERROR statement with no effect
Struct { ..s }; //~ERROR statement with no effect
Union { a: 0 }; //~ERROR statement with no effect
Enum::Tuple(0); //~ERROR statement with no effect
Enum::Struct { field: 0 }; //~ERROR statement with no effect
5 + 6; //~ERROR statement with no effect

View File

@ -1,8 +1,8 @@
#![feature(plugin)]
#![plugin(clippy)]
#![allow(unused_parens, unused_variables)]
#![deny(clippy, clippy_pedantic)]
#![allow(unused_parens, unused_variables, missing_docs_in_private_items)]
fn id<T>(x: T) -> T { x }

View File

@ -0,0 +1,14 @@
#![feature(plugin)]
#![plugin(clippy)]
#![deny(stutter)]
#![allow(dead_code)]
mod foo {
pub fn foo() {}
pub fn foo_bar() {} //~ ERROR: item name starts with its containing module's name
pub fn bar_foo() {} //~ ERROR: item name ends with its containing module's name
pub struct FooCake {} //~ ERROR: item name starts with its containing module's name
pub enum CakeFoo {} //~ ERROR: item name ends with its containing module's name
}
fn main() {}

View File

@ -7,4 +7,8 @@
//~| SUGGESTION #![allow(dead_code)]
extern crate clippy_lints;
// don't lint on unused_import for `use` items
#[allow(unused_imports)]
use std::collections;
fn main() {}

View File

@ -165,3 +165,31 @@ fn issue1017() {
}
}
}
// Issue #1188
fn refutable() {
let a = [42, 1337];
let mut b = a.iter();
// consume all the 42s
while let Some(&42) = b.next() {
}
let a = [(1, 2, 3)];
let mut b = a.iter();
while let Some(&(1, 2, 3)) = b.next() {
}
let a = [Some(42)];
let mut b = a.iter();
while let Some(&None) = b.next() {
}
/* This gives “refutable pattern in `for` loop binding: `&_` not covered”
for &42 in b {}
for &(1, 2, 3) in b {}
for &Option::None in b.next() {}
// */
}

View File

@ -24,7 +24,7 @@ fn dogfood() {
let mut s = String::new();
s.push_str(" -L target/debug/");
s.push_str(" -L target/debug/deps");
s.push_str(" -Zextra-plugins=clippy -Ltarget_recur/debug -Dclippy_pedantic -Dclippy -Dclippy_lints_internal");
s.push_str(" -Zextra-plugins=clippy -Ltarget_recur/debug -Dclippy_pedantic -Dclippy -Dclippy_internal");
config.target_rustcflags = Some(s);
if let Ok(name) = var("TESTNAME") {
config.filter = Some(name.to_owned())

View File

@ -62,7 +62,8 @@
</div>
</div>
<article class="panel panel-default" id="{{lint.id}}" ng-repeat="lint in data | filter:byLevels | filter:search | orderBy:'id' track by lint.id">
<article class="panel panel-default" id="{{lint.id}}"
ng-repeat="lint in data | filter:byLevels | filter:search | orderBy:'id' track by lint.id" on-finish-render="ngRepeatFinished">
<header class="panel-heading" ng-click="open[lint.id] = !open[lint.id]">
<button class="btn btn-default btn-sm pull-right" style="margin-top: -6px;">
<span ng-show="open[lint.id]">&minus;</span>
@ -77,11 +78,11 @@
<span ng-if="lint.level == 'Deny'" class="label label-danger">Deny</span>
<span ng-if="lint.level == 'Deprecated'" class="label label-default">Deprecated</span>
<a href="#{{lint.id}}" class="anchor label label-default">&para;</a>
<a href="#{{lint.id}}" class="anchor label label-default" ng-click="open[lint.id] = true; $event.stopPropagation()">&para;</a>
</h2>
</header>
<ul class="list-group" ng-if="lint.docs" ng-class="{collapse: true, in: open[lint.id]}">
<ul class="list-group lint-docs" ng-if="lint.docs" ng-class="{collapse: true, in: open[lint.id]}">
<li class="list-group-item" ng-repeat="(title, text) in lint.docs">
<h4 class="list-group-item-heading">
{{title}}
@ -96,7 +97,7 @@
<a href="https://github.com/Manishearth/rust-clippy">
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png"/>
</a>
<script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/7.0.0/markdown-it.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.5.0/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.5.0/languages/rust.min.js"></script>
@ -120,6 +121,21 @@
}
});
function scrollToLint(lintId) {
var target = document.getElementById(lintId);
if (!target) {
return;
}
target.scrollIntoView();
}
function scrollToLintByURL($scope) {
var removeListener = $scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) {
scrollToLint(window.location.hash.slice(1));
removeListener();
});
}
angular.module("clippy", [])
.filter('markdown', function ($sce) {
return function (text) {
@ -130,9 +146,22 @@
);
};
})
.controller("lintList", function ($scope, $http) {
.directive('onFinishRender', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
$timeout(function () {
scope.$emit(attr.onFinishRender);
});
}
}
};
})
.controller("lintList", function ($scope, $http, $timeout) {
// Level filter
$scope.levels = {Allow: true, Warn: true, Deny: true, Deprecated: true};
var LEVEL_FILTERS_DEFAULT = {Allow: true, Warn: true, Deny: true, Deprecated: true};
$scope.levels = LEVEL_FILTERS_DEFAULT;
$scope.byLevels = function (lint) {
return $scope.levels[lint.level];
};
@ -141,17 +170,37 @@
$scope.open = {};
$scope.loading = true;
if (window.location.hash.length > 1) {
$scope.search = window.location.hash.slice(1);
$scope.open[window.location.hash.slice(1)] = true;
scrollToLintByURL($scope);
}
$http.get('./lints.json')
.success(function (data) {
$scope.data = data;
$scope.loading = false;
scrollToLintByURL($scope);
})
.error(function (data) {
$scope.error = data;
$scope.loading = false;
});
})
window.addEventListener('hashchange', function () {
// trigger re-render
$timeout(function () {
$scope.levels = LEVEL_FILTERS_DEFAULT;
$scope.search = window.location.hash.slice(1);
$scope.open[window.location.hash.slice(1)] = true;
scrollToLintByURL($scope);
});
return true;
}, false);
});
})();
</script>
</body>
</html>
</html>