]> git.lizzy.rs Git - rust.git/blob - src/ranges.rs
rustup to 1.5.0-nightly (7bf4c885f 2015-09-26)
[rust.git] / src / ranges.rs
1 use rustc::lint::*;
2 use rustc_front::hir::*;
3 use syntax::codemap::Spanned;
4 use utils::{match_type, is_integer_literal};
5
6 declare_lint! {
7     pub RANGE_STEP_BY_ZERO, Warn,
8     "using Range::step_by(0), which produces an infinite iterator"
9 }
10
11 #[derive(Copy,Clone)]
12 pub struct StepByZero;
13
14 impl LintPass for StepByZero {
15     fn get_lints(&self) -> LintArray {
16         lint_array!(RANGE_STEP_BY_ZERO)
17     }
18 }
19
20 impl LateLintPass for StepByZero {
21     fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
22         if let ExprMethodCall(Spanned { node: ref name, .. }, _,
23                               ref args) = expr.node {
24             // Only warn on literal ranges.
25             if name.as_str() == "step_by" && args.len() == 2 &&
26                 is_range(cx, &args[0]) && is_integer_literal(&args[1], 0) {
27                 cx.span_lint(RANGE_STEP_BY_ZERO, expr.span,
28                              "Range::step_by(0) produces an infinite iterator. \
29                               Consider using `std::iter::repeat()` instead")
30             }
31         }
32     }
33 }
34
35 fn is_range(cx: &LateContext, expr: &Expr) -> bool {
36     // No need for walk_ptrs_ty here because step_by moves self, so it
37     // can't be called on a borrowed range.
38     let ty = cx.tcx.expr_ty(expr);
39     // Note: RangeTo and RangeFull don't have step_by
40     match_type(cx, ty, &["core", "ops", "Range"]) || match_type(cx, ty, &["core", "ops", "RangeFrom"])
41 }