]> git.lizzy.rs Git - rust.git/commitdiff
Merge pull request #432 from nweston/zip-with-range
authorllogiq <bogusandre@gmail.com>
Tue, 3 Nov 2015 21:45:52 +0000 (22:45 +0100)
committerllogiq <bogusandre@gmail.com>
Tue, 3 Nov 2015 21:45:52 +0000 (22:45 +0100)
New lint for zip with array length instead of enumerate()

README.md
src/lib.rs
src/ranges.rs
tests/compile-fail/range.rs

index 29eb6750d1621b1f86e05ad55f4774bcffa93e0f..0da037e7b16d3d651a1f0637ca6b8557caf4a24d 100644 (file)
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code.
 [Jump to usage instructions](#usage)
 
 ##Lints
-There are 70 lints included in this crate:
+There are 71 lints included in this crate:
 
 name                                                                                                   | default | meaning
 -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -53,6 +53,7 @@ name
 [precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence)                               | warn    | catches operations where precedence may be unclear. See the wiki for a list of cases caught
 [ptr_arg](https://github.com/Manishearth/rust-clippy/wiki#ptr_arg)                                     | warn    | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively
 [range_step_by_zero](https://github.com/Manishearth/rust-clippy/wiki#range_step_by_zero)               | warn    | using Range::step_by(0), which produces an infinite iterator
+[range_zip_with_len](https://github.com/Manishearth/rust-clippy/wiki#range_zip_with_len)               | warn    | zipping iterator with a range when enumerate() would do
 [redundant_closure](https://github.com/Manishearth/rust-clippy/wiki#redundant_closure)                 | warn    | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`)
 [redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern)                 | warn    | using `name @ _` in a pattern
 [result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used)               | allow   | using `Result.unwrap()`, which might be better handled
index 60ab18566b8cc63964b539dffe783208615b1af3..525603dc2b805f1b6339f789ce1b585fd4ebee09 100755 (executable)
@@ -166,6 +166,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
         precedence::PRECEDENCE,
         ptr_arg::PTR_ARG,
         ranges::RANGE_STEP_BY_ZERO,
+        ranges::RANGE_ZIP_WITH_LEN,
         returns::LET_AND_RETURN,
         returns::NEEDLESS_RETURN,
         types::BOX_VEC,
index 2ef272237d135dd69aca6e41232b6c5ba0711020..39ff7d3cd31406bfa9b407d502475de24328626e 100644 (file)
@@ -1,19 +1,23 @@
 use rustc::lint::*;
 use rustc_front::hir::*;
 use syntax::codemap::Spanned;
-use utils::{match_type, is_integer_literal};
+use utils::{is_integer_literal, match_type, snippet};
 
 declare_lint! {
     pub RANGE_STEP_BY_ZERO, Warn,
     "using Range::step_by(0), which produces an infinite iterator"
 }
+declare_lint! {
+    pub RANGE_ZIP_WITH_LEN, Warn,
+    "zipping iterator with a range when enumerate() would do"
+}
 
 #[derive(Copy,Clone)]
 pub struct StepByZero;
 
 impl LintPass for StepByZero {
     fn get_lints(&self) -> LintArray {
-        lint_array!(RANGE_STEP_BY_ZERO)
+        lint_array!(RANGE_STEP_BY_ZERO, RANGE_ZIP_WITH_LEN)
     }
 }
 
@@ -21,13 +25,40 @@ impl LateLintPass for StepByZero {
     fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
         if let ExprMethodCall(Spanned { node: ref name, .. }, _,
                               ref args) = expr.node {
-            // Only warn on literal ranges.
+            // Range with step_by(0).
             if name.as_str() == "step_by" && args.len() == 2 &&
                 is_range(cx, &args[0]) && is_integer_literal(&args[1], 0) {
                 cx.span_lint(RANGE_STEP_BY_ZERO, expr.span,
                              "Range::step_by(0) produces an infinite iterator. \
                               Consider using `std::iter::repeat()` instead")
             }
+
+            // x.iter().zip(0..x.len())
+            else if name.as_str() == "zip" && args.len() == 2 {
+                let iter = &args[0].node;
+                let zip_arg = &args[1].node;
+                if_let_chain! {
+                    [
+                        // .iter() call
+                        let &ExprMethodCall( Spanned { node: ref iter_name, .. }, _, ref iter_args ) = iter,
+                        iter_name.as_str() == "iter",
+                        // range expression in .zip() call: 0..x.len()
+                        let &ExprRange(Some(ref from), Some(ref to)) = zip_arg,
+                        is_integer_literal(from, 0),
+                        // .len() call
+                        let ExprMethodCall(Spanned { node: ref len_name, .. }, _, ref len_args) = to.node,
+                        len_name.as_str() == "len" && len_args.len() == 1,
+                        // .iter() and .len() called on same Path
+                        let ExprPath(_, Path { segments: ref iter_path, .. }) = iter_args[0].node,
+                        let ExprPath(_, Path { segments: ref len_path, .. }) = len_args[0].node,
+                        iter_path == len_path
+                     ], {
+                        cx.span_lint(RANGE_ZIP_WITH_LEN, expr.span,
+                                     &format!("It is more idiomatic to use {}.iter().enumerate()",
+                                              snippet(cx, iter_args[0].span, "_")));
+                    }
+                }
+            }
         }
     }
 }
index 324f129fafacd496511a8c7abd77f569fad5e560..2d731670cbe391dd58b3b2ae521f354f9e78531b 100644 (file)
@@ -7,7 +7,7 @@ impl NotARange {
     fn step_by(&self, _: u32) {}
 }
 
-#[deny(range_step_by_zero)]
+#[deny(range_step_by_zero, range_zip_with_len)]
 fn main() {
     (0..1).step_by(0); //~ERROR Range::step_by(0) produces an infinite iterator
     // No warning for non-zero step
@@ -21,4 +21,9 @@ fn main() {
     // No error, not a range.
     let y = NotARange;
     y.step_by(0);
+
+    let _v1 = vec![1,2,3];
+    let _v2 = vec![4,5];
+    let _x = _v1.iter().zip(0.._v1.len()); //~ERROR It is more idiomatic to use _v1.iter().enumerate()
+    let _y = _v1.iter().zip(0.._v2.len()); // No error
 }