@@ -10,10 +10,13 @@ use rustc_front::hir::*;
1010use rustc_front:: intravisit:: { Visitor , walk_expr, walk_block, walk_decl} ;
1111use std:: borrow:: Cow ;
1212use std:: collections:: HashMap ;
13+ use syntax:: ast;
1314
1415use utils:: { snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro,
15- span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, walk_ptrs_ty} ;
16+ span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then,
17+ unsugar_range, walk_ptrs_ty} ;
1618use utils:: { BTREEMAP_PATH , HASHMAP_PATH , LL_PATH , OPTION_PATH , RESULT_PATH , VEC_PATH } ;
19+ use utils:: UnsugaredRange ;
1720
1821/// **What it does:** This lint checks for looping over the range of `0..len` of some collection just to get the values by index.
1922///
@@ -323,10 +326,9 @@ fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &E
323326/// Check for looping over a range and then indexing a sequence with it.
324327/// The iteratee must be a range literal.
325328fn check_for_loop_range ( cx : & LateContext , pat : & Pat , arg : & Expr , body : & Expr , expr : & Expr ) {
326- if let ExprRange ( Some ( ref l ) , ref r ) = arg. node {
329+ if let Some ( UnsugaredRange { start : Some ( ref start ) , ref end , .. } ) = unsugar_range ( & arg) {
327330 // the var must be a single name
328331 if let PatKind :: Ident ( _, ref ident, _) = pat. node {
329-
330332 let mut visitor = VarVisitor {
331333 cx : cx,
332334 var : ident. node . name ,
@@ -348,19 +350,19 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex
348350 return ;
349351 }
350352
351- let starts_at_zero = is_integer_literal ( l , 0 ) ;
353+ let starts_at_zero = is_integer_literal ( start , 0 ) ;
352354
353355 let skip: Cow < _ > = if starts_at_zero {
354356 "" . into ( )
355357 } else {
356- format ! ( ".skip({})" , snippet( cx, l . span, ".." ) ) . into ( )
358+ format ! ( ".skip({})" , snippet( cx, start . span, ".." ) ) . into ( )
357359 } ;
358360
359- let take: Cow < _ > = if let Some ( ref r ) = * r {
360- if is_len_call ( & r , & indexed) {
361+ let take: Cow < _ > = if let Some ( ref end ) = * end {
362+ if is_len_call ( & end , & indexed) {
361363 "" . into ( )
362364 } else {
363- format ! ( ".take({})" , snippet( cx, r . span, ".." ) ) . into ( )
365+ format ! ( ".take({})" , snippet( cx, end . span, ".." ) ) . into ( )
364366 }
365367 } else {
366368 "" . into ( )
@@ -416,27 +418,27 @@ fn is_len_call(expr: &Expr, var: &Name) -> bool {
416418
417419fn check_for_loop_reverse_range ( cx : & LateContext , arg : & Expr , expr : & Expr ) {
418420 // if this for loop is iterating over a two-sided range...
419- if let ExprRange ( Some ( ref start_expr ) , Some ( ref stop_expr ) ) = arg. node {
421+ if let Some ( UnsugaredRange { start : Some ( ref start ) , end : Some ( ref end ) , limits } ) = unsugar_range ( & arg) {
420422 // ...and both sides are compile-time constant integers...
421- if let Ok ( start_idx) = eval_const_expr_partial ( & cx. tcx , start_expr , ExprTypeChecked , None ) {
422- if let Ok ( stop_idx ) = eval_const_expr_partial ( & cx. tcx , stop_expr , ExprTypeChecked , None ) {
423- // ...and the start index is greater than the stop index,
423+ if let Ok ( start_idx) = eval_const_expr_partial ( & cx. tcx , start , ExprTypeChecked , None ) {
424+ if let Ok ( end_idx ) = eval_const_expr_partial ( & cx. tcx , end , ExprTypeChecked , None ) {
425+ // ...and the start index is greater than the end index,
424426 // this loop will never run. This is often confusing for developers
425427 // who think that this will iterate from the larger value to the
426428 // smaller value.
427- let ( sup, eq) = match ( start_idx, stop_idx ) {
428- ( ConstVal :: Int ( start_idx) , ConstVal :: Int ( stop_idx ) ) => {
429- ( start_idx > stop_idx , start_idx == stop_idx )
429+ let ( sup, eq) = match ( start_idx, end_idx ) {
430+ ( ConstVal :: Int ( start_idx) , ConstVal :: Int ( end_idx ) ) => {
431+ ( start_idx > end_idx , start_idx == end_idx )
430432 }
431- ( ConstVal :: Uint ( start_idx) , ConstVal :: Uint ( stop_idx ) ) => {
432- ( start_idx > stop_idx , start_idx == stop_idx )
433+ ( ConstVal :: Uint ( start_idx) , ConstVal :: Uint ( end_idx ) ) => {
434+ ( start_idx > end_idx , start_idx == end_idx )
433435 }
434436 _ => ( false , false ) ,
435437 } ;
436438
437439 if sup {
438- let start_snippet = snippet ( cx, start_expr . span , "_" ) ;
439- let stop_snippet = snippet ( cx, stop_expr . span , "_" ) ;
440+ let start_snippet = snippet ( cx, start . span , "_" ) ;
441+ let end_snippet = snippet ( cx, end . span , "_" ) ;
440442
441443 span_lint_and_then ( cx,
442444 REVERSE_RANGE_LOOP ,
@@ -447,9 +449,9 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) {
447449 "consider using the following if \
448450 you are attempting to iterate \
449451 over this range in reverse",
450- format ! ( "({}..{}).rev()` " , stop_snippet , start_snippet) ) ;
452+ format ! ( "({}..{}).rev()` " , end_snippet , start_snippet) ) ;
451453 } ) ;
452- } else if eq {
454+ } else if eq && limits != ast :: RangeLimits :: Closed {
453455 // if they are equal, it's also problematic - this loop
454456 // will never run.
455457 span_lint ( cx,
0 commit comments