Add slice_iter_nth lint

This commit is contained in:
Devon Hollowood 2016-06-16 01:36:11 -07:00
parent 555e4555b1
commit 7764dc5ef4
4 changed files with 42 additions and 2 deletions

View file

@ -234,6 +234,7 @@ All notable changes to this project will be documented in this file.
[`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
[`slice_iter_nth`]: https://github.com/Manishearth/rust-clippy/wiki#slice_iter_nth
[`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

View file

@ -17,7 +17,7 @@ Table of contents:
## Lints
There are 152 lints included in this crate:
There are 153 lints included in this crate:
name | default | meaning
---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -140,6 +140,7 @@ name
[single_char_pattern](https://github.com/Manishearth/rust-clippy/wiki#single_char_pattern) | warn | using a single-character str where a char could be used, e.g. `_.split("x")`
[single_match](https://github.com/Manishearth/rust-clippy/wiki#single_match) | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead
[single_match_else](https://github.com/Manishearth/rust-clippy/wiki#single_match_else) | allow | a match statement with a two arms where the second arm's pattern is a wildcard; recommends `if let` instead
[slice_iter_nth](https://github.com/Manishearth/rust-clippy/wiki#slice_iter_nth) | warn | using `.iter().nth()` on a slice
[string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add) | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead
[string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign) | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead
[string_lit_as_bytes](https://github.com/Manishearth/rust-clippy/wiki#string_lit_as_bytes) | warn | calling `as_bytes` on a string literal; suggests using a byte string literal instead

View file

@ -357,6 +357,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
methods::SEARCH_IS_SOME,
methods::SHOULD_IMPLEMENT_TRAIT,
methods::SINGLE_CHAR_PATTERN,
methods::SLICE_ITER_NTH,
methods::TEMPORARY_CSTRING_AS_PTR,
methods::WRONG_SELF_CONVENTION,
minmax::MIN_MAX,

View file

@ -312,6 +312,28 @@ declare_lint! {
"getting the inner pointer of a temporary `CString`"
}
/// **What it does:** This lint checks for use of `.iter().nth()` on a slice.
///
/// **Why is this bad?** `.get()` is more efficient and more readable.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// let some_slice = &[0, 1, 2, 3][..];
/// let third_elem = some_slice.iter().nth(3);
/// ```
/// The correct use would be:
/// ```rust
/// let some_slice = &[0, 1, 2, 3][..];
/// let third_elem = some_slice.get(3);
/// ```
declare_lint! {
pub SLICE_ITER_NTH,
Warn,
"using `.iter().nth()` on a slice"
}
impl LintPass for MethodsPass {
fn get_lints(&self) -> LintArray {
lint_array!(EXTEND_FROM_SLICE,
@ -330,7 +352,8 @@ impl LintPass for MethodsPass {
NEW_RET_NO_SELF,
SINGLE_CHAR_PATTERN,
SEARCH_IS_SOME,
TEMPORARY_CSTRING_AS_PTR)
TEMPORARY_CSTRING_AS_PTR,
SLICE_ITER_NTH)
}
}
@ -363,6 +386,8 @@ impl LateLintPass for MethodsPass {
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]);
} else if let Some(arglists) = method_chain_args(expr, &["iter", "nth"]) {
lint_slice_iter_nth(cx, expr, arglists[0]);
}
lint_or_fun_call(cx, expr, &name.node.as_str(), args);
@ -616,6 +641,18 @@ fn lint_cstring_as_ptr(cx: &LateContext, expr: &hir::Expr, new: &hir::Expr, unwr
}}
}
#[allow(ptr_arg)]
// Type of MethodArgs is potentially a Vec
fn lint_slice_iter_nth(cx: &LateContext, expr: &hir::Expr, iter_args: &MethodArgs){
// lint if the caller of `.iter().nth` is a `slice`
if let Some(_) = derefs_to_slice(cx, &iter_args[0], &cx.tcx.expr_ty(&iter_args[0])) {
span_lint(cx,
SLICE_ITER_NTH,
expr.span,
"called `.iter().nth()` on a slice. Calling `.get()` is both faster and more readable");
}
}
fn derefs_to_slice(cx: &LateContext, expr: &hir::Expr, ty: &ty::Ty) -> Option<(Span, &'static str)> {
fn may_slice(cx: &LateContext, ty: &ty::Ty) -> bool {
match ty.sty {