diff --git a/clippy_lints/src/array_indexing.rs b/clippy_lints/src/array_indexing.rs index 1b21cf8c5ff4..e07804468e17 100644 --- a/clippy_lints/src/array_indexing.rs +++ b/clippy_lints/src/array_indexing.rs @@ -73,7 +73,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIndexing { } // Index is a constant range - if let Some(range) = higher::range(index) { + if let Some(range) = higher::range(cx, index) { if let Some((start, end)) = to_const_range(cx, range, size) { if start > size || end > size { utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "range is out of bounds"); @@ -83,7 +83,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIndexing { } } - if let Some(range) = higher::range(index) { + if let Some(range) = higher::range(cx, index) { // Full ranges are always valid if range.start.is_none() && range.end.is_none() { return; diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 238970d4a9f2..a2eea3467438 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -167,7 +167,7 @@ fn is_infinite(cx: &LateContext, expr: &Expr) -> Finiteness { } else { Finite }, - ExprStruct(..) => higher::range(expr) + ExprStruct(..) => higher::range(cx, expr) .map_or(false, |r| r.end.is_none()) .into(), _ => Finite, diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index df5e4b885bce..87ea98533c32 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -888,7 +888,7 @@ fn detect_manual_memcpy<'a, 'tcx>( start: Some(start), ref end, limits, - }) = higher::range(arg) + }) = higher::range(cx, arg) { // the var must be a single name if let PatKind::Binding(_, canonical_id, _, _) = pat.node { @@ -982,7 +982,7 @@ fn check_for_loop_range<'a, 'tcx>( start: Some(start), ref end, limits, - }) = higher::range(arg) + }) = higher::range(cx, arg) { // the var must be a single name if let PatKind::Binding(_, canonical_id, ref ident, _) = pat.node { @@ -1118,7 +1118,7 @@ fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx start: Some(start), end: Some(end), limits, - }) = higher::range(arg) + }) = higher::range(cx, arg) { // ...and both sides are compile-time constant integers... if let Some((start_idx, _)) = constant(cx, start) { @@ -1456,7 +1456,7 @@ fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, body: &Expr) { start: Some(start), end: Some(end), .. - }) = higher::range(arg) + }) = higher::range(cx, arg) { let mut_ids = vec![ check_for_mutability(cx, start), diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 5a5dfe04d016..bc1ffc570036 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -110,7 +110,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { if let ExprMethodCall(ref iter_path, _, ref iter_args ) = *iter; if iter_path.name == "iter"; // range expression in .zip() call: 0..x.len() - if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(zip_arg); + if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(cx, zip_arg); if is_integer_literal(start, 0); // .len() call if let ExprMethodCall(ref len_path, _, ref len_args) = end.node; @@ -132,7 +132,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { // exclusive range plus one: x..(y+1) if_chain! { - if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::HalfOpen }) = higher::range(expr); + if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::HalfOpen }) = higher::range(cx, expr); if let Some(y) = y_plus_one(end); then { span_lint_and_then( @@ -153,7 +153,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { // inclusive range minus one: x..=(y-1) if_chain! { - if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::range(expr); + if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::range(cx, expr); if let Some(y) = y_minus_one(end); then { span_lint_and_then( diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index 011d2f7b8a25..9a4fcd45d8a6 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -3,7 +3,7 @@ #![deny(missing_docs_in_private_items)] -use rustc::hir; +use rustc::{hir, ty}; use rustc::lint::LateContext; use syntax::ast; use utils::{is_expn_of, match_def_path, match_qpath, opt_def_id, paths, resolve_node}; @@ -44,7 +44,36 @@ pub struct Range<'a> { } /// Higher a `hir` range to something similar to `ast::ExprKind::Range`. -pub fn range(expr: &hir::Expr) -> Option { +pub fn range<'a, 'b, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'b hir::Expr) -> Option> { + + let def_path = match cx.tables.expr_ty(expr).sty { + ty::TyAdt(def, _) => cx.tcx.def_path(def.did), + _ => return None, + }; + + // sanity checks for std::ops::RangeXXXX + if def_path.data.len() != 3 { + return None; + } + if def_path.data.get(0)?.data.as_interned_str() != "ops" { + return None; + } + if def_path.data.get(1)?.data.as_interned_str() != "range" { + return None; + } + let type_name = def_path.data.get(2)?.data.as_interned_str(); + let range_types = [ + "RangeFrom", + "RangeFull", + "RangeInclusive", + "Range", + "RangeTo", + "RangeToInclusive", + ]; + if !range_types.contains(&&*type_name.as_str()) { + return None; + } + /// Find the field named `name` in the field. Always return `Some` for /// convenience. fn get_field<'a>(name: &str, fields: &'a [hir::Field]) -> Option<&'a hir::Expr> { diff --git a/tests/run-pass/ice-2727.rs b/tests/run-pass/ice-2727.rs new file mode 100644 index 000000000000..79c6f1c55db6 --- /dev/null +++ b/tests/run-pass/ice-2727.rs @@ -0,0 +1,5 @@ +pub fn f(new: fn()) { + new(); +} + +fn main() {}