Merge pull request #856 from Manishearth/stuffs
Various ~~small~~ stuffs
This commit is contained in:
commit
63404ff4f2
12
.travis.yml
12
.travis.yml
@ -13,11 +13,15 @@ script:
|
||||
- rm -rf target/ Cargo.lock
|
||||
- cargo test --features debugging
|
||||
|
||||
# only test regex_macros if it compiles
|
||||
- if [[ "$(cargo build --features 'debugging test-regex_macros')" = 101 ]]; then cargo test --features 'debugging test-regex_macros'; fi
|
||||
|
||||
# trigger rebuild of the clippy-service, to keep it up to date with clippy itself
|
||||
after_success:
|
||||
# only test regex_macros if it compiles
|
||||
- |
|
||||
#!/bin/bash
|
||||
cargo test --no-run --features 'debugging test-regex_macros'
|
||||
if [ "$?" != 101 ]; then
|
||||
cargo test --features 'debugging test-regex_macros' compile_test
|
||||
fi
|
||||
# trigger rebuild of the clippy-service, to keep it up to date with clippy itself
|
||||
- |
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
136
CHANGELOG.md
136
CHANGELOG.md
@ -1,6 +1,9 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## Unreleased
|
||||
* New lint: [`temporary_cstring_as_ptr`]
|
||||
|
||||
## 0.0.63 — 2016-04-08
|
||||
* Rustup to *rustc 1.9.0-nightly (7979dd608 2016-04-07)*
|
||||
|
||||
@ -31,7 +34,7 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
## 0.0.56 — 2016-03-23
|
||||
* Update to *rustc 1.9.0-nightly (0dcc413e4 2016-03-22)*
|
||||
* New lint: [`non_expressive_names`]
|
||||
* New lints: [`many_single_char_names`] and [`similar_names`]
|
||||
|
||||
## 0.0.55 — 2016-03-21
|
||||
* Update to *rustc 1.9.0-nightly (02310fd31 2016-03-19)*
|
||||
@ -64,21 +67,150 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
[configuration file]: ./rust-clippy#configuration
|
||||
|
||||
<!-- begin autogenerated links to wiki -->
|
||||
[`absurd_extreme_comparisons`]: https://github.com/Manishearth/rust-clippy/wiki#absurd_extreme_comparisons
|
||||
[`almost_swapped`]: https://github.com/Manishearth/rust-clippy/wiki#almost_swapped
|
||||
[`approx_constant`]: https://github.com/Manishearth/rust-clippy/wiki#approx_constant
|
||||
[`bad_bit_mask`]: https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask
|
||||
[`blacklisted_name`]: https://github.com/Manishearth/rust-clippy/wiki#blacklisted_name
|
||||
[`block_in_if_condition_expr`]: https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr
|
||||
[`block_in_if_condition_stmt`]: https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_stmt
|
||||
[`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
|
||||
[`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
|
||||
[`cast_sign_loss`]: https://github.com/Manishearth/rust-clippy/wiki#cast_sign_loss
|
||||
[`char_lit_as_u8`]: https://github.com/Manishearth/rust-clippy/wiki#char_lit_as_u8
|
||||
[`chars_next_cmp`]: https://github.com/Manishearth/rust-clippy/wiki#chars_next_cmp
|
||||
[`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_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
|
||||
[`doc_markdown`]: https://github.com/Manishearth/rust-clippy/wiki#doc_markdown
|
||||
[`drop_ref`]: https://github.com/Manishearth/rust-clippy/wiki#drop_ref
|
||||
[`duplicate_underscore_argument`]: https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument
|
||||
[`empty_loop`]: https://github.com/Manishearth/rust-clippy/wiki#empty_loop
|
||||
[`enum_clike_unportable_variant`]: https://github.com/Manishearth/rust-clippy/wiki#enum_clike_unportable_variant
|
||||
[`enum_glob_use`]: https://github.com/Manishearth/rust-clippy/wiki#enum_glob_use
|
||||
[`enum_variant_names`]: https://github.com/Manishearth/rust-clippy/wiki#enum_variant_names
|
||||
[`eq_op`]: https://github.com/Manishearth/rust-clippy/wiki#eq_op
|
||||
[`expl_impl_clone_on_copy`]: https://github.com/Manishearth/rust-clippy/wiki#expl_impl_clone_on_copy
|
||||
[`explicit_counter_loop`]: https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop
|
||||
[`explicit_iter_loop`]: https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop
|
||||
[`extend_from_slice`]: https://github.com/Manishearth/rust-clippy/wiki#extend_from_slice
|
||||
[`filter_next`]: https://github.com/Manishearth/rust-clippy/wiki#filter_next
|
||||
[`float_cmp`]: https://github.com/Manishearth/rust-clippy/wiki#float_cmp
|
||||
[`for_kv_map`]: https://github.com/Manishearth/rust-clippy/wiki#for_kv_map
|
||||
[`for_loop_over_option`]: https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_option
|
||||
[`for_loop_over_result`]: https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_result
|
||||
[`identity_op`]: https://github.com/Manishearth/rust-clippy/wiki#identity_op
|
||||
[`if_not_else`]: https://github.com/Manishearth/rust-clippy/wiki#if_not_else
|
||||
[`if_same_then_else`]: https://github.com/Manishearth/rust-clippy/wiki#if_same_then_else
|
||||
[`ifs_same_cond`]: https://github.com/Manishearth/rust-clippy/wiki#ifs_same_cond
|
||||
[`indexing_slicing`]: https://github.com/Manishearth/rust-clippy/wiki#indexing_slicing
|
||||
[`ineffective_bit_mask`]: https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask
|
||||
[`inline_always`]: https://github.com/Manishearth/rust-clippy/wiki#inline_always
|
||||
[`invalid_regex`]: https://github.com/Manishearth/rust-clippy/wiki#invalid_regex
|
||||
[`invalid_upcast_comparisons`]: https://github.com/Manishearth/rust-clippy/wiki#invalid_upcast_comparisons
|
||||
[`items_after_statements`]: https://github.com/Manishearth/rust-clippy/wiki#items_after_statements
|
||||
[`iter_next_loop`]: https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop
|
||||
[`len_without_is_empty`]: https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty
|
||||
[`len_zero`]: https://github.com/Manishearth/rust-clippy/wiki#len_zero
|
||||
[`let_and_return`]: https://github.com/Manishearth/rust-clippy/wiki#let_and_return
|
||||
[`let_unit_value`]: https://github.com/Manishearth/rust-clippy/wiki#let_unit_value
|
||||
[`linkedlist`]: https://github.com/Manishearth/rust-clippy/wiki#linkedlist
|
||||
[`logic_bug`]: https://github.com/Manishearth/rust-clippy/wiki#logic_bug
|
||||
[`manual_swap`]: https://github.com/Manishearth/rust-clippy/wiki#manual_swap
|
||||
[`many_single_char_names`]: https://github.com/Manishearth/rust-clippy/wiki#many_single_char_names
|
||||
[`map_clone`]: https://github.com/Manishearth/rust-clippy/wiki#map_clone
|
||||
[`map_entry`]: https://github.com/Manishearth/rust-clippy/wiki#map_entry
|
||||
[`match_bool`]: https://github.com/Manishearth/rust-clippy/wiki#match_bool
|
||||
[`match_overlapping_arm`]: https://github.com/Manishearth/rust-clippy/wiki#match_overlapping_arm
|
||||
[`match_ref_pats`]: https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats
|
||||
[`match_same_arms`]: https://github.com/Manishearth/rust-clippy/wiki#match_same_arms
|
||||
[`min_max`]: https://github.com/Manishearth/rust-clippy/wiki#min_max
|
||||
[`modulo_one`]: https://github.com/Manishearth/rust-clippy/wiki#modulo_one
|
||||
[`mut_mut`]: https://github.com/Manishearth/rust-clippy/wiki#mut_mut
|
||||
[`mutex_atomic`]: https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic
|
||||
[`mutex_integer`]: https://github.com/Manishearth/rust-clippy/wiki#mutex_integer
|
||||
[`needless_bool`]: https://github.com/Manishearth/rust-clippy/wiki#needless_bool
|
||||
[`needless_lifetimes`]: https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes
|
||||
[`needless_range_loop`]: https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop
|
||||
[`needless_return`]: https://github.com/Manishearth/rust-clippy/wiki#needless_return
|
||||
[`needless_update`]: https://github.com/Manishearth/rust-clippy/wiki#needless_update
|
||||
[`new_ret_no_self`]: https://github.com/Manishearth/rust-clippy/wiki#new_ret_no_self
|
||||
[`new_without_default`]: https://github.com/Manishearth/rust-clippy/wiki#new_without_default
|
||||
[`non_expressive_names`]: https://github.com/Manishearth/rust-clippy/wiki#non_expressive_names
|
||||
[`no_effect`]: https://github.com/Manishearth/rust-clippy/wiki#no_effect
|
||||
[`non_ascii_literal`]: https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal
|
||||
[`nonminimal_bool`]: https://github.com/Manishearth/rust-clippy/wiki#nonminimal_bool
|
||||
[`nonsensical_open_options`]: https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options
|
||||
[`ok_expect`]: https://github.com/Manishearth/rust-clippy/wiki#ok_expect
|
||||
[`option_map_unwrap_or`]: https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or
|
||||
[`option_map_unwrap_or_else`]: https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or_else
|
||||
[`option_unwrap_used`]: https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used
|
||||
[`or_fun_call`]: https://github.com/Manishearth/rust-clippy/wiki#or_fun_call
|
||||
[`out_of_bounds_indexing`]: https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing
|
||||
[`overflow_check_conditional`]: https://github.com/Manishearth/rust-clippy/wiki#overflow_check_conditional
|
||||
[`panic_params`]: https://github.com/Manishearth/rust-clippy/wiki#panic_params
|
||||
[`precedence`]: https://github.com/Manishearth/rust-clippy/wiki#precedence
|
||||
[`print_stdout`]: https://github.com/Manishearth/rust-clippy/wiki#print_stdout
|
||||
[`ptr_arg`]: https://github.com/Manishearth/rust-clippy/wiki#ptr_arg
|
||||
[`range_step_by_zero`]: https://github.com/Manishearth/rust-clippy/wiki#range_step_by_zero
|
||||
[`range_zip_with_len`]: https://github.com/Manishearth/rust-clippy/wiki#range_zip_with_len
|
||||
[`redundant_closure`]: https://github.com/Manishearth/rust-clippy/wiki#redundant_closure
|
||||
[`redundant_closure_call`]: https://github.com/Manishearth/rust-clippy/wiki#redundant_closure_call
|
||||
[`redundant_pattern`]: https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern
|
||||
[`regex_macro`]: https://github.com/Manishearth/rust-clippy/wiki#regex_macro
|
||||
[`result_unwrap_used`]: https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used
|
||||
[`reverse_range_loop`]: https://github.com/Manishearth/rust-clippy/wiki#reverse_range_loop
|
||||
[`search_is_some`]: https://github.com/Manishearth/rust-clippy/wiki#search_is_some
|
||||
[`shadow_reuse`]: https://github.com/Manishearth/rust-clippy/wiki#shadow_reuse
|
||||
[`shadow_same`]: https://github.com/Manishearth/rust-clippy/wiki#shadow_same
|
||||
[`shadow_unrelated`]: https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated
|
||||
[`should_implement_trait`]: https://github.com/Manishearth/rust-clippy/wiki#should_implement_trait
|
||||
[`similar_names`]: https://github.com/Manishearth/rust-clippy/wiki#similar_names
|
||||
[`single_char_pattern`]: https://github.com/Manishearth/rust-clippy/wiki#single_char_pattern
|
||||
[`single_match`]: https://github.com/Manishearth/rust-clippy/wiki#single_match
|
||||
[`single_match_else`]: https://github.com/Manishearth/rust-clippy/wiki#single_match_else
|
||||
[`str_to_string`]: https://github.com/Manishearth/rust-clippy/wiki#str_to_string
|
||||
[`string_add`]: https://github.com/Manishearth/rust-clippy/wiki#string_add
|
||||
[`string_add_assign`]: https://github.com/Manishearth/rust-clippy/wiki#string_add_assign
|
||||
[`string_lit_as_bytes`]: https://github.com/Manishearth/rust-clippy/wiki#string_lit_as_bytes
|
||||
[`string_to_string`]: https://github.com/Manishearth/rust-clippy/wiki#string_to_string
|
||||
[`suspicious_assignment_formatting`]: https://github.com/Manishearth/rust-clippy/wiki#suspicious_assignment_formatting
|
||||
[`suspicious_else_formatting`]: https://github.com/Manishearth/rust-clippy/wiki#suspicious_else_formatting
|
||||
[`temporary_assignment`]: https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment
|
||||
[`temporary_cstring_as_ptr`]: https://github.com/Manishearth/rust-clippy/wiki#temporary_cstring_as_ptr
|
||||
[`too_many_arguments`]: https://github.com/Manishearth/rust-clippy/wiki#too_many_arguments
|
||||
[`toplevel_ref_arg`]: https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg
|
||||
[`transmute_ptr_to_ref`]: https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref
|
||||
[`trivial_regex`]: https://github.com/Manishearth/rust-clippy/wiki#trivial_regex
|
||||
[`type_complexity`]: https://github.com/Manishearth/rust-clippy/wiki#type_complexity
|
||||
[`unicode_not_nfc`]: https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc
|
||||
[`unit_cmp`]: https://github.com/Manishearth/rust-clippy/wiki#unit_cmp
|
||||
[`unnecessary_mut_passed`]: https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed
|
||||
[`unneeded_field_pattern`]: https://github.com/Manishearth/rust-clippy/wiki#unneeded_field_pattern
|
||||
[`unstable_as_mut_slice`]: https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice
|
||||
[`unstable_as_slice`]: https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice
|
||||
[`unused_collect`]: https://github.com/Manishearth/rust-clippy/wiki#unused_collect
|
||||
[`unused_label`]: https://github.com/Manishearth/rust-clippy/wiki#unused_label
|
||||
[`unused_lifetimes`]: https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes
|
||||
[`use_debug`]: https://github.com/Manishearth/rust-clippy/wiki#use_debug
|
||||
[`used_underscore_binding`]: https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding
|
||||
[`useless_format`]: https://github.com/Manishearth/rust-clippy/wiki#useless_format
|
||||
[`useless_transmute`]: https://github.com/Manishearth/rust-clippy/wiki#useless_transmute
|
||||
[`useless_vec`]: https://github.com/Manishearth/rust-clippy/wiki#useless_vec
|
||||
[`while_let_loop`]: https://github.com/Manishearth/rust-clippy/wiki#while_let_loop
|
||||
[`while_let_on_iterator`]: https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator
|
||||
[`wrong_pub_self_convention`]: https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention
|
||||
[`wrong_self_convention`]: https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention
|
||||
[`zero_divided_by_zero`]: https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero
|
||||
[`zero_width_space`]: https://github.com/Manishearth/rust-clippy/wiki#zero_width_space
|
||||
<!-- end autogenerated links to wiki -->
|
||||
|
@ -14,7 +14,7 @@ Table of contents:
|
||||
* [License](#license)
|
||||
|
||||
##Lints
|
||||
There are 140 lints included in this crate:
|
||||
There are 141 lints included in this crate:
|
||||
|
||||
name | default | meaning
|
||||
---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@ -135,6 +135,7 @@ 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 was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`.
|
||||
[transmute_ptr_to_ref](https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref) | warn | transmutes from a pointer to a reference type
|
||||
|
@ -78,17 +78,16 @@ impl LateLintPass for ArrayIndexing {
|
||||
|
||||
// Index is a constant range
|
||||
if let Some(range) = utils::unsugar_range(index) {
|
||||
let start = range.start.map(|start|
|
||||
eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None)).map(|v| v.ok());
|
||||
let end = range.end.map(|end|
|
||||
eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None)).map(|v| v.ok());
|
||||
let start = range.start
|
||||
.map(|start| eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None))
|
||||
.map(|v| v.ok());
|
||||
let end = range.end
|
||||
.map(|end| eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None))
|
||||
.map(|v| v.ok());
|
||||
|
||||
if let Some((start, end)) = to_const_range(start, end, range.limits, size) {
|
||||
if start > size || end > size {
|
||||
utils::span_lint(cx,
|
||||
OUT_OF_BOUNDS_INDEXING,
|
||||
e.span,
|
||||
"range is out of bounds");
|
||||
utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "range is out of bounds");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -111,11 +110,9 @@ impl LateLintPass for ArrayIndexing {
|
||||
}
|
||||
|
||||
/// Returns an option containing a tuple with the start and end (exclusive) of the range.
|
||||
fn to_const_range(start: Option<Option<ConstVal>>,
|
||||
end: Option<Option<ConstVal>>,
|
||||
limits: RangeLimits,
|
||||
fn to_const_range(start: Option<Option<ConstVal>>, end: Option<Option<ConstVal>>, limits: RangeLimits,
|
||||
array_size: ConstInt)
|
||||
-> Option<(ConstInt, ConstInt)> {
|
||||
-> Option<(ConstInt, ConstInt)> {
|
||||
let start = match start {
|
||||
Some(Some(ConstVal::Integral(x))) => x,
|
||||
Some(_) => return None,
|
||||
@ -131,7 +128,7 @@ fn to_const_range(start: Option<Option<ConstVal>>,
|
||||
}
|
||||
}
|
||||
Some(_) => return None,
|
||||
None => array_size
|
||||
None => array_size,
|
||||
};
|
||||
|
||||
Some((start, end))
|
||||
|
@ -7,7 +7,8 @@ use semver::Version;
|
||||
use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind};
|
||||
use syntax::attr::*;
|
||||
use syntax::codemap::Span;
|
||||
use utils::{in_macro, match_path, span_lint, BEGIN_UNWIND};
|
||||
use utils::{in_macro, match_path, span_lint};
|
||||
use utils::paths;
|
||||
|
||||
/// **What it does:** This lint checks for items annotated with `#[inline(always)]`, unless the annotated function is empty or simply panics.
|
||||
///
|
||||
@ -114,7 +115,8 @@ fn is_relevant_block(block: &Block) -> bool {
|
||||
for stmt in &block.stmts {
|
||||
match stmt.node {
|
||||
StmtDecl(_, _) => return true,
|
||||
StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => {
|
||||
StmtExpr(ref expr, _) |
|
||||
StmtSemi(ref expr, _) => {
|
||||
return is_relevant_expr(expr);
|
||||
}
|
||||
}
|
||||
@ -129,7 +131,7 @@ fn is_relevant_expr(expr: &Expr) -> bool {
|
||||
ExprRet(None) | ExprBreak(_) => false,
|
||||
ExprCall(ref path_expr, _) => {
|
||||
if let ExprPath(_, ref path) = path_expr.node {
|
||||
!match_path(path, &BEGIN_UNWIND)
|
||||
!match_path(path, &paths::BEGIN_UNWIND)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u64> {
|
||||
// borrowing.
|
||||
let def_map = cx.tcx.def_map.borrow();
|
||||
match def_map.get(&lit.id) {
|
||||
Some(&PathResolution { base_def: Def::Const(def_id), ..}) => Some(def_id),
|
||||
Some(&PathResolution { base_def: Def::Const(def_id), .. }) => Some(def_id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ struct NonminimalBoolVisitor<'a, 'tcx: 'a>(&'a LateContext<'a, 'tcx>);
|
||||
use quine_mc_cluskey::Bool;
|
||||
struct Hir2Qmm<'a, 'tcx: 'a, 'v> {
|
||||
terminals: Vec<&'v Expr>,
|
||||
cx: &'a LateContext<'a, 'tcx>
|
||||
cx: &'a LateContext<'a, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
|
||||
@ -75,17 +75,17 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
|
||||
match binop.node {
|
||||
BiOr => return Ok(Bool::Or(self.extract(BiOr, &[lhs, rhs], Vec::new())?)),
|
||||
BiAnd => return Ok(Bool::And(self.extract(BiAnd, &[lhs, rhs], Vec::new())?)),
|
||||
_ => {},
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
}
|
||||
ExprLit(ref lit) => {
|
||||
match lit.node {
|
||||
LitKind::Bool(true) => return Ok(Bool::True),
|
||||
LitKind::Bool(false) => return Ok(Bool::False),
|
||||
_ => {},
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
for (n, expr) in self.terminals.iter().enumerate() {
|
||||
@ -95,11 +95,13 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
|
||||
}
|
||||
let negated = match e.node {
|
||||
ExprBinary(binop, ref lhs, ref rhs) => {
|
||||
let mk_expr = |op| Expr {
|
||||
id: DUMMY_NODE_ID,
|
||||
span: DUMMY_SP,
|
||||
attrs: None,
|
||||
node: ExprBinary(dummy_spanned(op), lhs.clone(), rhs.clone()),
|
||||
let mk_expr = |op| {
|
||||
Expr {
|
||||
id: DUMMY_NODE_ID,
|
||||
span: DUMMY_SP,
|
||||
attrs: None,
|
||||
node: ExprBinary(dummy_spanned(op), lhs.clone(), rhs.clone()),
|
||||
}
|
||||
};
|
||||
match binop.node {
|
||||
BiEq => mk_expr(BiNe),
|
||||
@ -110,7 +112,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
|
||||
BiLe => mk_expr(BiGt),
|
||||
_ => continue,
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
if SpanlessEq::new(self.cx).ignore_fn().eq_expr(&negated, expr) {
|
||||
@ -137,17 +139,17 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
|
||||
True => {
|
||||
s.push_str("true");
|
||||
s
|
||||
},
|
||||
}
|
||||
False => {
|
||||
s.push_str("false");
|
||||
s
|
||||
},
|
||||
}
|
||||
Not(ref inner) => {
|
||||
match **inner {
|
||||
And(_) | Or(_) => {
|
||||
s.push('!');
|
||||
recurse(true, cx, inner, terminals, s)
|
||||
},
|
||||
}
|
||||
Term(n) => {
|
||||
if let ExprBinary(binop, ref lhs, ref rhs) = terminals[n as usize].node {
|
||||
let op = match binop.node {
|
||||
@ -159,8 +161,8 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
|
||||
BiGe => " < ",
|
||||
_ => {
|
||||
s.push('!');
|
||||
return recurse(true, cx, inner, terminals, s)
|
||||
},
|
||||
return recurse(true, cx, inner, terminals, s);
|
||||
}
|
||||
};
|
||||
s.push_str(&snip(lhs));
|
||||
s.push_str(op);
|
||||
@ -170,13 +172,13 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
|
||||
s.push('!');
|
||||
recurse(false, cx, inner, terminals, s)
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
s.push('!');
|
||||
recurse(false, cx, inner, terminals, s)
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
And(ref v) => {
|
||||
if brackets {
|
||||
s.push('(');
|
||||
@ -198,7 +200,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
|
||||
s.push(')');
|
||||
}
|
||||
s
|
||||
},
|
||||
}
|
||||
Or(ref v) => {
|
||||
if brackets {
|
||||
s.push('(');
|
||||
@ -212,7 +214,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
|
||||
s.push(')');
|
||||
}
|
||||
s
|
||||
},
|
||||
}
|
||||
Term(n) => {
|
||||
if brackets {
|
||||
if let ExprBinary(..) = terminals[n as usize].node {
|
||||
@ -243,13 +245,13 @@ fn simple_negate(b: Bool) -> Bool {
|
||||
*el = simple_negate(::std::mem::replace(el, True));
|
||||
}
|
||||
Or(v)
|
||||
},
|
||||
}
|
||||
Or(mut v) => {
|
||||
for el in &mut v {
|
||||
*el = simple_negate(::std::mem::replace(el, True));
|
||||
}
|
||||
And(v)
|
||||
},
|
||||
}
|
||||
Not(inner) => *inner,
|
||||
}
|
||||
}
|
||||
@ -271,13 +273,13 @@ fn terminal_stats(b: &Bool) -> Stats {
|
||||
_ => stats.negations += 1,
|
||||
}
|
||||
recurse(inner, stats);
|
||||
},
|
||||
}
|
||||
And(ref v) | Or(ref v) => {
|
||||
stats.ops += v.len() - 1;
|
||||
for inner in v {
|
||||
recurse(inner, stats);
|
||||
}
|
||||
},
|
||||
}
|
||||
Term(n) => stats.terminals[n as usize] += 1,
|
||||
}
|
||||
}
|
||||
@ -306,7 +308,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
|
||||
let mut simplified = expr.simplify();
|
||||
for simple in Bool::Not(Box::new(expr.clone())).simplify() {
|
||||
match simple {
|
||||
Bool::Not(_) | Bool::True | Bool::False => {},
|
||||
Bool::Not(_) | Bool::True | Bool::False => {}
|
||||
_ => simplified.push(Bool::Not(Box::new(simple.clone()))),
|
||||
}
|
||||
let simple_negated = simple_negate(simple);
|
||||
@ -325,28 +327,43 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
|
||||
continue 'simplified;
|
||||
}
|
||||
if stats.terminals[i] != 0 && simplified_stats.terminals[i] == 0 {
|
||||
span_lint_and_then(self.0, LOGIC_BUG, e.span, "this boolean expression contains a logic bug", |db| {
|
||||
db.span_help(h2q.terminals[i].span, "this expression can be optimized out by applying boolean operations to the outer expression");
|
||||
db.span_suggestion(e.span, "it would look like the following", suggest(self.0, suggestion, &h2q.terminals));
|
||||
});
|
||||
span_lint_and_then(self.0,
|
||||
LOGIC_BUG,
|
||||
e.span,
|
||||
"this boolean expression contains a logic bug",
|
||||
|db| {
|
||||
db.span_help(h2q.terminals[i].span,
|
||||
"this expression can be optimized out by applying \
|
||||
boolean operations to the outer expression");
|
||||
db.span_suggestion(e.span,
|
||||
"it would look like the following",
|
||||
suggest(self.0, suggestion, &h2q.terminals));
|
||||
});
|
||||
// don't also lint `NONMINIMAL_BOOL`
|
||||
return;
|
||||
}
|
||||
// if the number of occurrences of a terminal decreases or any of the stats decreases while none increases
|
||||
improvement |= (stats.terminals[i] > simplified_stats.terminals[i]) ||
|
||||
(stats.negations > simplified_stats.negations && stats.ops == simplified_stats.ops) ||
|
||||
(stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations);
|
||||
(stats.negations > simplified_stats.negations &&
|
||||
stats.ops == simplified_stats.ops) ||
|
||||
(stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations);
|
||||
}
|
||||
if improvement {
|
||||
improvements.push(suggestion);
|
||||
}
|
||||
}
|
||||
if !improvements.is_empty() {
|
||||
span_lint_and_then(self.0, NONMINIMAL_BOOL, e.span, "this boolean expression can be simplified", |db| {
|
||||
for suggestion in &improvements {
|
||||
db.span_suggestion(e.span, "try", suggest(self.0, suggestion, &h2q.terminals));
|
||||
}
|
||||
});
|
||||
span_lint_and_then(self.0,
|
||||
NONMINIMAL_BOOL,
|
||||
e.span,
|
||||
"this boolean expression can be simplified",
|
||||
|db| {
|
||||
for suggestion in &improvements {
|
||||
db.span_suggestion(e.span,
|
||||
"try",
|
||||
suggest(self.0, suggestion, &h2q.terminals));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -354,7 +371,9 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
|
||||
|
||||
impl<'a, 'v, 'tcx> Visitor<'v> for NonminimalBoolVisitor<'a, 'tcx> {
|
||||
fn visit_expr(&mut self, e: &'v Expr) {
|
||||
if in_macro(self.0, e.span) { return }
|
||||
if in_macro(self.0, e.span) {
|
||||
return;
|
||||
}
|
||||
match e.node {
|
||||
ExprBinary(binop, _, _) if binop.node == BiOr || binop.node == BiAnd => self.bool_expr(e),
|
||||
ExprUnary(UnNot, ref inner) => {
|
||||
@ -363,7 +382,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for NonminimalBoolVisitor<'a, 'tcx> {
|
||||
} else {
|
||||
walk_expr(self, e);
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => walk_expr(self, e),
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ fn check_if(cx: &LateContext, e: &Expr) {
|
||||
db.span_suggestion(block.span, "try", snippet_block(cx, else_.span, "..").into_owned());
|
||||
});
|
||||
}}
|
||||
} else if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), span: sp, ..}) =
|
||||
} else if let Some(&Expr { node: ExprIf(ref check_inner, ref content, None), span: sp, .. }) =
|
||||
single_stmt_of_block(then) {
|
||||
if e.span.expn_id != sp.expn_id {
|
||||
return;
|
||||
@ -89,7 +89,7 @@ fn check_if(cx: &LateContext, e: &Expr) {
|
||||
|
||||
fn requires_brackets(e: &Expr) -> bool {
|
||||
match e.node {
|
||||
ExprBinary(Spanned {node: n, ..}, _, _) if n == BiEq => false,
|
||||
ExprBinary(Spanned { node: n, .. }, _, _) if n == BiEq => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +85,9 @@ impl PartialEq for Constant {
|
||||
(&Constant::Str(ref ls, ref l_sty), &Constant::Str(ref rs, ref r_sty)) => ls == rs && l_sty == r_sty,
|
||||
(&Constant::Binary(ref l), &Constant::Binary(ref r)) => l == r,
|
||||
(&Constant::Char(l), &Constant::Char(r)) => l == r,
|
||||
(&Constant::Int(l), &Constant::Int(r)) => l.is_negative() == r.is_negative() && l.to_u64_unchecked() == r.to_u64_unchecked(),
|
||||
(&Constant::Int(l), &Constant::Int(r)) => {
|
||||
l.is_negative() == r.is_negative() && l.to_u64_unchecked() == r.to_u64_unchecked()
|
||||
}
|
||||
(&Constant::Float(ref ls, _), &Constant::Float(ref rs, _)) => {
|
||||
// we want `Fw32 == FwAny` and `FwAny == Fw64`, by transitivity we must have
|
||||
// `Fw32 == Fw64` so don’t compare them
|
||||
@ -131,7 +133,8 @@ impl Hash for Constant {
|
||||
Constant::Bool(b) => {
|
||||
b.hash(state);
|
||||
}
|
||||
Constant::Vec(ref v) | Constant::Tuple(ref v) => {
|
||||
Constant::Vec(ref v) |
|
||||
Constant::Tuple(ref v) => {
|
||||
v.hash(state);
|
||||
}
|
||||
Constant::Repeat(ref c, l) => {
|
||||
@ -186,12 +189,16 @@ fn lit_to_constant(lit: &LitKind) -> Constant {
|
||||
LitKind::Int(value, LitIntType::Unsigned(UintTy::U16)) => Constant::Int(ConstInt::U16(value as u16)),
|
||||
LitKind::Int(value, LitIntType::Unsigned(UintTy::U32)) => Constant::Int(ConstInt::U32(value as u32)),
|
||||
LitKind::Int(value, LitIntType::Unsigned(UintTy::U64)) => Constant::Int(ConstInt::U64(value as u64)),
|
||||
LitKind::Int(value, LitIntType::Unsigned(UintTy::Us)) => Constant::Int(ConstInt::Usize(ConstUsize::Us32(value as u32))),
|
||||
LitKind::Int(value, LitIntType::Unsigned(UintTy::Us)) => {
|
||||
Constant::Int(ConstInt::Usize(ConstUsize::Us32(value as u32)))
|
||||
}
|
||||
LitKind::Int(value, LitIntType::Signed(IntTy::I8)) => Constant::Int(ConstInt::I8(value as i8)),
|
||||
LitKind::Int(value, LitIntType::Signed(IntTy::I16)) => Constant::Int(ConstInt::I16(value as i16)),
|
||||
LitKind::Int(value, LitIntType::Signed(IntTy::I32)) => Constant::Int(ConstInt::I32(value as i32)),
|
||||
LitKind::Int(value, LitIntType::Signed(IntTy::I64)) => Constant::Int(ConstInt::I64(value as i64)),
|
||||
LitKind::Int(value, LitIntType::Signed(IntTy::Is)) => Constant::Int(ConstInt::Isize(ConstIsize::Is32(value as i32))),
|
||||
LitKind::Int(value, LitIntType::Signed(IntTy::Is)) => {
|
||||
Constant::Int(ConstInt::Isize(ConstIsize::Is32(value as i32)))
|
||||
}
|
||||
LitKind::Float(ref is, ty) => Constant::Float(is.to_string(), ty.into()),
|
||||
LitKind::FloatUnsuffixed(ref is) => Constant::Float(is.to_string(), FloatWidth::Any),
|
||||
LitKind::Bool(b) => Constant::Bool(b),
|
||||
@ -285,7 +292,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
|
||||
fn fetch_path(&mut self, e: &Expr) -> Option<Constant> {
|
||||
if let Some(lcx) = self.lcx {
|
||||
let mut maybe_id = None;
|
||||
if let Some(&PathResolution { base_def: Def::Const(id), ..}) = lcx.tcx.def_map.borrow().get(&e.id) {
|
||||
if let Some(&PathResolution { base_def: Def::Const(id), .. }) = lcx.tcx.def_map.borrow().get(&e.id) {
|
||||
maybe_id = Some(id);
|
||||
}
|
||||
// separate if lets to avoid double borrowing the def_map
|
||||
@ -324,7 +331,11 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
|
||||
}
|
||||
|
||||
fn binop(&mut self, op: BinOp, left: &Expr, right: &Expr) -> Option<Constant> {
|
||||
let l = if let Some(l) = self.expr(left) { l } else { return None; };
|
||||
let l = if let Some(l) = self.expr(left) {
|
||||
l
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
let r = self.expr(right);
|
||||
match (op.node, l, r) {
|
||||
(BiAdd, Constant::Int(l), Some(Constant::Int(r))) => (l + r).ok().map(Constant::Int),
|
||||
|
@ -71,7 +71,7 @@ impl LateLintPass for CopyAndPaste {
|
||||
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
|
||||
if !in_macro(cx, expr.span) {
|
||||
// skip ifs directly in else, it will be checked in the parent if
|
||||
if let Some(&Expr{node: ExprIf(_, _, Some(ref else_expr)), ..}) = get_parent_expr(cx, expr) {
|
||||
if let Some(&Expr { node: ExprIf(_, _, Some(ref else_expr)), .. }) = get_parent_expr(cx, expr) {
|
||||
if else_expr.id == expr.id {
|
||||
return;
|
||||
}
|
||||
@ -185,7 +185,8 @@ fn if_sequence(mut expr: &Expr) -> (SmallVector<&Expr>, SmallVector<&Block>) {
|
||||
fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<InternedString, ty::Ty<'tcx>> {
|
||||
fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut HashMap<InternedString, ty::Ty<'tcx>>) {
|
||||
match pat.node {
|
||||
PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map),
|
||||
PatKind::Box(ref pat) |
|
||||
PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map),
|
||||
PatKind::TupleStruct(_, Some(ref pats)) => {
|
||||
for pat in pats {
|
||||
bindings_impl(cx, pat, map);
|
||||
|
@ -1,12 +1,12 @@
|
||||
//! calculate cyclomatic complexity and warn about overly complex functions
|
||||
|
||||
use rustc::lint::*;
|
||||
use rustc::cfg::CFG;
|
||||
use rustc::lint::*;
|
||||
use rustc::ty;
|
||||
use rustc::hir::*;
|
||||
use rustc::hir::intravisit::{Visitor, walk_expr};
|
||||
use syntax::ast::Attribute;
|
||||
use syntax::attr::*;
|
||||
use syntax::attr;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
use utils::{in_macro, LimitStack, span_help_and_lint};
|
||||
@ -44,6 +44,7 @@ impl CyclomaticComplexity {
|
||||
if in_macro(cx, span) {
|
||||
return;
|
||||
}
|
||||
|
||||
let cfg = CFG::new(cx.tcx, block);
|
||||
let n = cfg.graph.len_nodes() as u64;
|
||||
let e = cfg.graph.len_edges() as u64;
|
||||
@ -59,12 +60,7 @@ impl CyclomaticComplexity {
|
||||
tcx: &cx.tcx,
|
||||
};
|
||||
helper.visit_block(block);
|
||||
let CCHelper {
|
||||
match_arms,
|
||||
divergence,
|
||||
short_circuits,
|
||||
..
|
||||
} = helper;
|
||||
let CCHelper { match_arms, divergence, short_circuits, .. } = helper;
|
||||
|
||||
if cc + divergence < match_arms + short_circuits {
|
||||
report_cc_bug(cx, cc, match_arms, divergence, short_circuits, span);
|
||||
@ -84,7 +80,9 @@ impl CyclomaticComplexity {
|
||||
impl LateLintPass for CyclomaticComplexity {
|
||||
fn check_item(&mut self, cx: &LateContext, item: &Item) {
|
||||
if let ItemFn(_, _, _, _, _, ref block) = item.node {
|
||||
self.check(cx, block, item.span);
|
||||
if !attr::contains_name(&item.attrs, "test") {
|
||||
self.check(cx, block, item.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,7 +127,8 @@ impl<'a, 'b, 'tcx> Visitor<'a> for CCHelper<'b, 'tcx> {
|
||||
walk_expr(self, e);
|
||||
let ty = self.tcx.node_id_to_type(callee.id);
|
||||
match ty.sty {
|
||||
ty::TyFnDef(_, _, ty) | ty::TyFnPtr(ty) if ty.sig.skip_binder().output.diverges() => {
|
||||
ty::TyFnDef(_, _, ty) |
|
||||
ty::TyFnPtr(ty) if ty.sig.skip_binder().output.diverges() => {
|
||||
self.divergence += 1;
|
||||
}
|
||||
_ => (),
|
||||
@ -140,7 +139,7 @@ impl<'a, 'b, 'tcx> Visitor<'a> for CCHelper<'b, 'tcx> {
|
||||
walk_expr(self, e);
|
||||
match op.node {
|
||||
BiAnd | BiOr => self.short_circuits += 1,
|
||||
_ => {},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
_ => walk_expr(self, e),
|
||||
@ -153,10 +152,10 @@ fn report_cc_bug(_: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, sp
|
||||
span_bug!(span,
|
||||
"Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \
|
||||
div = {}, shorts = {}. Please file a bug report.",
|
||||
cc,
|
||||
narms,
|
||||
div,
|
||||
shorts);
|
||||
cc,
|
||||
narms,
|
||||
div,
|
||||
shorts);
|
||||
}
|
||||
#[cfg(not(feature="debugging"))]
|
||||
fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, span: Span) {
|
||||
|
@ -5,7 +5,7 @@ use rustc::ty;
|
||||
use rustc::hir::*;
|
||||
use syntax::ast::{Attribute, MetaItemKind};
|
||||
use syntax::codemap::Span;
|
||||
use utils::{CLONE_TRAIT_PATH, HASH_PATH};
|
||||
use utils::paths;
|
||||
use utils::{match_path, span_lint_and_then};
|
||||
|
||||
/// **What it does:** This lint warns about deriving `Hash` but implementing `PartialEq`
|
||||
@ -88,7 +88,7 @@ impl LateLintPass for Derive {
|
||||
/// Implementation of the `DERIVE_HASH_XOR_EQ` lint.
|
||||
fn check_hash_peq<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, trait_ref: &TraitRef, ty: ty::Ty<'tcx>, hash_is_automatically_derived: bool) {
|
||||
if_let_chain! {[
|
||||
match_path(&trait_ref.path, &HASH_PATH),
|
||||
match_path(&trait_ref.path, &paths::HASH),
|
||||
let Some(peq_trait_def_id) = cx.tcx.lang_items.eq_trait()
|
||||
], {
|
||||
let peq_trait_def = cx.tcx.lookup_trait_def(peq_trait_def_id);
|
||||
@ -129,7 +129,7 @@ fn check_hash_peq<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, trait_ref: &
|
||||
|
||||
/// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
|
||||
fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref: &TraitRef, ty: ty::Ty<'tcx>) {
|
||||
if match_path(&trait_ref.path, &CLONE_TRAIT_PATH) {
|
||||
if match_path(&trait_ref.path, &paths::CLONE_TRAIT) {
|
||||
let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, item.id);
|
||||
let subst_ty = ty.subst(cx.tcx, ¶meter_environment.free_substs);
|
||||
|
||||
|
11
src/doc.rs
11
src/doc.rs
@ -142,10 +142,10 @@ pub fn check_doc(cx: &EarlyContext, valid_idents: &[String], doc: &str, span: Sp
|
||||
}
|
||||
'`' => {
|
||||
current_word_begin = jump_to!(chars, '`', len);
|
||||
},
|
||||
}
|
||||
'[' => {
|
||||
let end = jump_to!(chars, ']', len);
|
||||
let link_text = &doc[current_word_begin+1..end];
|
||||
let link_text = &doc[current_word_begin + 1..end];
|
||||
|
||||
match chars.peek() {
|
||||
Some(&(_, c)) => {
|
||||
@ -199,7 +199,7 @@ fn check_word(cx: &EarlyContext, valid_idents: &[String], word: &str, span: Span
|
||||
}
|
||||
|
||||
let s = if s.ends_with('s') {
|
||||
&s[..s.len()-1]
|
||||
&s[..s.len() - 1]
|
||||
} else {
|
||||
s
|
||||
};
|
||||
@ -223,6 +223,9 @@ fn check_word(cx: &EarlyContext, valid_idents: &[String], word: &str, span: Span
|
||||
}
|
||||
|
||||
if has_underscore(word) || word.contains("::") || is_camel_case(word) {
|
||||
span_lint(cx, DOC_MARKDOWN, span, &format!("you should put `{}` between ticks in the documentation", word));
|
||||
span_lint(cx,
|
||||
DOC_MARKDOWN,
|
||||
span,
|
||||
&format!("you should put `{}` between ticks in the documentation", word));
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,7 @@ use rustc::lint::*;
|
||||
use rustc::ty;
|
||||
use rustc::hir::*;
|
||||
use syntax::codemap::Span;
|
||||
use utils::DROP_PATH;
|
||||
use utils::{match_def_path, span_note_and_lint};
|
||||
use utils::{match_def_path, paths, span_note_and_lint};
|
||||
|
||||
/// **What it does:** This lint checks for calls to `std::mem::drop` with a reference instead of an owned value.
|
||||
///
|
||||
@ -37,7 +36,7 @@ impl LateLintPass for DropRefPass {
|
||||
if let ExprCall(ref path, ref args) = expr.node {
|
||||
if let ExprPath(None, _) = path.node {
|
||||
let def_id = cx.tcx.def_map.borrow()[&path.id].def_id();
|
||||
if match_def_path(cx, def_id, &DROP_PATH) {
|
||||
if match_def_path(cx, def_id, &paths::DROP) {
|
||||
if args.len() != 1 {
|
||||
return;
|
||||
}
|
||||
|
11
src/entry.rs
11
src/entry.rs
@ -1,10 +1,9 @@
|
||||
use rustc::lint::*;
|
||||
use rustc::hir::*;
|
||||
use rustc::hir::intravisit::{Visitor, walk_expr, walk_block};
|
||||
use rustc::lint::*;
|
||||
use syntax::codemap::Span;
|
||||
use utils::SpanlessEq;
|
||||
use utils::{BTREEMAP_PATH, HASHMAP_PATH};
|
||||
use utils::{get_item_name, match_type, snippet, span_lint_and_then, walk_ptrs_ty};
|
||||
use utils::{get_item_name, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty};
|
||||
|
||||
/// **What it does:** This lint checks for uses of `contains_key` + `insert` on `HashMap` or
|
||||
/// `BTreeMap`.
|
||||
@ -48,7 +47,7 @@ impl LateLintPass for HashMapLint {
|
||||
// in case of `if !m.contains_key(&k) { m.insert(k, v); }`
|
||||
// we can give a better error message
|
||||
let sole_expr = else_block.is_none() &&
|
||||
((then_block.expr.is_some() as usize) + then_block.stmts.len() == 1);
|
||||
((then_block.expr.is_some() as usize) + then_block.stmts.len() == 1);
|
||||
|
||||
let mut visitor = InsertVisitor {
|
||||
cx: cx,
|
||||
@ -89,10 +88,10 @@ fn check_cond<'a, 'tcx, 'b>(cx: &'a LateContext<'a, 'tcx>, check: &'b Expr) -> O
|
||||
let map = ¶ms[0];
|
||||
let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(map));
|
||||
|
||||
return if match_type(cx, obj_ty, &BTREEMAP_PATH) {
|
||||
return if match_type(cx, obj_ty, &paths::BTREEMAP) {
|
||||
Some(("BTreeMap", map, key))
|
||||
}
|
||||
else if match_type(cx, obj_ty, &HASHMAP_PATH) {
|
||||
else if match_type(cx, obj_ty, &paths::HASHMAP) {
|
||||
Some(("HashMap", map, key))
|
||||
}
|
||||
else {
|
||||
|
@ -54,7 +54,7 @@ impl EnumGlobUse {
|
||||
let child = cx.sess().cstore.item_children(def.def_id());
|
||||
if let Some(child) = child.first() {
|
||||
if let DefLike::DlDef(Def::Variant(..)) = child.def {
|
||||
span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants");
|
||||
span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,9 +60,10 @@ fn check_closure(cx: &LateContext, expr: &Expr) {
|
||||
let fn_ty = cx.tcx.expr_ty(caller);
|
||||
match fn_ty.sty {
|
||||
// Is it an unsafe function? They don't implement the closure traits
|
||||
ty::TyFnDef(_, _, fn_ty) | ty::TyFnPtr(fn_ty) => {
|
||||
ty::TyFnDef(_, _, fn_ty) |
|
||||
ty::TyFnPtr(fn_ty) => {
|
||||
if fn_ty.unsafety == Unsafety::Unsafe ||
|
||||
fn_ty.sig.skip_binder().output == ty::FnOutput::FnDiverging {
|
||||
fn_ty.sig.skip_binder().output == ty::FnOutput::FnDiverging {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
use rustc::hir::*;
|
||||
use rustc::hir::map::Node::NodeItem;
|
||||
use rustc::lint::*;
|
||||
use rustc::ty::TypeVariants;
|
||||
use rustc::hir::*;
|
||||
use syntax::ast::LitKind;
|
||||
use utils::{DISPLAY_FMT_METHOD_PATH, FMT_ARGUMENTS_NEWV1_PATH, STRING_PATH};
|
||||
use utils::paths;
|
||||
use utils::{is_expn_of, match_path, match_type, span_lint, walk_ptrs_ty};
|
||||
|
||||
/// **What it does:** This lints about use of `format!("string literal with no argument")` and
|
||||
@ -40,7 +40,7 @@ impl LateLintPass for FormatMacLint {
|
||||
if_let_chain!{[
|
||||
let ExprPath(_, ref path) = fun.node,
|
||||
args.len() == 2,
|
||||
match_path(path, &FMT_ARGUMENTS_NEWV1_PATH),
|
||||
match_path(path, &paths::FMT_ARGUMENTS_NEWV1),
|
||||
// ensure the format string is `"{..}"` with only one argument and no text
|
||||
check_static_str(cx, &args[0]),
|
||||
// ensure the format argument is `{}` ie. Display with no fancy option
|
||||
@ -108,11 +108,11 @@ fn check_arg_is_display(cx: &LateContext, expr: &Expr) -> bool {
|
||||
let ExprCall(_, ref args) = exprs[0].node,
|
||||
args.len() == 2,
|
||||
let ExprPath(None, ref path) = args[1].node,
|
||||
match_path(path, &DISPLAY_FMT_METHOD_PATH)
|
||||
match_path(path, &paths::DISPLAY_FMT_METHOD)
|
||||
], {
|
||||
let ty = walk_ptrs_ty(cx.tcx.pat_ty(&pat[0]));
|
||||
|
||||
return ty.sty == TypeVariants::TyStr || match_type(cx, ty, &STRING_PATH);
|
||||
return ty.sty == TypeVariants::TyStr || match_type(cx, ty, &paths::STRING);
|
||||
}}
|
||||
|
||||
false
|
||||
|
@ -31,9 +31,7 @@ pub struct Functions {
|
||||
|
||||
impl Functions {
|
||||
pub fn new(threshold: u64) -> Functions {
|
||||
Functions {
|
||||
threshold: threshold
|
||||
}
|
||||
Functions { threshold: threshold }
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +47,8 @@ impl LateLintPass for Functions {
|
||||
|
||||
if let Some(NodeItem(ref item)) = cx.tcx.map.find(cx.tcx.map.get_parent_node(nodeid)) {
|
||||
match item.node {
|
||||
hir::ItemImpl(_, _, _, Some(_), _, _) | hir::ItemDefaultImpl(..) => return,
|
||||
hir::ItemImpl(_, _, _, Some(_), _, _) |
|
||||
hir::ItemDefaultImpl(..) => return,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
@ -68,7 +67,9 @@ impl Functions {
|
||||
fn check_arg_number(&self, cx: &LateContext, decl: &hir::FnDecl, span: Span) {
|
||||
let args = decl.inputs.len() as u64;
|
||||
if args > self.threshold {
|
||||
span_lint(cx, TOO_MANY_ARGUMENTS, span,
|
||||
span_lint(cx,
|
||||
TOO_MANY_ARGUMENTS,
|
||||
span,
|
||||
&format!("this function has to many arguments ({}/{})", args, self.threshold));
|
||||
}
|
||||
}
|
||||
|
@ -37,15 +37,15 @@ impl EarlyLintPass for IfNotElse {
|
||||
item.span,
|
||||
"Unnecessary boolean `not` operation",
|
||||
"remove the `!` and swap the blocks of the if/else");
|
||||
},
|
||||
}
|
||||
ExprKind::Binary(ref kind, _, _) if kind.node == BinOpKind::Ne => {
|
||||
span_help_and_lint(cx,
|
||||
IF_NOT_ELSE,
|
||||
item.span,
|
||||
"Unnecessary `!=` operation",
|
||||
"change to `==` and swap the blocks of the if/else");
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ impl LateLintPass for LenZero {
|
||||
return;
|
||||
}
|
||||
|
||||
if let ExprBinary(Spanned{node: cmp, ..}, ref left, ref right) = expr.node {
|
||||
if let ExprBinary(Spanned { node: cmp, .. }, ref left, ref right) = expr.node {
|
||||
match cmp {
|
||||
BiEq => check_cmp(cx, expr.span, left, right, ""),
|
||||
BiGt | BiNe => check_cmp(cx, expr.span, left, right, "!"),
|
||||
@ -155,7 +155,7 @@ fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str)
|
||||
}
|
||||
|
||||
fn check_len_zero(cx: &LateContext, span: Span, name: &Name, args: &[P<Expr>], lit: &Lit, op: &str) {
|
||||
if let Spanned{node: LitKind::Int(0, _), ..} = *lit {
|
||||
if let Spanned { node: LitKind::Int(0, _), .. } = *lit {
|
||||
if name.as_str() == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) {
|
||||
span_lint_and_then(cx, LEN_ZERO, span, "length comparison to zero", |db| {
|
||||
db.span_suggestion(span,
|
||||
@ -199,7 +199,8 @@ 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(ref id, _) | ty::TyStruct(ref id, _) => has_is_empty_impl(cx, &id.did),
|
||||
ty::TyEnum(ref id, _) |
|
||||
ty::TyStruct(ref id, _) => has_is_empty_impl(cx, &id.did),
|
||||
ty::TyArray(..) | ty::TyStr => true,
|
||||
_ => false,
|
||||
}
|
||||
|
@ -325,6 +325,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
||||
methods::SEARCH_IS_SOME,
|
||||
methods::SHOULD_IMPLEMENT_TRAIT,
|
||||
methods::SINGLE_CHAR_PATTERN,
|
||||
methods::TEMPORARY_CSTRING_AS_PTR,
|
||||
methods::WRONG_SELF_CONVENTION,
|
||||
minmax::MIN_MAX,
|
||||
misc::CMP_NAN,
|
||||
|
@ -127,7 +127,7 @@ fn could_use_elision<'a, T: Iterator<Item = &'a Lifetime>>(cx: &LateContext, fun
|
||||
match slf.node {
|
||||
SelfRegion(ref opt_lt, _, _) => input_visitor.record(opt_lt),
|
||||
SelfExplicit(ref ty, _) => walk_ty(&mut input_visitor, ty),
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
// extract lifetimes in input argument types
|
||||
@ -243,7 +243,8 @@ impl<'v, 't> RefVisitor<'v, 't> {
|
||||
if params.lifetimes.is_empty() {
|
||||
if let Some(def) = self.cx.tcx.def_map.borrow().get(&ty.id).map(|r| r.full_def()) {
|
||||
match def {
|
||||
Def::TyAlias(def_id) | Def::Struct(def_id) => {
|
||||
Def::TyAlias(def_id) |
|
||||
Def::Struct(def_id) => {
|
||||
let type_scheme = self.cx.tcx.lookup_item_type(def_id);
|
||||
for _ in type_scheme.generics.regions.as_slice() {
|
||||
self.record(&None);
|
||||
@ -255,7 +256,7 @@ impl<'v, 't> RefVisitor<'v, 't> {
|
||||
self.record(&None);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -277,7 +278,7 @@ impl<'v, 't> Visitor<'v> for RefVisitor<'v, 't> {
|
||||
TyPath(_, ref path) => {
|
||||
self.collect_anonymous_lifetimes(path, ty);
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
walk_ty(self, ty);
|
||||
}
|
||||
@ -353,7 +354,7 @@ fn report_extra_lifetimes(cx: &LateContext, func: &FnDecl, generics: &Generics,
|
||||
match slf.node {
|
||||
SelfRegion(Some(ref lt), _, _) => checker.visit_lifetime(lt),
|
||||
SelfExplicit(ref t, _) => walk_ty(&mut checker, t),
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
26
src/loops.rs
26
src/loops.rs
@ -14,9 +14,9 @@ use std::collections::HashMap;
|
||||
use syntax::ast;
|
||||
|
||||
use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro,
|
||||
span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then,
|
||||
unsugar_range, walk_ptrs_ty, recover_for_loop};
|
||||
use utils::{BTREEMAP_PATH, HASHMAP_PATH, LL_PATH, OPTION_PATH, RESULT_PATH, VEC_PATH};
|
||||
span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, unsugar_range,
|
||||
walk_ptrs_ty, recover_for_loop};
|
||||
use utils::paths;
|
||||
use utils::UnsugaredRange;
|
||||
|
||||
/// **What it does:** This lint checks for looping over the range of `0..len` of some collection just to get the values by index.
|
||||
@ -247,7 +247,8 @@ impl LateLintPass for LoopsPass {
|
||||
if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node {
|
||||
// ensure "if let" compatible match structure
|
||||
match *source {
|
||||
MatchSource::Normal | MatchSource::IfLetDesugar{..} => {
|
||||
MatchSource::Normal |
|
||||
MatchSource::IfLetDesugar { .. } => {
|
||||
if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none() &&
|
||||
arms[1].pats.len() == 1 && arms[1].guard.is_none() &&
|
||||
is_break_expr(&arms[1].body) {
|
||||
@ -505,7 +506,7 @@ fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) {
|
||||
/// Check for `for` loops over `Option`s and `Results`
|
||||
fn check_arg_type(cx: &LateContext, pat: &Pat, arg: &Expr) {
|
||||
let ty = cx.tcx.expr_ty(arg);
|
||||
if match_type(cx, ty, &OPTION_PATH) {
|
||||
if match_type(cx, ty, &paths::OPTION) {
|
||||
span_help_and_lint(cx,
|
||||
FOR_LOOP_OVER_OPTION,
|
||||
arg.span,
|
||||
@ -515,7 +516,7 @@ fn check_arg_type(cx: &LateContext, pat: &Pat, arg: &Expr) {
|
||||
&format!("consider replacing `for {0} in {1}` with `if let Some({0}) = {1}`",
|
||||
snippet(cx, pat.span, "_"),
|
||||
snippet(cx, arg.span, "_")));
|
||||
} else if match_type(cx, ty, &RESULT_PATH) {
|
||||
} else if match_type(cx, ty, &paths::RESULT) {
|
||||
span_help_and_lint(cx,
|
||||
FOR_LOOP_OVER_RESULT,
|
||||
arg.span,
|
||||
@ -589,7 +590,7 @@ fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Ex
|
||||
};
|
||||
|
||||
let ty = walk_ptrs_ty(cx.tcx.expr_ty(arg));
|
||||
if match_type(cx, ty, &HASHMAP_PATH) || match_type(cx, ty, &BTREEMAP_PATH) {
|
||||
if match_type(cx, ty, &paths::HASHMAP) || match_type(cx, ty, &paths::BTREEMAP) {
|
||||
span_lint_and_then(cx,
|
||||
FOR_KV_MAP,
|
||||
expr.span,
|
||||
@ -735,13 +736,13 @@ fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool {
|
||||
// will allow further borrows afterwards
|
||||
let ty = cx.tcx.expr_ty(e);
|
||||
is_iterable_array(ty) ||
|
||||
match_type(cx, ty, &VEC_PATH) ||
|
||||
match_type(cx, ty, &LL_PATH) ||
|
||||
match_type(cx, ty, &HASHMAP_PATH) ||
|
||||
match_type(cx, ty, &paths::VEC) ||
|
||||
match_type(cx, ty, &paths::LINKED_LIST) ||
|
||||
match_type(cx, ty, &paths::HASHMAP) ||
|
||||
match_type(cx, ty, &["std", "collections", "hash", "set", "HashSet"]) ||
|
||||
match_type(cx, ty, &["collections", "vec_deque", "VecDeque"]) ||
|
||||
match_type(cx, ty, &["collections", "binary_heap", "BinaryHeap"]) ||
|
||||
match_type(cx, ty, &BTREEMAP_PATH) ||
|
||||
match_type(cx, ty, &paths::BTREEMAP) ||
|
||||
match_type(cx, ty, &["collections", "btree", "set", "BTreeSet"])
|
||||
}
|
||||
|
||||
@ -779,7 +780,8 @@ fn extract_first_expr(block: &Block) -> Option<&Expr> {
|
||||
Some(ref expr) => Some(expr),
|
||||
None if !block.stmts.is_empty() => {
|
||||
match block.stmts[0].node {
|
||||
StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => Some(expr),
|
||||
StmtExpr(ref expr, _) |
|
||||
StmtSemi(ref expr, _) => Some(expr),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
use rustc::lint::*;
|
||||
use rustc::hir::*;
|
||||
use utils::{CLONE_PATH, OPTION_PATH};
|
||||
use utils::{is_adjusted, match_path, match_trait_method, match_type, snippet, span_help_and_lint, walk_ptrs_ty,
|
||||
walk_ptrs_ty_depth};
|
||||
use utils::{is_adjusted, match_path, match_trait_method, match_type, paths, snippet,
|
||||
span_help_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth};
|
||||
|
||||
/// **What it does:** This lint checks for mapping clone() over an iterator.
|
||||
///
|
||||
@ -65,7 +64,7 @@ impl LateLintPass for MapClonePass {
|
||||
}
|
||||
}
|
||||
ExprPath(_, ref path) => {
|
||||
if match_path(path, &CLONE_PATH) {
|
||||
if match_path(path, &paths::CLONE) {
|
||||
let type_name = get_type_name(cx, expr, &args[0]).unwrap_or("_");
|
||||
span_help_and_lint(cx,
|
||||
MAP_CLONE,
|
||||
@ -99,7 +98,7 @@ fn expr_eq_ident(expr: &Expr, id: Ident) -> bool {
|
||||
fn get_type_name(cx: &LateContext, expr: &Expr, arg: &Expr) -> Option<&'static str> {
|
||||
if match_trait_method(cx, expr, &["core", "iter", "Iterator"]) {
|
||||
Some("iterator")
|
||||
} else if match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(arg)), &OPTION_PATH) {
|
||||
} else if match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(arg)), &paths::OPTION) {
|
||||
Some("Option")
|
||||
} else {
|
||||
None
|
||||
|
@ -8,7 +8,7 @@ use rustc_const_math::ConstInt;
|
||||
use std::cmp::Ordering;
|
||||
use syntax::ast::LitKind;
|
||||
use syntax::codemap::Span;
|
||||
use utils::{COW_PATH, OPTION_PATH, RESULT_PATH};
|
||||
use utils::paths;
|
||||
use utils::{match_type, snippet, span_note_and_lint, span_lint_and_then, in_external_macro, expr_block};
|
||||
|
||||
/// **What it does:** This lint checks for matches with a single arm where an `if let` will usually suffice.
|
||||
@ -184,13 +184,13 @@ fn check_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm],
|
||||
|
||||
fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, ty: ty::Ty, els: Option<&Expr>) {
|
||||
// list of candidate Enums we know will never get any more members
|
||||
let candidates = &[(&COW_PATH, "Borrowed"),
|
||||
(&COW_PATH, "Cow::Borrowed"),
|
||||
(&COW_PATH, "Cow::Owned"),
|
||||
(&COW_PATH, "Owned"),
|
||||
(&OPTION_PATH, "None"),
|
||||
(&RESULT_PATH, "Err"),
|
||||
(&RESULT_PATH, "Ok")];
|
||||
let candidates = &[(&paths::COW, "Borrowed"),
|
||||
(&paths::COW, "Cow::Borrowed"),
|
||||
(&paths::COW, "Cow::Owned"),
|
||||
(&paths::COW, "Owned"),
|
||||
(&paths::OPTION, "None"),
|
||||
(&paths::RESULT, "Err"),
|
||||
(&paths::RESULT, "Ok")];
|
||||
|
||||
let path = match arms[1].pats[0].node {
|
||||
PatKind::TupleStruct(ref path, Some(ref inner)) => {
|
||||
@ -252,19 +252,20 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) {
|
||||
|
||||
if let Some((ref true_expr, ref false_expr)) = exprs {
|
||||
match (is_unit_expr(true_expr), is_unit_expr(false_expr)) {
|
||||
(false, false) =>
|
||||
(false, false) => {
|
||||
Some(format!("if {} {} else {}",
|
||||
snippet(cx, ex.span, "b"),
|
||||
expr_block(cx, true_expr, None, ".."),
|
||||
expr_block(cx, false_expr, None, ".."))),
|
||||
(false, true) =>
|
||||
Some(format!("if {} {}",
|
||||
snippet(cx, ex.span, "b"),
|
||||
expr_block(cx, true_expr, None, ".."))),
|
||||
(true, false) =>
|
||||
expr_block(cx, false_expr, None, "..")))
|
||||
}
|
||||
(false, true) => {
|
||||
Some(format!("if {} {}", snippet(cx, ex.span, "b"), expr_block(cx, true_expr, None, "..")))
|
||||
}
|
||||
(true, false) => {
|
||||
Some(format!("try\nif !{} {}",
|
||||
snippet(cx, ex.span, "b"),
|
||||
expr_block(cx, false_expr, None, ".."))),
|
||||
expr_block(cx, false_expr, None, "..")))
|
||||
}
|
||||
(true, true) => None,
|
||||
}
|
||||
} else {
|
||||
@ -312,9 +313,7 @@ fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: Match
|
||||
expr.span,
|
||||
"you don't need to add `&` to both the expression and the patterns",
|
||||
|db| {
|
||||
db.span_suggestion(expr.span,
|
||||
"try",
|
||||
template);
|
||||
db.span_suggestion(expr.span, "try", template);
|
||||
});
|
||||
} else {
|
||||
let template = match_template(cx, expr.span, source, "*", ex);
|
||||
@ -324,7 +323,8 @@ fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: Match
|
||||
"you don't need to add `&` to all patterns",
|
||||
|db| {
|
||||
db.span_suggestion(expr.span,
|
||||
"instead of prefixing all patterns with `&`, you can dereference the expression",
|
||||
"instead of prefixing all patterns with `&`, you can \
|
||||
dereference the expression",
|
||||
template);
|
||||
});
|
||||
}
|
||||
@ -373,17 +373,18 @@ type TypedRanges = Vec<SpannedRange<ConstInt>>;
|
||||
/// Get all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway and other types than
|
||||
/// `Uint` and `Int` probably don't make sense.
|
||||
fn type_ranges(ranges: &[SpannedRange<ConstVal>]) -> TypedRanges {
|
||||
ranges.iter().filter_map(|range| {
|
||||
if let (ConstVal::Integral(start), ConstVal::Integral(end)) = range.node {
|
||||
Some(SpannedRange {
|
||||
span: range.span,
|
||||
node: (start, end),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
ranges.iter()
|
||||
.filter_map(|range| {
|
||||
if let (ConstVal::Integral(start), ConstVal::Integral(end)) = range.node {
|
||||
Some(SpannedRange {
|
||||
span: range.span,
|
||||
node: (start, end),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn is_unit_expr(expr: &Expr) -> bool {
|
||||
@ -416,7 +417,7 @@ fn match_template(cx: &LateContext, span: Span, source: MatchSource, op: &str, e
|
||||
MatchSource::IfLetDesugar { .. } => format!("if let .. = {}{} {{ .. }}", op, expr_snippet),
|
||||
MatchSource::WhileLetDesugar => format!("while let .. = {}{} {{ .. }}", op, expr_snippet),
|
||||
MatchSource::ForLoopDesugar => span_bug!(span, "for loop desugared to match with &-patterns!"),
|
||||
MatchSource::TryDesugar => span_bug!(span, "`?` operator desugared to match with &-patterns!")
|
||||
MatchSource::TryDesugar => span_bug!(span, "`?` operator desugared to match with &-patterns!"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -432,13 +433,15 @@ pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &
|
||||
impl<'a, T: Copy> Kind<'a, T> {
|
||||
fn range(&self) -> &'a SpannedRange<T> {
|
||||
match *self {
|
||||
Kind::Start(_, r) | Kind::End(_, r) => r,
|
||||
Kind::Start(_, r) |
|
||||
Kind::End(_, r) => r,
|
||||
}
|
||||
}
|
||||
|
||||
fn value(self) -> T {
|
||||
match self {
|
||||
Kind::Start(t, _) | Kind::End(t, _) => t,
|
||||
Kind::Start(t, _) |
|
||||
Kind::End(t, _) => t,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,9 +13,8 @@ use syntax::ptr::P;
|
||||
use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, match_path, match_trait_method,
|
||||
match_type, method_chain_args, return_ty, same_tys, snippet, snippet_opt, span_lint,
|
||||
span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth};
|
||||
use utils::{BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, OPTION_PATH, RESULT_PATH,
|
||||
VEC_PATH};
|
||||
use utils::MethodArgs;
|
||||
use utils::paths;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MethodsPass;
|
||||
@ -286,6 +285,33 @@ declare_lint! {
|
||||
`_.split(\"x\")`"
|
||||
}
|
||||
|
||||
/// **What it does:** This lint checks for getting the inner pointer of a temporary `CString`.
|
||||
///
|
||||
/// **Why is this bad?** The inner pointer of a `CString` is only valid as long as the `CString` is
|
||||
/// alive.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust,ignore
|
||||
/// let c_str = CString::new("foo").unwrap().as_ptr();
|
||||
/// unsafe {
|
||||
/// call_some_ffi_func(c_str);
|
||||
/// }
|
||||
/// ```
|
||||
/// Here `c_str` point to a freed address. The correct use would be:
|
||||
/// ```rust,ignore
|
||||
/// let c_str = CString::new("foo").unwrap();
|
||||
/// unsafe {
|
||||
/// call_some_ffi_func(c_str.as_ptr());
|
||||
/// }
|
||||
/// ```
|
||||
declare_lint! {
|
||||
pub TEMPORARY_CSTRING_AS_PTR,
|
||||
Warn,
|
||||
"getting the inner pointer of a temporary `CString`"
|
||||
}
|
||||
|
||||
impl LintPass for MethodsPass {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(EXTEND_FROM_SLICE,
|
||||
@ -303,7 +329,8 @@ impl LintPass for MethodsPass {
|
||||
CLONE_DOUBLE_REF,
|
||||
NEW_RET_NO_SELF,
|
||||
SINGLE_CHAR_PATTERN,
|
||||
SEARCH_IS_SOME)
|
||||
SEARCH_IS_SOME,
|
||||
TEMPORARY_CSTRING_AS_PTR)
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,7 +361,11 @@ impl LateLintPass for MethodsPass {
|
||||
lint_search_is_some(cx, expr, "rposition", arglists[0], arglists[1]);
|
||||
} else if let Some(arglists) = method_chain_args(expr, &["extend"]) {
|
||||
lint_extend(cx, expr, arglists[0]);
|
||||
} else if let Some(arglists) = method_chain_args(expr, &["unwrap", "as_ptr"]) {
|
||||
lint_cstring_as_ptr(cx, expr, &arglists[0][0], &arglists[1][0]);
|
||||
}
|
||||
|
||||
|
||||
lint_or_fun_call(cx, expr, &name.node.as_str(), &args);
|
||||
if args.len() == 1 && name.node.as_str() == "clone" {
|
||||
lint_clone_on_copy(cx, expr);
|
||||
@ -405,7 +436,8 @@ impl LateLintPass for MethodsPass {
|
||||
}
|
||||
|
||||
let ret_ty = return_ty(cx, implitem.id);
|
||||
if &name.as_str() == &"new" && !ret_ty.map_or(false, |ret_ty| ret_ty.walk().any(|t| same_tys(cx, t, ty, implitem.id))) {
|
||||
if &name.as_str() == &"new" &&
|
||||
!ret_ty.map_or(false, |ret_ty| ret_ty.walk().any(|t| same_tys(cx, t, ty, implitem.id))) {
|
||||
span_lint(cx,
|
||||
NEW_RET_NO_SELF,
|
||||
sig.explicit_self.span,
|
||||
@ -438,7 +470,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>])
|
||||
|
||||
if ["default", "new"].contains(&path) {
|
||||
let arg_ty = cx.tcx.expr_ty(arg);
|
||||
let default_trait_id = if let Some(default_trait_id) = get_trait_def_id(cx, &DEFAULT_TRAIT_PATH) {
|
||||
let default_trait_id = if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT) {
|
||||
default_trait_id
|
||||
} else {
|
||||
return false;
|
||||
@ -465,13 +497,13 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>])
|
||||
fn check_general_case(cx: &LateContext, name: &str, fun: &Expr, self_expr: &Expr, arg: &Expr, or_has_args: bool,
|
||||
span: Span) {
|
||||
// (path, fn_has_argument, methods)
|
||||
let know_types: &[(&[_], _, &[_], _)] = &[(&BTREEMAP_ENTRY_PATH, false, &["or_insert"], "with"),
|
||||
(&HASHMAP_ENTRY_PATH, false, &["or_insert"], "with"),
|
||||
(&OPTION_PATH,
|
||||
let know_types: &[(&[_], _, &[_], _)] = &[(&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
|
||||
(&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
|
||||
(&paths::OPTION,
|
||||
false,
|
||||
&["map_or", "ok_or", "or", "unwrap_or"],
|
||||
"else"),
|
||||
(&RESULT_PATH, true, &["or", "unwrap_or"], "else")];
|
||||
(&paths::RESULT, true, &["or", "unwrap_or"], "else")];
|
||||
|
||||
let self_ty = cx.tcx.expr_ty(self_expr);
|
||||
|
||||
@ -539,7 +571,7 @@ fn lint_clone_double_ref(cx: &LateContext, expr: &Expr, arg: &Expr) {
|
||||
|
||||
fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) {
|
||||
let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0]));
|
||||
if !match_type(cx, obj_ty, &VEC_PATH) {
|
||||
if !match_type(cx, obj_ty, &paths::VEC) {
|
||||
return;
|
||||
}
|
||||
let arg_ty = cx.tcx.expr_ty(&args[1]);
|
||||
@ -554,11 +586,27 @@ fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) {
|
||||
}
|
||||
}
|
||||
|
||||
fn lint_cstring_as_ptr(cx: &LateContext, expr: &Expr, new: &Expr, unwrap: &Expr) {
|
||||
if_let_chain!{[
|
||||
let ExprCall(ref fun, ref args) = new.node,
|
||||
args.len() == 1,
|
||||
let ExprPath(None, ref path) = fun.node,
|
||||
match_path(path, &paths::CSTRING_NEW),
|
||||
], {
|
||||
span_lint_and_then(cx, TEMPORARY_CSTRING_AS_PTR, expr.span,
|
||||
"you are getting the inner pointer of a temporary `CString`",
|
||||
|db| {
|
||||
db.fileline_note(expr.span, "that pointer will be invalid outside this expression");
|
||||
db.span_help(unwrap.span, "assign the `CString` to a variable to extend its lifetime");
|
||||
});
|
||||
}}
|
||||
}
|
||||
|
||||
fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) -> Option<(Span, &'static str)> {
|
||||
fn may_slice(cx: &LateContext, ty: &ty::Ty) -> bool {
|
||||
match ty.sty {
|
||||
ty::TySlice(_) => true,
|
||||
ty::TyStruct(..) => match_type(cx, ty, &VEC_PATH),
|
||||
ty::TyStruct(..) => match_type(cx, ty, &paths::VEC),
|
||||
ty::TyArray(_, size) => size < 32,
|
||||
ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) |
|
||||
ty::TyBox(ref inner) => may_slice(cx, inner),
|
||||
@ -593,9 +641,9 @@ fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) -> Option<(Span,
|
||||
fn lint_unwrap(cx: &LateContext, expr: &Expr, unwrap_args: &MethodArgs) {
|
||||
let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&unwrap_args[0]));
|
||||
|
||||
let mess = if match_type(cx, obj_ty, &OPTION_PATH) {
|
||||
let mess = if match_type(cx, obj_ty, &paths::OPTION) {
|
||||
Some((OPTION_UNWRAP_USED, "an Option", "None"))
|
||||
} else if match_type(cx, obj_ty, &RESULT_PATH) {
|
||||
} else if match_type(cx, obj_ty, &paths::RESULT) {
|
||||
Some((RESULT_UNWRAP_USED, "a Result", "Err"))
|
||||
} else {
|
||||
None
|
||||
@ -618,7 +666,7 @@ fn lint_unwrap(cx: &LateContext, expr: &Expr, unwrap_args: &MethodArgs) {
|
||||
/// lint use of `ok().expect()` for `Result`s
|
||||
fn lint_ok_expect(cx: &LateContext, expr: &Expr, ok_args: &MethodArgs) {
|
||||
// lint if the caller of `ok()` is a `Result`
|
||||
if match_type(cx, cx.tcx.expr_ty(&ok_args[0]), &RESULT_PATH) {
|
||||
if match_type(cx, cx.tcx.expr_ty(&ok_args[0]), &paths::RESULT) {
|
||||
let result_type = cx.tcx.expr_ty(&ok_args[0]);
|
||||
if let Some(error_type) = get_error_type(cx, result_type) {
|
||||
if has_debug_impl(error_type, cx) {
|
||||
@ -636,7 +684,7 @@ fn lint_ok_expect(cx: &LateContext, expr: &Expr, ok_args: &MethodArgs) {
|
||||
/// lint use of `map().unwrap_or()` for `Option`s
|
||||
fn lint_map_unwrap_or(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, unwrap_args: &MethodArgs) {
|
||||
// lint if the caller of `map()` is an `Option`
|
||||
if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &OPTION_PATH) {
|
||||
if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &paths::OPTION) {
|
||||
// lint message
|
||||
let msg = "called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling \
|
||||
`map_or(a, f)` instead";
|
||||
@ -667,7 +715,7 @@ fn lint_map_unwrap_or(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, unwr
|
||||
/// lint use of `map().unwrap_or_else()` for `Option`s
|
||||
fn lint_map_unwrap_or_else(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, unwrap_args: &MethodArgs) {
|
||||
// lint if the caller of `map()` is an `Option`
|
||||
if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &OPTION_PATH) {
|
||||
if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &paths::OPTION) {
|
||||
// lint message
|
||||
let msg = "called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling \
|
||||
`map_or_else(g, f)` instead";
|
||||
@ -794,7 +842,7 @@ fn lint_single_char_pattern(cx: &LateContext, expr: &Expr, arg: &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, &RESULT_PATH) {
|
||||
if !match_type(cx, ty, &paths::RESULT) {
|
||||
return None;
|
||||
}
|
||||
if let ty::TyEnum(_, substs) = ty.sty {
|
||||
@ -805,7 +853,7 @@ fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// This checks whether a given type is known to implement `Debug`.
|
||||
/// This checks whether a given type is known to implement Debug.
|
||||
fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool {
|
||||
match cx.tcx.lang_items.debug_trait() {
|
||||
Some(debug) => implements_trait(cx, ty, debug, Vec::new()),
|
||||
@ -899,7 +947,8 @@ impl SelfKind {
|
||||
(&SelfKind::Ref, &SelfRegion(_, Mutability::MutImmutable, _)) |
|
||||
(&SelfKind::RefMut, &SelfRegion(_, Mutability::MutMutable, _)) |
|
||||
(&SelfKind::No, &SelfStatic) => true,
|
||||
(&SelfKind::Ref, &SelfValue(_)) | (&SelfKind::RefMut, &SelfValue(_)) => allow_value_for_ref,
|
||||
(&SelfKind::Ref, &SelfValue(_)) |
|
||||
(&SelfKind::RefMut, &SelfValue(_)) => allow_value_for_ref,
|
||||
(_, &SelfExplicit(ref ty, _)) => self.matches_explicit_type(ty, allow_value_for_ref),
|
||||
_ => false,
|
||||
}
|
||||
|
@ -34,7 +34,9 @@ impl LateLintPass for MinMaxPass {
|
||||
return;
|
||||
}
|
||||
match (outer_max, outer_c.partial_cmp(&inner_c)) {
|
||||
(_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (),
|
||||
(_, None) |
|
||||
(MinMax::Max, Some(Ordering::Less)) |
|
||||
(MinMax::Min, Some(Ordering::Greater)) => (),
|
||||
_ => {
|
||||
span_lint(cx, MIN_MAX, expr.span, "this min/max combination leads to constant result");
|
||||
}
|
||||
|
@ -226,7 +226,7 @@ impl LateLintPass for CmpOwned {
|
||||
|
||||
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 => {
|
||||
ExprMethodCall(Spanned { node: ref name, .. }, _, ref args) if args.len() == 1 => {
|
||||
if name.as_str() == "to_string" || name.as_str() == "to_owned" && is_str_arg(cx, args) {
|
||||
(cx.tcx.expr_ty(&args[0]), snippet(cx, args[0].span, ".."))
|
||||
} else {
|
||||
@ -309,7 +309,7 @@ impl LintPass for ModuloOne {
|
||||
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 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");
|
||||
}
|
||||
@ -422,7 +422,8 @@ impl LateLintPass for UsedUnderscoreBinding {
|
||||
fn is_used(cx: &LateContext, expr: &Expr) -> bool {
|
||||
if let Some(ref parent) = get_parent_expr(cx, expr) {
|
||||
match parent.node {
|
||||
ExprAssign(_, ref rhs) | ExprAssignOp(_, _, ref rhs) => **rhs == *expr,
|
||||
ExprAssign(_, ref rhs) |
|
||||
ExprAssignOp(_, _, ref rhs) => **rhs == *expr,
|
||||
_ => is_used(cx, &parent),
|
||||
}
|
||||
} else {
|
||||
|
@ -134,11 +134,11 @@ impl EarlyLintPass for MiscEarly {
|
||||
expr.span,
|
||||
"Try not to call a closure in the expression where it is declared.",
|
||||
|db| {
|
||||
if decl.inputs.is_empty() {
|
||||
let hint = format!("{}", snippet(cx, block.span, ".."));
|
||||
db.span_suggestion(expr.span, "Try doing something like: ", hint);
|
||||
}
|
||||
});
|
||||
if decl.inputs.is_empty() {
|
||||
let hint = format!("{}", snippet(cx, block.span, ".."));
|
||||
db.span_suggestion(expr.span, "Try doing something like: ", hint);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ fn check_expr_mut(cx: &LateContext, expr: &Expr) {
|
||||
|
||||
unwrap_addr(expr).map_or((), |e| {
|
||||
unwrap_addr(e).map_or_else(|| {
|
||||
if let TyRef(_, TypeAndMut{mutbl: MutMutable, ..}) = cx.tcx.expr_ty(e).sty {
|
||||
if let TyRef(_, TypeAndMut { mutbl: MutMutable, .. }) = cx.tcx.expr_ty(e).sty {
|
||||
span_lint(cx,
|
||||
MUT_MUT,
|
||||
expr.span,
|
||||
@ -71,7 +71,7 @@ fn check_expr_mut(cx: &LateContext, expr: &Expr) {
|
||||
|
||||
fn unwrap_mut(ty: &Ty) -> Option<&Ty> {
|
||||
match ty.node {
|
||||
TyRptr(_, MutTy{ ty: ref pty, mutbl: MutMutable }) => Some(pty),
|
||||
TyRptr(_, MutTy { ty: ref pty, mutbl: MutMutable }) => Some(pty),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -47,19 +47,20 @@ impl LateLintPass for UnnecessaryMutPassed {
|
||||
let method_type = borrowed_table.method_map.get(&method_call).expect("This should never happen.");
|
||||
check_arguments(cx, &arguments, method_type.ty, &name.node.as_str())
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_arguments(cx: &LateContext, arguments: &[P<Expr>], type_definition: &TyS, name: &str) {
|
||||
match type_definition.sty {
|
||||
TypeVariants::TyFnDef(_, _, ref fn_type) | TypeVariants::TyFnPtr(ref fn_type) => {
|
||||
TypeVariants::TyFnDef(_, _, ref fn_type) |
|
||||
TypeVariants::TyFnPtr(ref fn_type) => {
|
||||
let parameters = &fn_type.sig.skip_binder().inputs;
|
||||
for (argument, parameter) in arguments.iter().zip(parameters.iter()) {
|
||||
match parameter.sty {
|
||||
TypeVariants::TyRef(_, TypeAndMut {mutbl: MutImmutable, ..}) |
|
||||
TypeVariants::TyRawPtr(TypeAndMut {mutbl: MutImmutable, ..}) => {
|
||||
TypeVariants::TyRef(_, TypeAndMut { mutbl: MutImmutable, .. }) |
|
||||
TypeVariants::TyRawPtr(TypeAndMut { mutbl: MutImmutable, .. }) => {
|
||||
if let ExprAddrOf(MutMutable, _) = argument.node {
|
||||
span_lint(cx,
|
||||
UNNECESSARY_MUT_PASSED,
|
||||
@ -67,7 +68,7 @@ fn check_arguments(cx: &LateContext, arguments: &[P<Expr>], type_definition: &Ty
|
||||
&format!("The function/method \"{}\" doesn't need a mutable reference", name));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use rustc::ty::subst::ParamSpace;
|
||||
use rustc::ty;
|
||||
use rustc::hir::Expr;
|
||||
use syntax::ast;
|
||||
use utils::{span_lint, MUTEX_PATH, match_type};
|
||||
use utils::{match_type, paths, span_lint};
|
||||
|
||||
/// **What it does:** This lint checks for usages of `Mutex<X>` where an atomic will do.
|
||||
///
|
||||
@ -47,7 +47,7 @@ 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 match_type(cx, ty, &MUTEX_PATH) {
|
||||
if match_type(cx, ty, &paths::MUTEX) {
|
||||
let mutex_param = &subst.types.get(ParamSpace::TypeSpace, 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 \
|
||||
|
@ -57,9 +57,10 @@ impl LateLintPass for NeedlessBool {
|
||||
span_lint_and_then(cx,
|
||||
NEEDLESS_BOOL,
|
||||
e.span,
|
||||
"this if-then-else expression returns a bool literal", |db| {
|
||||
db.span_suggestion(e.span, "you can reduce it to", hint);
|
||||
});
|
||||
"this if-then-else expression returns a bool literal",
|
||||
|db| {
|
||||
db.span_suggestion(e.span, "you can reduce it to", hint);
|
||||
});
|
||||
};
|
||||
match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) {
|
||||
(RetBool(true), RetBool(true)) |
|
||||
@ -98,7 +99,7 @@ impl LintPass for BoolComparison {
|
||||
impl LateLintPass for BoolComparison {
|
||||
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
|
||||
use self::Expression::*;
|
||||
if let ExprBinary(Spanned{ node: BiEq, .. }, ref left_side, ref right_side) = e.node {
|
||||
if let ExprBinary(Spanned { node: BiEq, .. }, ref left_side, ref right_side) = e.node {
|
||||
match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
|
||||
(Bool(true), Other) => {
|
||||
let hint = snippet(cx, right_side.span, "..").into_owned();
|
||||
@ -155,15 +156,17 @@ enum Expression {
|
||||
fn fetch_bool_block(block: &Block) -> Expression {
|
||||
match (&*block.stmts, block.expr.as_ref()) {
|
||||
([], Some(e)) => fetch_bool_expr(&**e),
|
||||
([ref e], None) => if let StmtSemi(ref e, _) = e.node {
|
||||
if let ExprRet(_) = e.node {
|
||||
fetch_bool_expr(&**e)
|
||||
([ref e], None) => {
|
||||
if let StmtSemi(ref e, _) = e.node {
|
||||
if let ExprRet(_) = e.node {
|
||||
fetch_bool_expr(&**e)
|
||||
} else {
|
||||
Expression::Other
|
||||
}
|
||||
} else {
|
||||
Expression::Other
|
||||
}
|
||||
} else {
|
||||
Expression::Other
|
||||
},
|
||||
}
|
||||
_ => Expression::Other,
|
||||
}
|
||||
}
|
||||
@ -177,11 +180,13 @@ fn fetch_bool_expr(expr: &Expr) -> Expression {
|
||||
} else {
|
||||
Expression::Other
|
||||
}
|
||||
},
|
||||
ExprRet(Some(ref expr)) => match fetch_bool_expr(expr) {
|
||||
Expression::Bool(value) => Expression::RetBool(value),
|
||||
_ => Expression::Other,
|
||||
},
|
||||
}
|
||||
ExprRet(Some(ref expr)) => {
|
||||
match fetch_bool_expr(expr) {
|
||||
Expression::Bool(value) => Expression::RetBool(value),
|
||||
_ => Expression::Other,
|
||||
}
|
||||
}
|
||||
_ => Expression::Other,
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
use rustc::lint::*;
|
||||
use rustc::hir;
|
||||
use rustc::hir::intravisit::FnKind;
|
||||
use rustc::hir;
|
||||
use rustc::lint::*;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, same_tys, span_lint,
|
||||
DEFAULT_TRAIT_PATH};
|
||||
use utils::paths;
|
||||
use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, same_tys, span_lint};
|
||||
|
||||
/// **What it does:** This lints about type with a `fn new() -> Self` method and no `Default`
|
||||
/// implementation.
|
||||
@ -54,7 +54,7 @@ impl LateLintPass for NewWithoutDefault {
|
||||
self_ty.walk_shallow().next().is_none(), // implements_trait does not work with generics
|
||||
let Some(ret_ty) = return_ty(cx, id),
|
||||
same_tys(cx, self_ty, ret_ty, id),
|
||||
let Some(default_trait_id) = get_trait_def_id(cx, &DEFAULT_TRAIT_PATH),
|
||||
let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT),
|
||||
!implements_trait(cx, self_ty, default_trait_id, Vec::new())
|
||||
], {
|
||||
span_lint(cx, NEW_WITHOUT_DEFAULT, span,
|
||||
|
@ -52,7 +52,8 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool {
|
||||
}
|
||||
}
|
||||
Expr_::ExprBlock(ref block) => {
|
||||
block.stmts.is_empty() && if let Some(ref expr) = block.expr {
|
||||
block.stmts.is_empty() &&
|
||||
if let Some(ref expr) = block.expr {
|
||||
has_no_effect(cx, expr)
|
||||
} else {
|
||||
false
|
||||
|
@ -45,7 +45,7 @@ struct ExistingName {
|
||||
interned: InternedString,
|
||||
span: Span,
|
||||
len: usize,
|
||||
whitelist: &'static[&'static str],
|
||||
whitelist: &'static [&'static str],
|
||||
}
|
||||
|
||||
struct SimilarNamesLocalVisitor<'a, 'b: 'a> {
|
||||
@ -57,6 +57,7 @@ struct SimilarNamesLocalVisitor<'a, 'b: 'a> {
|
||||
|
||||
// this list contains lists of names that are allowed to be similar
|
||||
// the assumption is that no name is ever contained in multiple lists.
|
||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||
const WHITELIST: &'static [&'static [&'static str]] = &[
|
||||
&["parsed", "parser"],
|
||||
&["lhs", "rhs"],
|
||||
@ -75,7 +76,7 @@ impl<'v, 'a, 'b, 'c> visit::Visitor<'v> for SimilarNamesNameVisitor<'a, 'b, 'c>
|
||||
}
|
||||
}
|
||||
|
||||
fn get_whitelist(interned_name: &str) -> Option<&'static[&'static str]> {
|
||||
fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> {
|
||||
for &allow in WHITELIST {
|
||||
if whitelisted(interned_name, allow) {
|
||||
return Some(allow);
|
||||
@ -112,8 +113,7 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> {
|
||||
span_lint(self.0.cx,
|
||||
MANY_SINGLE_CHAR_NAMES,
|
||||
span,
|
||||
&format!("{}th binding whose name is just one char",
|
||||
self.0.single_char_names.len()));
|
||||
&format!("{}th binding whose name is just one char", self.0.single_char_names.len()));
|
||||
}
|
||||
}
|
||||
fn check_name(&mut self, span: Span, name: Name) {
|
||||
@ -162,7 +162,8 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> {
|
||||
} else {
|
||||
let second_last_i = interned_chars.next_back().expect("we know we have at least three chars");
|
||||
let second_last_e = existing_chars.next_back().expect("we know we have at least three chars");
|
||||
if !eq_or_numeric(second_last_i, second_last_e) || second_last_i == '_' || !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) {
|
||||
if !eq_or_numeric(second_last_i, second_last_e) || second_last_i == '_' ||
|
||||
!interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) {
|
||||
// allowed similarity foo_x, foo_y
|
||||
// or too many chars differ (foo_x, boo_y) or (foox, booy)
|
||||
continue;
|
||||
@ -172,7 +173,8 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> {
|
||||
} else {
|
||||
let second_i = interned_chars.next().expect("we know we have at least two chars");
|
||||
let second_e = existing_chars.next().expect("we know we have at least two chars");
|
||||
if !eq_or_numeric(second_i, second_e) || second_i == '_' || !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) {
|
||||
if !eq_or_numeric(second_i, second_e) || second_i == '_' ||
|
||||
!interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) {
|
||||
// allowed similarity x_foo, y_foo
|
||||
// or too many chars differ (x_foo, y_boo) or (xfoo, yboo)
|
||||
continue;
|
||||
@ -187,10 +189,11 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> {
|
||||
|diag| {
|
||||
diag.span_note(existing_name.span, "existing binding defined here");
|
||||
if let Some(split) = split_at {
|
||||
diag.span_help(span, &format!("separate the discriminating character \
|
||||
by an underscore like: `{}_{}`",
|
||||
&interned_name[..split],
|
||||
&interned_name[split..]));
|
||||
diag.span_help(span,
|
||||
&format!("separate the discriminating character by an \
|
||||
underscore like: `{}_{}`",
|
||||
&interned_name[..split],
|
||||
&interned_name[split..]));
|
||||
}
|
||||
});
|
||||
return;
|
||||
|
@ -1,8 +1,8 @@
|
||||
use rustc::lint::*;
|
||||
use rustc::hir::{Expr, ExprMethodCall, ExprLit};
|
||||
use rustc::lint::*;
|
||||
use syntax::ast::LitKind;
|
||||
use syntax::codemap::{Span, Spanned};
|
||||
use utils::{walk_ptrs_ty_depth, match_type, span_lint, OPEN_OPTIONS_PATH};
|
||||
use utils::{match_type, paths, span_lint, walk_ptrs_ty_depth};
|
||||
|
||||
/// **What it does:** This lint checks for duplicate open options as well as combinations that make no sense.
|
||||
///
|
||||
@ -31,7 +31,7 @@ impl LateLintPass for NonSensicalOpenOptions {
|
||||
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
|
||||
if let ExprMethodCall(ref name, _, ref arguments) = e.node {
|
||||
let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&arguments[0]));
|
||||
if name.node.as_str() == "open" && match_type(cx, obj_ty, &OPEN_OPTIONS_PATH) {
|
||||
if name.node.as_str() == "open" && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) {
|
||||
let mut options = Vec::new();
|
||||
get_open_options(cx, &arguments[0], &mut options);
|
||||
check_open_options(cx, &options, e.span);
|
||||
@ -61,11 +61,11 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp
|
||||
let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&arguments[0]));
|
||||
|
||||
// Only proceed if this is a call on some object of type std::fs::OpenOptions
|
||||
if match_type(cx, obj_ty, &OPEN_OPTIONS_PATH) && arguments.len() >= 2 {
|
||||
if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 {
|
||||
|
||||
let argument_option = match arguments[1].node {
|
||||
ExprLit(ref span) => {
|
||||
if let Spanned {node: LitKind::Bool(lit), ..} = **span {
|
||||
if let Spanned { node: LitKind::Bool(lit), .. } = **span {
|
||||
if lit {
|
||||
Argument::True
|
||||
} else {
|
||||
@ -96,7 +96,7 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp
|
||||
"write" => {
|
||||
options.push((OpenOption::Write, argument_option));
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
get_open_options(cx, &arguments[0], options);
|
||||
|
@ -1,6 +1,6 @@
|
||||
use rustc::lint::*;
|
||||
use rustc::hir::*;
|
||||
use utils::{span_lint};
|
||||
use utils::span_lint;
|
||||
|
||||
/// **What it does:** This lint finds classic underflow / overflow checks.
|
||||
///
|
||||
|
@ -1,7 +1,7 @@
|
||||
use rustc::lint::*;
|
||||
use rustc::hir::*;
|
||||
use rustc::lint::*;
|
||||
use syntax::ast::LitKind;
|
||||
use utils::{span_lint, is_direct_expn_of, match_path, BEGIN_UNWIND};
|
||||
use utils::{is_direct_expn_of, match_path, paths, span_lint};
|
||||
|
||||
/// **What it does:** This lint checks for missing parameters in `panic!`.
|
||||
///
|
||||
@ -33,7 +33,7 @@ impl LateLintPass for PanicPass {
|
||||
let ExprCall(ref fun, ref params) = ex.node,
|
||||
params.len() == 2,
|
||||
let ExprPath(None, ref path) = fun.node,
|
||||
match_path(path, &BEGIN_UNWIND),
|
||||
match_path(path, &paths::BEGIN_UNWIND),
|
||||
let ExprLit(ref lit) = params[0].node,
|
||||
is_direct_expn_of(cx, params[0].span, "panic").is_some(),
|
||||
let LitKind::Str(ref string, _) = lit.node,
|
||||
|
@ -31,7 +31,7 @@ impl LintPass for Precedence {
|
||||
|
||||
impl EarlyLintPass for Precedence {
|
||||
fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
|
||||
if let ExprKind::Binary(Spanned { node: op, ..}, ref left, ref right) = expr.node {
|
||||
if let ExprKind::Binary(Spanned { node: op, .. }, ref left, ref right) = expr.node {
|
||||
if !is_bit_op(op) {
|
||||
return;
|
||||
}
|
||||
@ -75,7 +75,9 @@ impl EarlyLintPass for Precedence {
|
||||
if let Some(slf) = args.first() {
|
||||
if let ExprKind::Lit(ref lit) = slf.node {
|
||||
match lit.node {
|
||||
LitKind::Int(..) | LitKind::Float(..) | LitKind::FloatUnsuffixed(..) => {
|
||||
LitKind::Int(..) |
|
||||
LitKind::Float(..) |
|
||||
LitKind::FloatUnsuffixed(..) => {
|
||||
span_lint(cx,
|
||||
PRECEDENCE,
|
||||
expr.span,
|
||||
@ -94,7 +96,7 @@ impl EarlyLintPass for Precedence {
|
||||
|
||||
fn is_arith_expr(expr: &Expr) -> bool {
|
||||
match expr.node {
|
||||
ExprKind::Binary(Spanned { node: op, ..}, _, _) => is_arith_op(op),
|
||||
ExprKind::Binary(Spanned { node: op, .. }, _, _) => is_arith_op(op),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
10
src/print.rs
10
src/print.rs
@ -1,7 +1,7 @@
|
||||
use rustc::hir::*;
|
||||
use rustc::hir::map::Node::{NodeItem, NodeImplItem};
|
||||
use rustc::lint::*;
|
||||
use rustc::hir::*;
|
||||
use utils::{FMT_ARGUMENTV1_NEW_PATH, DEBUG_FMT_METHOD_PATH, IO_PRINT_PATH};
|
||||
use utils::paths;
|
||||
use utils::{is_expn_of, match_path, span_lint};
|
||||
|
||||
/// **What it does:** This lint warns whenever you print on *stdout*. The purpose of this lint is to catch debugging remnants.
|
||||
@ -45,7 +45,7 @@ impl LateLintPass for PrintLint {
|
||||
if let ExprPath(_, ref path) = fun.node {
|
||||
// Search for `std::io::_print(..)` which is unique in a
|
||||
// `print!` expansion.
|
||||
if match_path(path, &IO_PRINT_PATH) {
|
||||
if match_path(path, &paths::IO_PRINT) {
|
||||
if let Some(span) = is_expn_of(cx, expr.span, "print") {
|
||||
// `println!` uses `print!`.
|
||||
let (span, name) = match is_expn_of(cx, span, "println") {
|
||||
@ -58,9 +58,9 @@ impl LateLintPass for PrintLint {
|
||||
}
|
||||
// Search for something like
|
||||
// `::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)`
|
||||
else if args.len() == 2 && match_path(path, &FMT_ARGUMENTV1_NEW_PATH) {
|
||||
else if args.len() == 2 && match_path(path, &paths::FMT_ARGUMENTV1_NEW) {
|
||||
if let ExprPath(None, ref path) = args[1].node {
|
||||
if match_path(path, &DEBUG_FMT_METHOD_PATH) && !is_in_debug_impl(cx, expr) &&
|
||||
if match_path(path, &paths::DEBUG_FMT_METHOD) && !is_in_debug_impl(cx, expr) &&
|
||||
is_expn_of(cx, expr.span, "panic").is_none() {
|
||||
span_lint(cx, USE_DEBUG, args[0].span, "use of `Debug`-based formatting");
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
//! Checks for usage of `&Vec[_]` and `&String`.
|
||||
|
||||
use rustc::hir::*;
|
||||
use rustc::hir::map::NodeItem;
|
||||
use rustc::lint::*;
|
||||
use rustc::ty;
|
||||
use rustc::hir::*;
|
||||
use syntax::ast::NodeId;
|
||||
use utils::{STRING_PATH, VEC_PATH};
|
||||
use utils::{span_lint, match_type};
|
||||
use utils::{match_type, paths, span_lint};
|
||||
|
||||
/// **What it does:** This lint checks for function arguments of type `&String` or `&Vec` unless the references are mutable.
|
||||
///
|
||||
@ -61,13 +60,13 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) {
|
||||
|
||||
for (arg, ty) in decl.inputs.iter().zip(&fn_ty.inputs) {
|
||||
if let ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = ty.sty {
|
||||
if match_type(cx, ty, &VEC_PATH) {
|
||||
if match_type(cx, ty, &paths::VEC) {
|
||||
span_lint(cx,
|
||||
PTR_ARG,
|
||||
arg.ty.span,
|
||||
"writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \
|
||||
with non-Vec-based slices. Consider changing the type to `&[...]`");
|
||||
} else if match_type(cx, ty, &STRING_PATH) {
|
||||
} else if match_type(cx, ty, &paths::STRING) {
|
||||
span_lint(cx,
|
||||
PTR_ARG,
|
||||
arg.ty.span,
|
||||
|
14
src/regex.rs
14
src/regex.rs
@ -9,7 +9,7 @@ use std::error::Error;
|
||||
use syntax::ast::{LitKind, NodeId};
|
||||
use syntax::codemap::{Span, BytePos};
|
||||
use syntax::parse::token::InternedString;
|
||||
use utils::{is_expn_of, match_path, match_type, REGEX_NEW_PATH, span_lint, span_help_and_lint};
|
||||
use utils::{is_expn_of, match_path, match_type, paths, span_lint, span_help_and_lint};
|
||||
|
||||
/// **What it does:** This lint checks `Regex::new(_)` invocations for correct regex syntax.
|
||||
///
|
||||
@ -72,8 +72,8 @@ impl LateLintPass for RegexPass {
|
||||
if_let_chain!{[
|
||||
self.last.is_none(),
|
||||
let Some(ref expr) = block.expr,
|
||||
match_type(cx, cx.tcx.expr_ty(expr), &["regex", "re", "Regex"]),
|
||||
let Some(span) = is_expn_of(cx, expr.span, "regex")
|
||||
match_type(cx, cx.tcx.expr_ty(expr), &paths::REGEX),
|
||||
let Some(span) = is_expn_of(cx, expr.span, "regex"),
|
||||
], {
|
||||
if !self.spans.contains(&span) {
|
||||
span_lint(cx,
|
||||
@ -97,7 +97,7 @@ impl LateLintPass for RegexPass {
|
||||
if_let_chain!{[
|
||||
let ExprCall(ref fun, ref args) = expr.node,
|
||||
let ExprPath(_, ref path) = fun.node,
|
||||
match_path(path, ®EX_NEW_PATH) && args.len() == 1
|
||||
match_path(path, &paths::REGEX_NEW) && args.len() == 1
|
||||
], {
|
||||
if let ExprLit(ref lit) = args[0].node {
|
||||
if let LitKind::Str(ref r, _) = lit.node {
|
||||
@ -166,14 +166,14 @@ fn is_trivial_regex(s: ®ex_syntax::Expr) -> Option<&'static str> {
|
||||
|
||||
match *s {
|
||||
Expr::Empty | Expr::StartText | Expr::EndText => Some("the regex is unlikely to be useful as it is"),
|
||||
Expr::Literal {..} => Some("consider using `str::contains`"),
|
||||
Expr::Literal { .. } => Some("consider using `str::contains`"),
|
||||
Expr::Concat(ref exprs) => {
|
||||
match exprs.len() {
|
||||
2 => {
|
||||
match (&exprs[0], &exprs[1]) {
|
||||
(&Expr::StartText, &Expr::EndText) => Some("consider using `str::is_empty`"),
|
||||
(&Expr::StartText, &Expr::Literal {..}) => Some("consider using `str::starts_with`"),
|
||||
(&Expr::Literal {..}, &Expr::EndText) => Some("consider using `str::ends_with`"),
|
||||
(&Expr::StartText, &Expr::Literal { .. }) => Some("consider using `str::starts_with`"),
|
||||
(&Expr::Literal { .. }, &Expr::EndText) => Some("consider using `str::ends_with`"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ impl ReturnPass {
|
||||
self.check_final_expr(cx, &arm.body);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,8 @@ fn check_block(cx: &LateContext, block: &Block, bindings: &mut Vec<(Name, Span)>
|
||||
for stmt in &block.stmts {
|
||||
match stmt.node {
|
||||
StmtDecl(ref decl, _) => check_decl(cx, decl, bindings),
|
||||
StmtExpr(ref e, _) | StmtSemi(ref e, _) => check_expr(cx, e, bindings),
|
||||
StmtExpr(ref e, _) |
|
||||
StmtSemi(ref e, _) => check_expr(cx, e, bindings),
|
||||
}
|
||||
}
|
||||
if let Some(ref o) = block.expr {
|
||||
@ -94,7 +95,7 @@ fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) {
|
||||
return;
|
||||
}
|
||||
if let DeclLocal(ref local) = decl.node {
|
||||
let Local{ ref pat, ref ty, ref init, span, .. } = **local;
|
||||
let Local { ref pat, ref ty, ref init, span, .. } = **local;
|
||||
if let Some(ref t) = *ty {
|
||||
check_ty(cx, t, bindings)
|
||||
}
|
||||
@ -109,7 +110,8 @@ fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) {
|
||||
|
||||
fn is_binding(cx: &LateContext, pat: &Pat) -> bool {
|
||||
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
|
||||
Some(Def::Variant(..)) | Some(Def::Struct(..)) => false,
|
||||
Some(Def::Variant(..)) |
|
||||
Some(Def::Struct(..)) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
@ -251,7 +253,8 @@ fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) {
|
||||
ExprTupField(ref e, _) |
|
||||
ExprAddrOf(_, ref e) |
|
||||
ExprBox(ref e) => check_expr(cx, e, bindings),
|
||||
ExprBlock(ref block) | ExprLoop(ref block, _) => check_block(cx, block, bindings),
|
||||
ExprBlock(ref block) |
|
||||
ExprLoop(ref block, _) => check_block(cx, block, bindings),
|
||||
// ExprCall
|
||||
// ExprMethodCall
|
||||
ExprVec(ref v) | ExprTup(ref v) => {
|
||||
@ -297,8 +300,8 @@ fn check_ty(cx: &LateContext, ty: &Ty, bindings: &mut Vec<(Name, Span)>) {
|
||||
check_ty(cx, fty, bindings);
|
||||
check_expr(cx, expr, bindings);
|
||||
}
|
||||
TyPtr(MutTy{ ty: ref mty, .. }) |
|
||||
TyRptr(_, MutTy{ ty: ref mty, .. }) => check_ty(cx, mty, bindings),
|
||||
TyPtr(MutTy { ty: ref mty, .. }) |
|
||||
TyRptr(_, MutTy { ty: ref mty, .. }) => check_ty(cx, mty, bindings),
|
||||
TyTup(ref tup) => {
|
||||
for ref t in tup {
|
||||
check_ty(cx, t, bindings)
|
||||
|
@ -3,12 +3,11 @@
|
||||
//! Note that since we have two lints where one subsumes the other, we try to
|
||||
//! disable the subsumed lint unless it has a higher level
|
||||
|
||||
use rustc::lint::*;
|
||||
use rustc::hir::*;
|
||||
use rustc::lint::*;
|
||||
use syntax::codemap::Spanned;
|
||||
use utils::STRING_PATH;
|
||||
use utils::SpanlessEq;
|
||||
use utils::{match_type, span_lint, span_lint_and_then, walk_ptrs_ty, get_parent_expr};
|
||||
use utils::{match_type, paths, span_lint, span_lint_and_then, walk_ptrs_ty, get_parent_expr};
|
||||
|
||||
/// **What it does:** This lint matches code of the form `x = x + y` (without `let`!).
|
||||
///
|
||||
@ -75,7 +74,7 @@ impl LintPass for StringAdd {
|
||||
|
||||
impl LateLintPass for StringAdd {
|
||||
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
|
||||
if let ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) = e.node {
|
||||
if let ExprBinary(Spanned { node: BiAdd, .. }, ref left, _) = e.node {
|
||||
if is_string(cx, left) {
|
||||
if let Allow = cx.current_level(STRING_ADD_ASSIGN) {
|
||||
// the string_add_assign is allow, so no duplicates
|
||||
@ -108,12 +107,12 @@ impl LateLintPass for StringAdd {
|
||||
}
|
||||
|
||||
fn is_string(cx: &LateContext, e: &Expr) -> bool {
|
||||
match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(e)), &STRING_PATH)
|
||||
match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(e)), &paths::STRING)
|
||||
}
|
||||
|
||||
fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool {
|
||||
match src.node {
|
||||
ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) => SpanlessEq::new(cx).eq_expr(target, left),
|
||||
ExprBinary(Spanned { node: BiAdd, .. }, ref left, _) => SpanlessEq::new(cx).eq_expr(target, left),
|
||||
ExprBlock(ref block) => {
|
||||
block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target))
|
||||
}
|
||||
@ -146,8 +145,7 @@ impl LateLintPass for StringLitAsBytes {
|
||||
e.span,
|
||||
"calling `as_bytes()` on a string literal",
|
||||
|db| {
|
||||
let sugg = format!("b{}",
|
||||
snippet(cx, args[0].span, r#""foo""#));
|
||||
let sugg = format!("b{}", snippet(cx, args[0].span, r#""foo""#));
|
||||
db.span_suggestion(e.span,
|
||||
"consider using a byte string literal instead",
|
||||
sugg);
|
||||
|
@ -18,8 +18,7 @@ declare_lint! {
|
||||
|
||||
fn is_temporary(expr: &Expr) -> bool {
|
||||
match expr.node {
|
||||
ExprStruct(..) |
|
||||
ExprTup(..) => true,
|
||||
ExprStruct(..) | ExprTup(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -37,7 +36,8 @@ impl LateLintPass for TemporaryAssignmentPass {
|
||||
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
|
||||
if let ExprAssign(ref target, _) = expr.node {
|
||||
match target.node {
|
||||
ExprField(ref base, _) | ExprTupField(ref base, _) => {
|
||||
ExprField(ref base, _) |
|
||||
ExprTupField(ref base, _) => {
|
||||
if is_temporary(base) && !is_adjusted(cx, base) {
|
||||
span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span, "assignment to temporary");
|
||||
}
|
||||
|
@ -2,8 +2,7 @@ use rustc::lint::*;
|
||||
use rustc::ty::TypeVariants::{TyRawPtr, TyRef};
|
||||
use rustc::ty;
|
||||
use rustc::hir::*;
|
||||
use utils::TRANSMUTE_PATH;
|
||||
use utils::{match_def_path, snippet_opt, span_lint, span_lint_and_then};
|
||||
use utils::{match_def_path, paths, snippet_opt, span_lint, span_lint_and_then};
|
||||
|
||||
/// **What it does:** This lint checks for transmutes to the original type of the object.
|
||||
///
|
||||
@ -53,11 +52,7 @@ pub struct Transmute;
|
||||
|
||||
impl LintPass for Transmute {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array! [
|
||||
CROSSPOINTER_TRANSMUTE,
|
||||
TRANSMUTE_PTR_TO_REF,
|
||||
USELESS_TRANSMUTE
|
||||
]
|
||||
lint_array![CROSSPOINTER_TRANSMUTE, TRANSMUTE_PTR_TO_REF, USELESS_TRANSMUTE]
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,7 +62,7 @@ impl LateLintPass for Transmute {
|
||||
if let ExprPath(None, _) = path_expr.node {
|
||||
let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id();
|
||||
|
||||
if match_def_path(cx, def_id, &TRANSMUTE_PATH) {
|
||||
if match_def_path(cx, def_id, &paths::TRANSMUTE) {
|
||||
let from_ty = cx.tcx.expr_ty(&args[0]);
|
||||
let to_ty = cx.tcx.expr_ty(e);
|
||||
|
||||
@ -80,12 +75,16 @@ impl LateLintPass for Transmute {
|
||||
span_lint(cx,
|
||||
CROSSPOINTER_TRANSMUTE,
|
||||
e.span,
|
||||
&format!("transmute from a type (`{}`) to a pointer to that type (`{}`)", from_ty, to_ty));
|
||||
&format!("transmute from a type (`{}`) to a pointer to that type (`{}`)",
|
||||
from_ty,
|
||||
to_ty));
|
||||
} else if is_ptr_to(from_ty, to_ty) {
|
||||
span_lint(cx,
|
||||
CROSSPOINTER_TRANSMUTE,
|
||||
e.span,
|
||||
&format!("transmute from a type (`{}`) to the type that it points to (`{}`)", from_ty, to_ty));
|
||||
&format!("transmute from a type (`{}`) to the type that it points to (`{}`)",
|
||||
from_ty,
|
||||
to_ty));
|
||||
} else {
|
||||
check_ptr_to_ref(cx, from_ty, to_ty, e, &args[0]);
|
||||
}
|
||||
@ -103,10 +102,7 @@ fn is_ptr_to(from: ty::Ty, to: ty::Ty) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_ptr_to_ref<'tcx>(cx: &LateContext,
|
||||
from_ty: ty::Ty<'tcx>,
|
||||
to_ty: ty::Ty<'tcx>,
|
||||
e: &Expr, arg: &Expr) {
|
||||
fn check_ptr_to_ref<'tcx>(cx: &LateContext, from_ty: ty::Ty<'tcx>, to_ty: ty::Ty<'tcx>, e: &Expr, arg: &Expr) {
|
||||
if let TyRawPtr(ref from_pty) = from_ty.sty {
|
||||
if let TyRef(_, ref to_rty) = to_ty.sty {
|
||||
let mess = format!("transmute from a pointer type (`{}`) to a reference type (`{}`)",
|
||||
@ -123,8 +119,7 @@ fn check_ptr_to_ref<'tcx>(cx: &LateContext,
|
||||
|
||||
let sugg = if from_pty.ty == to_rty.ty {
|
||||
format!("{}{}", deref, arg)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
format!("{}({} as {} {})", deref, arg, cast, to_rty.ty)
|
||||
};
|
||||
|
||||
|
116
src/types.rs
116
src/types.rs
@ -6,7 +6,9 @@ use rustc::ty;
|
||||
use std::cmp::Ordering;
|
||||
use syntax::ast::{IntTy, UintTy, FloatTy};
|
||||
use syntax::codemap::Span;
|
||||
use utils::*;
|
||||
use utils::{comparisons, in_external_macro, in_macro, is_from_for_desugar, match_def_path, snippet,
|
||||
span_help_and_lint, span_lint};
|
||||
use utils::paths;
|
||||
|
||||
/// Handles all the linting of funky types
|
||||
#[allow(missing_copy_implementations)]
|
||||
@ -63,7 +65,7 @@ impl LateLintPass for TypePass {
|
||||
let Some(ref vec) = ag.types.get(0),
|
||||
let Some(did) = cx.tcx.def_map.borrow().get(&vec.id),
|
||||
let def::Def::Struct(..) = did.full_def(),
|
||||
match_def_path(cx, did.def_id(), &VEC_PATH),
|
||||
match_def_path(cx, did.def_id(), &paths::VEC),
|
||||
],
|
||||
{
|
||||
span_help_and_lint(cx,
|
||||
@ -73,7 +75,7 @@ impl LateLintPass for TypePass {
|
||||
"`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.");
|
||||
}
|
||||
}
|
||||
} else if match_def_path(cx, did.def_id(), &LL_PATH) {
|
||||
} else if match_def_path(cx, did.def_id(), &paths::LINKED_LIST) {
|
||||
span_help_and_lint(cx,
|
||||
LINKEDLIST,
|
||||
ast_ty.span,
|
||||
@ -246,7 +248,8 @@ fn int_ty_to_nbits(typ: &ty::TyS) -> usize {
|
||||
|
||||
fn is_isize_or_usize(typ: &ty::TyS) -> bool {
|
||||
match typ.sty {
|
||||
ty::TyInt(IntTy::Is) | ty::TyUint(UintTy::Us) => true,
|
||||
ty::TyInt(IntTy::Is) |
|
||||
ty::TyUint(UintTy::Us) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -534,9 +537,7 @@ impl<'v> Visitor<'v> for TypeComplexityVisitor {
|
||||
fn visit_ty(&mut self, ty: &'v Ty) {
|
||||
let (add_score, sub_nest) = match ty.node {
|
||||
// _, &x and *x have only small overhead; don't mess with nesting level
|
||||
TyInfer |
|
||||
TyPtr(..) |
|
||||
TyRptr(..) => (1, 0),
|
||||
TyInfer | TyPtr(..) | TyRptr(..) => (1, 0),
|
||||
|
||||
// the "normal" components of a type: named types, arrays/tuples
|
||||
TyPath(..) |
|
||||
@ -661,17 +662,17 @@ fn detect_absurd_comparison<'a>(cx: &LateContext, op: BinOp_, lhs: &'a Expr, rhs
|
||||
Some(match rel {
|
||||
Rel::Lt => {
|
||||
match (lx, rx) {
|
||||
(Some(l @ Extr { which: Maximum, ..}), _) => (l, AlwaysFalse), // max < x
|
||||
(_, Some(r @ Extr { which: Minimum, ..})) => (r, AlwaysFalse), // x < min
|
||||
(Some(l @ Extr { which: Maximum, .. }), _) => (l, AlwaysFalse), // max < x
|
||||
(_, Some(r @ Extr { which: Minimum, .. })) => (r, AlwaysFalse), // x < min
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
Rel::Le => {
|
||||
match (lx, rx) {
|
||||
(Some(l @ Extr { which: Minimum, ..}), _) => (l, AlwaysTrue), // min <= x
|
||||
(Some(l @ Extr { which: Maximum, ..}), _) => (l, InequalityImpossible), //max <= x
|
||||
(_, Some(r @ Extr { which: Minimum, ..})) => (r, InequalityImpossible), // x <= min
|
||||
(_, Some(r @ Extr { which: Maximum, ..})) => (r, AlwaysTrue), // x <= max
|
||||
(Some(l @ Extr { which: Minimum, .. }), _) => (l, AlwaysTrue), // min <= x
|
||||
(Some(l @ Extr { which: Maximum, .. }), _) => (l, InequalityImpossible), //max <= x
|
||||
(_, Some(r @ Extr { which: Minimum, .. })) => (r, InequalityImpossible), // x <= min
|
||||
(_, Some(r @ Extr { which: Maximum, .. })) => (r, AlwaysTrue), // x <= max
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
@ -700,14 +701,12 @@ fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeEx
|
||||
|
||||
let which = match (ty, cv) {
|
||||
(&ty::TyBool, Bool(false)) |
|
||||
|
||||
(&ty::TyInt(IntTy::Is), Integral(Isize(Is32(::std::i32::MIN)))) |
|
||||
(&ty::TyInt(IntTy::Is), Integral(Isize(Is64(::std::i64::MIN)))) |
|
||||
(&ty::TyInt(IntTy::I8), Integral(I8(::std::i8::MIN))) |
|
||||
(&ty::TyInt(IntTy::I16), Integral(I16(::std::i16::MIN))) |
|
||||
(&ty::TyInt(IntTy::I32), Integral(I32(::std::i32::MIN))) |
|
||||
(&ty::TyInt(IntTy::I64), Integral(I64(::std::i64::MIN))) |
|
||||
|
||||
(&ty::TyUint(UintTy::Us), Integral(Usize(Us32(::std::u32::MIN)))) |
|
||||
(&ty::TyUint(UintTy::Us), Integral(Usize(Us64(::std::u64::MIN)))) |
|
||||
(&ty::TyUint(UintTy::U8), Integral(U8(::std::u8::MIN))) |
|
||||
@ -716,14 +715,12 @@ fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeEx
|
||||
(&ty::TyUint(UintTy::U64), Integral(U64(::std::u64::MIN))) => Minimum,
|
||||
|
||||
(&ty::TyBool, Bool(true)) |
|
||||
|
||||
(&ty::TyInt(IntTy::Is), Integral(Isize(Is32(::std::i32::MAX)))) |
|
||||
(&ty::TyInt(IntTy::Is), Integral(Isize(Is64(::std::i64::MAX)))) |
|
||||
(&ty::TyInt(IntTy::I8), Integral(I8(::std::i8::MAX))) |
|
||||
(&ty::TyInt(IntTy::I16), Integral(I16(::std::i16::MAX))) |
|
||||
(&ty::TyInt(IntTy::I32), Integral(I32(::std::i32::MAX))) |
|
||||
(&ty::TyInt(IntTy::I64), Integral(I64(::std::i64::MAX))) |
|
||||
|
||||
(&ty::TyUint(UintTy::Us), Integral(Usize(Us32(::std::u32::MAX)))) |
|
||||
(&ty::TyUint(UintTy::Us), Integral(Usize(Us64(::std::u64::MAX)))) |
|
||||
(&ty::TyUint(UintTy::U8), Integral(U8(::std::u8::MAX))) |
|
||||
@ -843,22 +840,26 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(
|
||||
use syntax::ast::{IntTy, UintTy};
|
||||
use std::*;
|
||||
|
||||
if let ExprCast(ref cast_exp,_) = expr.node {
|
||||
if let ExprCast(ref cast_exp, _) = expr.node {
|
||||
match cx.tcx.expr_ty(cast_exp).sty {
|
||||
TyInt(int_ty) => Some(match int_ty {
|
||||
IntTy::I8 => (FullInt::S(i8::min_value() as i64), FullInt::S(i8::max_value() as i64)),
|
||||
IntTy::I16 => (FullInt::S(i16::min_value() as i64), FullInt::S(i16::max_value() as i64)),
|
||||
IntTy::I32 => (FullInt::S(i32::min_value() as i64), FullInt::S(i32::max_value() as i64)),
|
||||
IntTy::I64 => (FullInt::S(i64::min_value() as i64), FullInt::S(i64::max_value() as i64)),
|
||||
IntTy::Is => (FullInt::S(isize::min_value() as i64), FullInt::S(isize::max_value() as i64)),
|
||||
}),
|
||||
TyUint(uint_ty) => Some(match uint_ty {
|
||||
UintTy::U8 => (FullInt::U(u8::min_value() as u64), FullInt::U(u8::max_value() as u64)),
|
||||
UintTy::U16 => (FullInt::U(u16::min_value() as u64), FullInt::U(u16::max_value() as u64)),
|
||||
UintTy::U32 => (FullInt::U(u32::min_value() as u64), FullInt::U(u32::max_value() as u64)),
|
||||
UintTy::U64 => (FullInt::U(u64::min_value() as u64), FullInt::U(u64::max_value() as u64)),
|
||||
UintTy::Us => (FullInt::U(usize::min_value() as u64), FullInt::U(usize::max_value() as u64)),
|
||||
}),
|
||||
TyInt(int_ty) => {
|
||||
Some(match int_ty {
|
||||
IntTy::I8 => (FullInt::S(i8::min_value() as i64), FullInt::S(i8::max_value() as i64)),
|
||||
IntTy::I16 => (FullInt::S(i16::min_value() as i64), FullInt::S(i16::max_value() as i64)),
|
||||
IntTy::I32 => (FullInt::S(i32::min_value() as i64), FullInt::S(i32::max_value() as i64)),
|
||||
IntTy::I64 => (FullInt::S(i64::min_value() as i64), FullInt::S(i64::max_value() as i64)),
|
||||
IntTy::Is => (FullInt::S(isize::min_value() as i64), FullInt::S(isize::max_value() as i64)),
|
||||
})
|
||||
}
|
||||
TyUint(uint_ty) => {
|
||||
Some(match uint_ty {
|
||||
UintTy::U8 => (FullInt::U(u8::min_value() as u64), FullInt::U(u8::max_value() as u64)),
|
||||
UintTy::U16 => (FullInt::U(u16::min_value() as u64), FullInt::U(u16::max_value() as u64)),
|
||||
UintTy::U32 => (FullInt::U(u32::min_value() as u64), FullInt::U(u32::max_value() as u64)),
|
||||
UintTy::U64 => (FullInt::U(u64::min_value() as u64), FullInt::U(u64::max_value() as u64)),
|
||||
UintTy::Us => (FullInt::U(usize::min_value() as u64), FullInt::U(usize::max_value() as u64)),
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
@ -883,29 +884,26 @@ fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> {
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
}
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn err_upcast_comparison(cx: &LateContext, span: &Span, expr: &Expr, always: bool) {
|
||||
if let ExprCast(ref cast_val, _) = expr.node {
|
||||
span_lint(
|
||||
cx,
|
||||
INVALID_UPCAST_COMPARISONS,
|
||||
*span,
|
||||
&format!(
|
||||
span_lint(cx,
|
||||
INVALID_UPCAST_COMPARISONS,
|
||||
*span,
|
||||
&format!(
|
||||
"because of the numeric bounds on `{}` prior to casting, this expression is always {}",
|
||||
snippet(cx, cast_val.span, "the expression"),
|
||||
if always { "true" } else { "false" },
|
||||
)
|
||||
);
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
fn upcast_comparison_bounds_err(
|
||||
cx: &LateContext, span: &Span, rel: comparisons::Rel,
|
||||
lhs_bounds: Option<(FullInt, FullInt)>, lhs: &Expr, rhs: &Expr, invert: bool) {
|
||||
fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons::Rel,
|
||||
lhs_bounds: Option<(FullInt, FullInt)>, lhs: &Expr, rhs: &Expr, invert: bool) {
|
||||
use utils::comparisons::*;
|
||||
|
||||
if let Some((lb, ub)) = lhs_bounds {
|
||||
@ -915,14 +913,38 @@ fn upcast_comparison_bounds_err(
|
||||
err_upcast_comparison(cx, &span, lhs, rel == Rel::Ne);
|
||||
}
|
||||
} else if match rel {
|
||||
Rel::Lt => if invert { norm_rhs_val < lb } else { ub < norm_rhs_val },
|
||||
Rel::Le => if invert { norm_rhs_val <= lb } else { ub <= norm_rhs_val },
|
||||
Rel::Lt => {
|
||||
if invert {
|
||||
norm_rhs_val < lb
|
||||
} else {
|
||||
ub < norm_rhs_val
|
||||
}
|
||||
}
|
||||
Rel::Le => {
|
||||
if invert {
|
||||
norm_rhs_val <= lb
|
||||
} else {
|
||||
ub <= norm_rhs_val
|
||||
}
|
||||
}
|
||||
Rel::Eq | Rel::Ne => unreachable!(),
|
||||
} {
|
||||
err_upcast_comparison(cx, &span, lhs, true)
|
||||
} else if match rel {
|
||||
Rel::Lt => if invert { norm_rhs_val >= ub } else { lb >= norm_rhs_val },
|
||||
Rel::Le => if invert { norm_rhs_val > ub } else { lb > norm_rhs_val },
|
||||
Rel::Lt => {
|
||||
if invert {
|
||||
norm_rhs_val >= ub
|
||||
} else {
|
||||
lb >= norm_rhs_val
|
||||
}
|
||||
}
|
||||
Rel::Le => {
|
||||
if invert {
|
||||
norm_rhs_val > ub
|
||||
} else {
|
||||
lb > norm_rhs_val
|
||||
}
|
||||
}
|
||||
Rel::Eq | Rel::Ne => unreachable!(),
|
||||
} {
|
||||
err_upcast_comparison(cx, &span, lhs, false)
|
||||
|
@ -8,7 +8,8 @@ use toml;
|
||||
pub fn conf_file(args: &[ptr::P<ast::MetaItem>]) -> Result<Option<token::InternedString>, (&'static str, codemap::Span)> {
|
||||
for arg in args {
|
||||
match arg.node {
|
||||
ast::MetaItemKind::Word(ref name) | ast::MetaItemKind::List(ref name, _) => {
|
||||
ast::MetaItemKind::Word(ref name) |
|
||||
ast::MetaItemKind::List(ref name, _) => {
|
||||
if name == &"conf_file" {
|
||||
return Err(("`conf_file` must be a named value", arg.span));
|
||||
}
|
||||
|
@ -76,7 +76,9 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
|
||||
(&ExprBlock(ref l), &ExprBlock(ref r)) => self.eq_block(l, r),
|
||||
(&ExprBinary(l_op, ref ll, ref lr), &ExprBinary(r_op, ref rl, ref rr)) => {
|
||||
l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) ||
|
||||
swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr))
|
||||
swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| {
|
||||
l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
|
||||
})
|
||||
}
|
||||
(&ExprBreak(li), &ExprBreak(ri)) => both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()),
|
||||
(&ExprBox(ref l), &ExprBox(ref r)) => self.eq_expr(l, r),
|
||||
@ -114,9 +116,8 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
|
||||
both(l_qself, r_qself, |l, r| self.eq_qself(l, r)) && self.eq_path(l_subpath, r_subpath)
|
||||
}
|
||||
(&ExprStruct(ref l_path, ref lf, ref lo), &ExprStruct(ref r_path, ref rf, ref ro)) => {
|
||||
self.eq_path(l_path, r_path) &&
|
||||
both(lo, ro, |l, r| self.eq_expr(l, r)) &&
|
||||
over(lf, rf, |l, r| self.eq_field(l, r))
|
||||
self.eq_path(l_path, r_path) && both(lo, ro, |l, r| self.eq_expr(l, r)) &&
|
||||
over(lf, rf, |l, r| self.eq_field(l, r))
|
||||
}
|
||||
(&ExprTup(ref l_tup), &ExprTup(ref r_tup)) => self.eq_exprs(l_tup, r_tup),
|
||||
(&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => li.node == ri.node && self.eq_expr(le, re),
|
||||
|
103
src/utils/mod.rs
103
src/utils/mod.rs
@ -22,44 +22,10 @@ use syntax::ptr::P;
|
||||
pub mod comparisons;
|
||||
pub mod conf;
|
||||
mod hir;
|
||||
pub mod paths;
|
||||
pub use self::hir::{SpanlessEq, SpanlessHash};
|
||||
pub type MethodArgs = HirVec<P<Expr>>;
|
||||
|
||||
// module DefPaths for certain structs/enums we check for
|
||||
pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"];
|
||||
pub const BOX_NEW_PATH: [&'static str; 4] = ["std", "boxed", "Box", "new"];
|
||||
pub const BTREEMAP_ENTRY_PATH: [&'static str; 4] = ["collections", "btree", "map", "Entry"];
|
||||
pub const BTREEMAP_PATH: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"];
|
||||
pub const CLONE_PATH: [&'static str; 3] = ["clone", "Clone", "clone"];
|
||||
pub const CLONE_TRAIT_PATH: [&'static str; 2] = ["clone", "Clone"];
|
||||
pub const COW_PATH: [&'static str; 3] = ["collections", "borrow", "Cow"];
|
||||
pub const DEBUG_FMT_METHOD_PATH: [&'static str; 4] = ["std", "fmt", "Debug", "fmt"];
|
||||
pub const DEFAULT_TRAIT_PATH: [&'static str; 3] = ["core", "default", "Default"];
|
||||
pub const DISPLAY_FMT_METHOD_PATH: [&'static str; 4] = ["std", "fmt", "Display", "fmt"];
|
||||
pub const DROP_PATH: [&'static str; 3] = ["core", "mem", "drop"];
|
||||
pub const FMT_ARGUMENTS_NEWV1_PATH: [&'static str; 4] = ["std", "fmt", "Arguments", "new_v1"];
|
||||
pub const FMT_ARGUMENTV1_NEW_PATH: [&'static str; 4] = ["std", "fmt", "ArgumentV1", "new"];
|
||||
pub const HASHMAP_ENTRY_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"];
|
||||
pub const HASHMAP_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"];
|
||||
pub const HASH_PATH: [&'static str; 2] = ["hash", "Hash"];
|
||||
pub const IO_PRINT_PATH: [&'static str; 3] = ["std", "io", "_print"];
|
||||
pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"];
|
||||
pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"];
|
||||
pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"];
|
||||
pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"];
|
||||
pub const RANGE_FROM_PATH: [&'static str; 3] = ["std", "ops", "RangeFrom"];
|
||||
pub const RANGE_FULL_PATH: [&'static str; 3] = ["std", "ops", "RangeFull"];
|
||||
pub const RANGE_INCLUSIVE_NON_EMPTY_PATH: [&'static str; 4] = ["std", "ops", "RangeInclusive", "NonEmpty"];
|
||||
pub const RANGE_PATH: [&'static str; 3] = ["std", "ops", "Range"];
|
||||
pub const RANGE_TO_INCLUSIVE_PATH: [&'static str; 3] = ["std", "ops", "RangeToInclusive"];
|
||||
pub const RANGE_TO_PATH: [&'static str; 3] = ["std", "ops", "RangeTo"];
|
||||
pub const REGEX_NEW_PATH: [&'static str; 3] = ["regex", "Regex", "new"];
|
||||
pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"];
|
||||
pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"];
|
||||
pub const TRANSMUTE_PATH: [&'static str; 4] = ["core", "intrinsics", "", "transmute"];
|
||||
pub const VEC_FROM_ELEM_PATH: [&'static str; 3] = ["std", "vec", "from_elem"];
|
||||
pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"];
|
||||
pub const BOX_PATH: [&'static str; 3] = ["std", "boxed", "Box"];
|
||||
pub type MethodArgs = HirVec<P<Expr>>;
|
||||
|
||||
/// Produce a nested chain of if-lets and ifs from the patterns:
|
||||
///
|
||||
@ -178,7 +144,8 @@ pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool {
|
||||
/// Check if type is struct or enum type with given def path.
|
||||
pub fn match_type(cx: &LateContext, ty: ty::Ty, path: &[&str]) -> bool {
|
||||
match ty.sty {
|
||||
ty::TyEnum(ref adt, _) | ty::TyStruct(ref adt, _) => match_def_path(cx, adt.did, path),
|
||||
ty::TyEnum(ref adt, _) |
|
||||
ty::TyStruct(ref adt, _) => match_def_path(cx, adt.did, path),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -338,9 +305,9 @@ pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option<Vec<&'a
|
||||
pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> {
|
||||
let parent_id = cx.tcx.map.get_parent(expr.id);
|
||||
match cx.tcx.map.find(parent_id) {
|
||||
Some(Node::NodeItem(&Item{ ref name, .. })) |
|
||||
Some(Node::NodeTraitItem(&TraitItem{ ref name, .. })) |
|
||||
Some(Node::NodeImplItem(&ImplItem{ ref name, .. })) => Some(*name),
|
||||
Some(Node::NodeItem(&Item { ref name, .. })) |
|
||||
Some(Node::NodeTraitItem(&TraitItem { ref name, .. })) |
|
||||
Some(Node::NodeImplItem(&ImplItem { ref name, .. })) => Some(*name),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -465,7 +432,7 @@ pub fn get_enclosing_block<'c>(cx: &'c LateContext, node: NodeId) -> Option<&'c
|
||||
if let Some(node) = enclosing_node {
|
||||
match node {
|
||||
Node::NodeBlock(ref block) => Some(block),
|
||||
Node::NodeItem(&Item{ node: ItemFn(_, _, _, _, _, ref block), .. }) => Some(block),
|
||||
Node::NodeItem(&Item { node: ItemFn(_, _, _, _, _, ref block), .. }) => Some(block),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
@ -551,7 +518,8 @@ pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint,
|
||||
/// Return the base type for references and raw pointers.
|
||||
pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty {
|
||||
match ty.sty {
|
||||
ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => walk_ptrs_ty(tm.ty),
|
||||
ty::TyRef(_, ref tm) |
|
||||
ty::TyRawPtr(ref tm) => walk_ptrs_ty(tm.ty),
|
||||
_ => ty,
|
||||
}
|
||||
}
|
||||
@ -560,7 +528,8 @@ pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty {
|
||||
pub fn walk_ptrs_ty_depth(ty: ty::Ty) -> (ty::Ty, usize) {
|
||||
fn inner(ty: ty::Ty, depth: usize) -> (ty::Ty, usize) {
|
||||
match ty.sty {
|
||||
ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => inner(tm.ty, depth + 1),
|
||||
ty::TyRef(_, ref tm) |
|
||||
ty::TyRawPtr(ref tm) => inner(tm.ty, depth + 1),
|
||||
_ => (ty, depth),
|
||||
}
|
||||
}
|
||||
@ -763,23 +732,47 @@ pub fn unsugar_range(expr: &Expr) -> Option<UnsugaredRange> {
|
||||
|
||||
match unwrap_unstable(&expr).node {
|
||||
ExprPath(None, ref path) => {
|
||||
if match_path(path, &RANGE_FULL_PATH) {
|
||||
Some(UnsugaredRange { start: None, end: None, limits: RangeLimits::HalfOpen })
|
||||
if match_path(path, &paths::RANGE_FULL) {
|
||||
Some(UnsugaredRange {
|
||||
start: None,
|
||||
end: None,
|
||||
limits: RangeLimits::HalfOpen,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
ExprStruct(ref path, ref fields, None) => {
|
||||
if match_path(path, &RANGE_FROM_PATH) {
|
||||
Some(UnsugaredRange { start: get_field("start", fields), end: None, limits: RangeLimits::HalfOpen })
|
||||
} else if match_path(path, &RANGE_INCLUSIVE_NON_EMPTY_PATH) {
|
||||
Some(UnsugaredRange { start: get_field("start", fields), end: get_field("end", fields), limits: RangeLimits::Closed })
|
||||
} else if match_path(path, &RANGE_PATH) {
|
||||
Some(UnsugaredRange { start: get_field("start", fields), end: get_field("end", fields), limits: RangeLimits::HalfOpen })
|
||||
} else if match_path(path, &RANGE_TO_INCLUSIVE_PATH) {
|
||||
Some(UnsugaredRange { start: None, end: get_field("end", fields), limits: RangeLimits::Closed })
|
||||
} else if match_path(path, &RANGE_TO_PATH) {
|
||||
Some(UnsugaredRange { start: None, end: get_field("end", fields), limits: RangeLimits::HalfOpen })
|
||||
if match_path(path, &paths::RANGE_FROM) {
|
||||
Some(UnsugaredRange {
|
||||
start: get_field("start", fields),
|
||||
end: None,
|
||||
limits: RangeLimits::HalfOpen,
|
||||
})
|
||||
} else if match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY) {
|
||||
Some(UnsugaredRange {
|
||||
start: get_field("start", fields),
|
||||
end: get_field("end", fields),
|
||||
limits: RangeLimits::Closed,
|
||||
})
|
||||
} else if match_path(path, &paths::RANGE) {
|
||||
Some(UnsugaredRange {
|
||||
start: get_field("start", fields),
|
||||
end: get_field("end", fields),
|
||||
limits: RangeLimits::HalfOpen,
|
||||
})
|
||||
} else if match_path(path, &paths::RANGE_TO_INCLUSIVE) {
|
||||
Some(UnsugaredRange {
|
||||
start: None,
|
||||
end: get_field("end", fields),
|
||||
limits: RangeLimits::Closed,
|
||||
})
|
||||
} else if match_path(path, &paths::RANGE_TO) {
|
||||
Some(UnsugaredRange {
|
||||
start: None,
|
||||
end: get_field("end", fields),
|
||||
limits: RangeLimits::HalfOpen,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
38
src/utils/paths.rs
Normal file
38
src/utils/paths.rs
Normal file
@ -0,0 +1,38 @@
|
||||
//! This module contains paths to types and functions Clippy needs to know about.
|
||||
|
||||
pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"];
|
||||
pub const BOX_NEW: [&'static str; 4] = ["std", "boxed", "Box", "new"];
|
||||
pub const BOX: [&'static str; 3] = ["std", "boxed", "Box"];
|
||||
pub const BTREEMAP_ENTRY: [&'static str; 4] = ["collections", "btree", "map", "Entry"];
|
||||
pub const BTREEMAP: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"];
|
||||
pub const CLONE: [&'static str; 3] = ["clone", "Clone", "clone"];
|
||||
pub const CLONE_TRAIT: [&'static str; 2] = ["clone", "Clone"];
|
||||
pub const COW: [&'static str; 3] = ["collections", "borrow", "Cow"];
|
||||
pub const CSTRING_NEW: [&'static str; 4] = ["std", "ffi", "CString", "new"];
|
||||
pub const DEBUG_FMT_METHOD: [&'static str; 4] = ["std", "fmt", "Debug", "fmt"];
|
||||
pub const DEFAULT_TRAIT: [&'static str; 3] = ["core", "default", "Default"];
|
||||
pub const DISPLAY_FMT_METHOD: [&'static str; 4] = ["std", "fmt", "Display", "fmt"];
|
||||
pub const DROP: [&'static str; 3] = ["core", "mem", "drop"];
|
||||
pub const FMT_ARGUMENTS_NEWV1: [&'static str; 4] = ["std", "fmt", "Arguments", "new_v1"];
|
||||
pub const FMT_ARGUMENTV1_NEW: [&'static str; 4] = ["std", "fmt", "ArgumentV1", "new"];
|
||||
pub const HASHMAP_ENTRY: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"];
|
||||
pub const HASHMAP: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"];
|
||||
pub const HASH: [&'static str; 2] = ["hash", "Hash"];
|
||||
pub const IO_PRINT: [&'static str; 3] = ["std", "io", "_print"];
|
||||
pub const LINKED_LIST: [&'static str; 3] = ["collections", "linked_list", "LinkedList"];
|
||||
pub const MUTEX: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"];
|
||||
pub const OPEN_OPTIONS: [&'static str; 3] = ["std", "fs", "OpenOptions"];
|
||||
pub const OPTION: [&'static str; 3] = ["core", "option", "Option"];
|
||||
pub const RANGE_FROM: [&'static str; 3] = ["std", "ops", "RangeFrom"];
|
||||
pub const RANGE_FULL: [&'static str; 3] = ["std", "ops", "RangeFull"];
|
||||
pub const RANGE_INCLUSIVE_NON_EMPTY: [&'static str; 4] = ["std", "ops", "RangeInclusive", "NonEmpty"];
|
||||
pub const RANGE: [&'static str; 3] = ["std", "ops", "Range"];
|
||||
pub const RANGE_TO_INCLUSIVE: [&'static str; 3] = ["std", "ops", "RangeToInclusive"];
|
||||
pub const RANGE_TO: [&'static str; 3] = ["std", "ops", "RangeTo"];
|
||||
pub const REGEX: [&'static str; 3] = ["regex", "re_unicode", "Regex"];
|
||||
pub const REGEX_NEW: [&'static str; 3] = ["regex", "Regex", "new"];
|
||||
pub const RESULT: [&'static str; 3] = ["core", "result", "Result"];
|
||||
pub const STRING: [&'static str; 3] = ["collections", "string", "String"];
|
||||
pub const TRANSMUTE: [&'static str; 4] = ["core", "intrinsics", "", "transmute"];
|
||||
pub const VEC_FROM_ELEM: [&'static str; 3] = ["std", "vec", "from_elem"];
|
||||
pub const VEC: [&'static str; 3] = ["collections", "vec", "Vec"];
|
@ -3,8 +3,7 @@ use rustc::ty::TypeVariants;
|
||||
use rustc::hir::*;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::ptr::P;
|
||||
use utils::VEC_FROM_ELEM_PATH;
|
||||
use utils::{is_expn_of, match_path, recover_for_loop, snippet, span_lint_and_then};
|
||||
use utils::{is_expn_of, match_path, paths, recover_for_loop, snippet, span_lint_and_then};
|
||||
|
||||
/// **What it does:** This lint warns about using `&vec![..]` when using `&[..]` would be possible.
|
||||
///
|
||||
@ -64,8 +63,7 @@ fn check_vec_macro(cx: &LateContext, expr: &Expr, vec: &Expr) {
|
||||
};
|
||||
|
||||
format!("&[{}]", snippet(cx, span, "..")).into()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
"&[]".into()
|
||||
}
|
||||
}
|
||||
@ -92,7 +90,7 @@ pub fn unexpand_vec<'e>(cx: &LateContext, expr: &'e Expr) -> Option<VecArgs<'e>>
|
||||
let ExprPath(_, ref path) = fun.node,
|
||||
is_expn_of(cx, fun.span, "vec").is_some()
|
||||
], {
|
||||
return if match_path(path, &VEC_FROM_ELEM_PATH) && args.len() == 2 {
|
||||
return if match_path(path, &paths::VEC_FROM_ELEM) && args.len() == 2 {
|
||||
// `vec![elem; size]` case
|
||||
Some(VecArgs::Repeat(&args[0], &args[1]))
|
||||
}
|
||||
|
@ -171,6 +171,17 @@ fn bar() { //~ ERROR: the function has a cyclomatic complexity of 2
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cyclomatic_complexity = "0"]
|
||||
/// Tests are usually complex but simple at the same time. `cyclomatic_complexity` used to give
|
||||
/// lots of false-positives in tests.
|
||||
fn dont_warn_on_tests() {
|
||||
match 99 {
|
||||
0 => println!("hi"),
|
||||
_ => println!("bye"),
|
||||
}
|
||||
}
|
||||
|
||||
#[cyclomatic_complexity = "0"]
|
||||
fn barr() { //~ ERROR: the function has a cyclomatic complexity of 2
|
||||
match 99 {
|
||||
|
@ -470,3 +470,15 @@ fn single_char_pattern() {
|
||||
//~| HELP try using a char instead:
|
||||
//~| SUGGESTION x.trim_right_matches('x');
|
||||
}
|
||||
|
||||
#[allow(result_unwrap_used)]
|
||||
fn temporary_cstring() {
|
||||
use std::ffi::CString;
|
||||
|
||||
( // extra parenthesis to better test spans
|
||||
//~^ ERROR you are getting the inner pointer of a temporary `CString`
|
||||
//~| NOTE that pointer will be invalid outside this expression
|
||||
CString::new("foo").unwrap()
|
||||
//~^ HELP assign the `CString` to a variable to extend its lifetime
|
||||
).as_ptr();
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ extern crate compiletest_rs as compiletest;
|
||||
use std::path::PathBuf;
|
||||
use std::env::var;
|
||||
|
||||
fn run_mode(mode: &'static str) {
|
||||
fn run_mode(dir: &'static str, mode: &'static str) {
|
||||
let mut config = compiletest::default_config();
|
||||
|
||||
let cfg_mode = mode.parse().ok().expect("Invalid mode");
|
||||
@ -14,7 +14,7 @@ fn run_mode(mode: &'static str) {
|
||||
}
|
||||
|
||||
config.mode = cfg_mode;
|
||||
config.src_base = PathBuf::from(format!("tests/{}", mode));
|
||||
config.src_base = PathBuf::from(format!("tests/{}", dir));
|
||||
|
||||
compiletest::run_tests(&config);
|
||||
}
|
||||
@ -22,13 +22,13 @@ fn run_mode(mode: &'static str) {
|
||||
#[test]
|
||||
#[cfg(not(feature = "test-regex_macros"))]
|
||||
fn compile_test() {
|
||||
run_mode("run-pass");
|
||||
run_mode("compile-fail");
|
||||
run_mode("run-pass", "run-pass");
|
||||
run_mode("compile-fail", "compile-fail");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "test-regex_macros")]
|
||||
fn compile_test() {
|
||||
run_mode("run-pass-regex_macros");
|
||||
run_mode("compile-fail-regex_macros");
|
||||
run_mode("run-pass-regex_macros", "run-pass");
|
||||
run_mode("compile-fail-regex_macros", "compile-fail");
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ def main(print_only=False, check=False):
|
||||
return
|
||||
|
||||
# collect all lints from source files
|
||||
for root, dirs, files in os.walk('src'):
|
||||
for root, _, files in os.walk('src'):
|
||||
for fn in files:
|
||||
if fn.endswith('.rs'):
|
||||
collect(lints, deprecated_lints, os.path.join(root, fn))
|
||||
@ -156,6 +156,15 @@ def main(print_only=False, check=False):
|
||||
lambda: ['There are %d lints included in this crate:\n' % len(lints)],
|
||||
write_back=not check)
|
||||
|
||||
# update the links in the CHANGELOG
|
||||
changed |= replace_region(
|
||||
'CHANGELOG.md',
|
||||
"<!-- begin autogenerated links to wiki -->",
|
||||
"<!-- end autogenerated links to wiki -->",
|
||||
lambda: ["[`{0}`]: {1}#{0}\n".format(l[1], wiki_link) for l in
|
||||
sorted(lints + deprecated_lints, key=lambda l: l[1])],
|
||||
replace_start=False, write_back=not check)
|
||||
|
||||
# update the `pub mod` list
|
||||
changed |= replace_region(
|
||||
'src/lib.rs', r'begin lints modules', r'end lints modules',
|
||||
|
Loading…
Reference in New Issue
Block a user