mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-03 02:23:20 +00:00
Merge remote-tracking branch 'origin/master' into examples
This commit is contained in:
commit
c89c5d21c1
35
CHANGELOG.md
35
CHANGELOG.md
@ -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 -->
|
||||
|
@ -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
355
README.md
@ -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/).
|
||||
|
@ -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>",
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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`)
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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, "_");
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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! {[
|
||||
|
179
clippy_lints/src/missing_doc.rs
Normal file
179
clippy_lints/src/missing_doc.rs
Normal 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");
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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<()>.",
|
||||
|
@ -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,
|
||||
|
@ -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()) {
|
||||
|
@ -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
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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),
|
||||
}
|
||||
|
||||
|
21
clippy_lints/src/utils/constants.rs
Normal file
21
clippy_lints/src/utils/constants.rs
Normal 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",
|
||||
];
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"];
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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?");
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
11
tests/compile-fail/builtin-type-shadow.rs
Normal file
11
tests/compile-fail/builtin-type-shadow.rs
Normal 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() {
|
||||
}
|
19
tests/compile-fail/cmp_null.rs
Normal file
19
tests/compile-fail/cmp_null.rs
Normal 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!");
|
||||
}
|
||||
}
|
@ -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> {
|
||||
|
37
tests/compile-fail/diverging_sub_expression.rs
Normal file
37
tests/compile-fail/diverging_sub_expression.rs
Normal 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
|
||||
};
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
27
tests/compile-fail/lint_pass.rs
Normal file
27
tests/compile-fail/lint_pass.rs
Normal 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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
202
tests/compile-fail/missing-doc.rs
Normal file
202
tests/compile-fail/missing-doc.rs
Normal 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
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
@ -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 }
|
||||
|
||||
|
14
tests/compile-fail/stutter.rs
Normal file
14
tests/compile-fail/stutter.rs
Normal 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() {}
|
@ -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() {}
|
||||
|
@ -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() {}
|
||||
// */
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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]">−</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">¶</a>
|
||||
<a href="#{{lint.id}}" class="anchor label label-default" ng-click="open[lint.id] = true; $event.stopPropagation()">¶</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>
|
||||
|
Loading…
Reference in New Issue
Block a user