Skip to content

Commit dba8b14

Browse files
committed
Move unsugar_range to utils::higher
1 parent 068a843 commit dba8b14

File tree

5 files changed

+99
-97
lines changed

5 files changed

+99
-97
lines changed

clippy_lints/src/array_indexing.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_const_eval::eval_const_expr_partial;
66
use rustc_const_math::ConstInt;
77
use rustc::hir::*;
88
use syntax::ast::RangeLimits;
9-
use utils;
9+
use utils::{self, higher};
1010

1111
/// **What it does:** Check for out of bounds array indexing with a constant index.
1212
///
@@ -77,7 +77,7 @@ impl LateLintPass for ArrayIndexing {
7777
}
7878

7979
// Index is a constant range
80-
if let Some(range) = utils::unsugar_range(index) {
80+
if let Some(range) = higher::range(index) {
8181
let start = range.start
8282
.map(|start| eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None))
8383
.map(|v| v.ok());
@@ -94,7 +94,7 @@ impl LateLintPass for ArrayIndexing {
9494
}
9595
}
9696

97-
if let Some(range) = utils::unsugar_range(index) {
97+
if let Some(range) = higher::range(index) {
9898
// Full ranges are always valid
9999
if range.start.is_none() && range.end.is_none() {
100100
return;

clippy_lints/src/loops.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@ use std::collections::HashMap;
1414
use syntax::ast;
1515

1616
use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro,
17-
span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, unsugar_range,
17+
span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, higher,
1818
walk_ptrs_ty, recover_for_loop};
1919
use utils::paths;
20-
use utils::UnsugaredRange;
2120

2221
/// **What it does:** This lint checks for looping over the range of `0..len` of some collection just to get the values by index.
2322
///
@@ -333,7 +332,7 @@ fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &E
333332
/// Check for looping over a range and then indexing a sequence with it.
334333
/// The iteratee must be a range literal.
335334
fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) {
336-
if let Some(UnsugaredRange { start: Some(ref start), ref end, .. }) = unsugar_range(arg) {
335+
if let Some(higher::Range { start: Some(ref start), ref end, .. }) = higher::range(arg) {
337336
// the var must be a single name
338337
if let PatKind::Binding(_, ref ident, _) = pat.node {
339338
let mut visitor = VarVisitor {
@@ -427,7 +426,7 @@ fn is_len_call(expr: &Expr, var: &Name) -> bool {
427426

428427
fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) {
429428
// if this for loop is iterating over a two-sided range...
430-
if let Some(UnsugaredRange { start: Some(ref start), end: Some(ref end), limits }) = unsugar_range(arg) {
429+
if let Some(higher::Range { start: Some(ref start), end: Some(ref end), limits }) = higher::range(arg) {
431430
// ...and both sides are compile-time constant integers...
432431
if let Ok(start_idx) = eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None) {
433432
if let Ok(end_idx) = eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None) {

clippy_lints/src/ranges.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use rustc::lint::*;
22
use rustc::hir::*;
33
use syntax::codemap::Spanned;
4-
use utils::{is_integer_literal, match_type, paths, snippet, span_lint, unsugar_range, UnsugaredRange};
4+
use utils::{is_integer_literal, match_type, paths, snippet, span_lint};
5+
use utils::higher;
56

67
/// **What it does:** This lint checks for iterating over ranges with a `.step_by(0)`, which never terminates.
78
///
@@ -54,7 +55,7 @@ impl LateLintPass for StepByZero {
5455
let ExprMethodCall( Spanned { node: ref iter_name, .. }, _, ref iter_args ) = *iter,
5556
iter_name.as_str() == "iter",
5657
// range expression in .zip() call: 0..x.len()
57-
let Some(UnsugaredRange { start: Some(ref start), end: Some(ref end), .. }) = unsugar_range(zip_arg),
58+
let Some(higher::Range { start: Some(ref start), end: Some(ref end), .. }) = higher::range(zip_arg),
5859
is_integer_literal(start, 0),
5960
// .len() call
6061
let ExprMethodCall(Spanned { node: ref len_name, .. }, _, ref len_args) = end.node,

clippy_lints/src/utils/higher.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use rustc::hir;
44
use syntax::ast;
5+
use utils::{match_path, paths};
56

67
/// Convert a hir binary operator to the corresponding `ast` type.
78
pub fn binop(op: hir::BinOp_) -> ast::BinOpKind {
@@ -26,3 +27,91 @@ pub fn binop(op: hir::BinOp_) -> ast::BinOpKind {
2627
hir::BiSub => ast::BinOpKind::Sub,
2728
}
2829
}
30+
31+
/// Represent a range akin to `ast::ExprKind::Range`.
32+
#[derive(Debug, Copy, Clone)]
33+
pub struct Range<'a> {
34+
pub start: Option<&'a hir::Expr>,
35+
pub end: Option<&'a hir::Expr>,
36+
pub limits: ast::RangeLimits,
37+
}
38+
39+
/// Higher a `hir` range to something similar to `ast::ExprKind::Range`.
40+
pub fn range(expr: &hir::Expr) -> Option<Range> {
41+
// To be removed when ranges get stable.
42+
fn unwrap_unstable(expr: &hir::Expr) -> &hir::Expr {
43+
if let hir::ExprBlock(ref block) = expr.node {
44+
if block.rules == hir::BlockCheckMode::PushUnstableBlock || block.rules == hir::BlockCheckMode::PopUnstableBlock {
45+
if let Some(ref expr) = block.expr {
46+
return expr;
47+
}
48+
}
49+
}
50+
51+
expr
52+
}
53+
54+
fn get_field<'a>(name: &str, fields: &'a [hir::Field]) -> Option<&'a hir::Expr> {
55+
let expr = &fields.iter()
56+
.find(|field| field.name.node.as_str() == name)
57+
.unwrap_or_else(|| panic!("missing {} field for range", name))
58+
.expr;
59+
60+
Some(unwrap_unstable(expr))
61+
}
62+
63+
// The range syntax is expanded to literal paths starting with `core` or `std` depending on
64+
// `#[no_std]`. Testing both instead of resolving the paths.
65+
66+
match unwrap_unstable(expr).node {
67+
hir::ExprPath(None, ref path) => {
68+
if match_path(path, &paths::RANGE_FULL_STD) || match_path(path, &paths::RANGE_FULL) {
69+
Some(Range {
70+
start: None,
71+
end: None,
72+
limits: ast::RangeLimits::HalfOpen,
73+
})
74+
} else {
75+
None
76+
}
77+
}
78+
hir::ExprStruct(ref path, ref fields, None) => {
79+
if match_path(path, &paths::RANGE_FROM_STD) || match_path(path, &paths::RANGE_FROM) {
80+
Some(Range {
81+
start: get_field("start", fields),
82+
end: None,
83+
limits: ast::RangeLimits::HalfOpen,
84+
})
85+
} else if match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY_STD) ||
86+
match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY) {
87+
Some(Range {
88+
start: get_field("start", fields),
89+
end: get_field("end", fields),
90+
limits: ast::RangeLimits::Closed,
91+
})
92+
} else if match_path(path, &paths::RANGE_STD) || match_path(path, &paths::RANGE) {
93+
Some(Range {
94+
start: get_field("start", fields),
95+
end: get_field("end", fields),
96+
limits: ast::RangeLimits::HalfOpen,
97+
})
98+
} else if match_path(path, &paths::RANGE_TO_INCLUSIVE_STD) || match_path(path, &paths::RANGE_TO_INCLUSIVE) {
99+
Some(Range {
100+
start: None,
101+
end: get_field("end", fields),
102+
limits: ast::RangeLimits::Closed,
103+
})
104+
} else if match_path(path, &paths::RANGE_TO_STD) || match_path(path, &paths::RANGE_TO) {
105+
Some(Range {
106+
start: None,
107+
end: get_field("end", fields),
108+
limits: ast::RangeLimits::HalfOpen,
109+
})
110+
} else {
111+
None
112+
}
113+
}
114+
_ => None,
115+
}
116+
}
117+

clippy_lints/src/utils/mod.rs

Lines changed: 1 addition & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use std::borrow::Cow;
1313
use std::env;
1414
use std::mem;
1515
use std::str::FromStr;
16-
use syntax::ast::{self, LitKind, RangeLimits};
16+
use syntax::ast::{self, LitKind};
1717
use syntax::codemap::{ExpnInfo, Span, ExpnFormat};
1818
use syntax::errors::DiagnosticBuilder;
1919
use syntax::ptr::P;
@@ -683,93 +683,6 @@ pub fn camel_case_from(s: &str) -> usize {
683683
last_i
684684
}
685685

686-
/// Represent a range akin to `ast::ExprKind::Range`.
687-
#[derive(Debug, Copy, Clone)]
688-
pub struct UnsugaredRange<'a> {
689-
pub start: Option<&'a Expr>,
690-
pub end: Option<&'a Expr>,
691-
pub limits: RangeLimits,
692-
}
693-
694-
/// Unsugar a `hir` range.
695-
pub fn unsugar_range(expr: &Expr) -> Option<UnsugaredRange> {
696-
// To be removed when ranges get stable.
697-
fn unwrap_unstable(expr: &Expr) -> &Expr {
698-
if let ExprBlock(ref block) = expr.node {
699-
if block.rules == BlockCheckMode::PushUnstableBlock || block.rules == BlockCheckMode::PopUnstableBlock {
700-
if let Some(ref expr) = block.expr {
701-
return expr;
702-
}
703-
}
704-
}
705-
706-
expr
707-
}
708-
709-
fn get_field<'a>(name: &str, fields: &'a [Field]) -> Option<&'a Expr> {
710-
let expr = &fields.iter()
711-
.find(|field| field.name.node.as_str() == name)
712-
.unwrap_or_else(|| panic!("missing {} field for range", name))
713-
.expr;
714-
715-
Some(unwrap_unstable(expr))
716-
}
717-
718-
// The range syntax is expanded to literal paths starting with `core` or `std` depending on
719-
// `#[no_std]`. Testing both instead of resolving the paths.
720-
721-
match unwrap_unstable(expr).node {
722-
ExprPath(None, ref path) => {
723-
if match_path(path, &paths::RANGE_FULL_STD) || match_path(path, &paths::RANGE_FULL) {
724-
Some(UnsugaredRange {
725-
start: None,
726-
end: None,
727-
limits: RangeLimits::HalfOpen,
728-
})
729-
} else {
730-
None
731-
}
732-
}
733-
ExprStruct(ref path, ref fields, None) => {
734-
if match_path(path, &paths::RANGE_FROM_STD) || match_path(path, &paths::RANGE_FROM) {
735-
Some(UnsugaredRange {
736-
start: get_field("start", fields),
737-
end: None,
738-
limits: RangeLimits::HalfOpen,
739-
})
740-
} else if match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY_STD) ||
741-
match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY) {
742-
Some(UnsugaredRange {
743-
start: get_field("start", fields),
744-
end: get_field("end", fields),
745-
limits: RangeLimits::Closed,
746-
})
747-
} else if match_path(path, &paths::RANGE_STD) || match_path(path, &paths::RANGE) {
748-
Some(UnsugaredRange {
749-
start: get_field("start", fields),
750-
end: get_field("end", fields),
751-
limits: RangeLimits::HalfOpen,
752-
})
753-
} else if match_path(path, &paths::RANGE_TO_INCLUSIVE_STD) || match_path(path, &paths::RANGE_TO_INCLUSIVE) {
754-
Some(UnsugaredRange {
755-
start: None,
756-
end: get_field("end", fields),
757-
limits: RangeLimits::Closed,
758-
})
759-
} else if match_path(path, &paths::RANGE_TO_STD) || match_path(path, &paths::RANGE_TO) {
760-
Some(UnsugaredRange {
761-
start: None,
762-
end: get_field("end", fields),
763-
limits: RangeLimits::HalfOpen,
764-
})
765-
} else {
766-
None
767-
}
768-
}
769-
_ => None,
770-
}
771-
}
772-
773686
/// Convenience function to get the return type of a function or `None` if the function diverges.
774687
pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> Option<ty::Ty<'tcx>> {
775688
let parameter_env = ty::ParameterEnvironment::for_item(cx.tcx, fn_item);

0 commit comments

Comments
 (0)