|
| 1 | +use reexport::*; |
| 2 | +use rustc::front::map::Node::NodeBlock; |
1 | 3 | use rustc::lint::*;
|
| 4 | +use rustc::middle::const_eval::EvalHint::ExprTypeChecked; |
| 5 | +use rustc::middle::const_eval::{ConstVal, eval_const_expr_partial}; |
| 6 | +use rustc::middle::def::Def; |
| 7 | +use rustc::middle::ty; |
2 | 8 | use rustc_front::hir::*;
|
3 |
| -use reexport::*; |
4 | 9 | use rustc_front::intravisit::{Visitor, walk_expr, walk_block, walk_decl};
|
5 |
| -use rustc::middle::ty; |
6 |
| -use rustc::middle::def::Def; |
7 |
| -use consts::{constant_simple, Constant}; |
8 |
| -use rustc::front::map::Node::NodeBlock; |
9 | 10 | use std::borrow::Cow;
|
10 | 11 | use std::collections::{HashSet, HashMap};
|
11 | 12 |
|
@@ -421,22 +422,36 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) {
|
421 | 422 | // if this for loop is iterating over a two-sided range...
|
422 | 423 | if let ExprRange(Some(ref start_expr), Some(ref stop_expr)) = arg.node {
|
423 | 424 | // ...and both sides are compile-time constant integers...
|
424 |
| - if let Some(start_idx @ Constant::Int(..)) = constant_simple(start_expr) { |
425 |
| - if let Some(stop_idx @ Constant::Int(..)) = constant_simple(stop_expr) { |
| 425 | + if let Ok(start_idx) = eval_const_expr_partial(&cx.tcx, start_expr, ExprTypeChecked, None) { |
| 426 | + if let Ok(stop_idx) = eval_const_expr_partial(&cx.tcx, stop_expr, ExprTypeChecked, None) { |
426 | 427 | // ...and the start index is greater than the stop index,
|
427 | 428 | // this loop will never run. This is often confusing for developers
|
428 | 429 | // who think that this will iterate from the larger value to the
|
429 | 430 | // smaller value.
|
430 |
| - if start_idx > stop_idx { |
431 |
| - span_help_and_lint(cx, |
| 431 | + let (sup, eq) = match (start_idx, stop_idx) { |
| 432 | + (ConstVal::Int(start_idx), ConstVal::Int(stop_idx)) => (start_idx > stop_idx, start_idx == stop_idx), |
| 433 | + (ConstVal::Uint(start_idx), ConstVal::Uint(stop_idx)) => (start_idx > stop_idx, start_idx == stop_idx), |
| 434 | + _ => (false, false), |
| 435 | + }; |
| 436 | + |
| 437 | + if sup { |
| 438 | + let start_snippet = snippet(cx, start_expr.span, "_"); |
| 439 | + let stop_snippet = snippet(cx, stop_expr.span, "_"); |
| 440 | + |
| 441 | + span_lint_and_then(cx, |
432 | 442 | REVERSE_RANGE_LOOP,
|
433 | 443 | expr.span,
|
434 | 444 | "this range is empty so this for loop will never run",
|
435 |
| - &format!("Consider using `({}..{}).rev()` if you are attempting to iterate \ |
436 |
| - over this range in reverse", |
437 |
| - stop_idx, |
438 |
| - start_idx)); |
439 |
| - } else if start_idx == stop_idx { |
| 445 | + |db| { |
| 446 | + db.span_suggestion(expr.span, |
| 447 | + "consider using the following if \ |
| 448 | + you are attempting to iterate \ |
| 449 | + over this range in reverse", |
| 450 | + format!("({}..{}).rev()` ", |
| 451 | + stop_snippet, |
| 452 | + start_snippet)); |
| 453 | + }); |
| 454 | + } else if eq { |
440 | 455 | // if they are equal, it's also problematic - this loop
|
441 | 456 | // will never run.
|
442 | 457 | span_lint(cx,
|
|
0 commit comments