mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-23 13:13:34 +00:00
Check that we don't treat any type but a range type as a range
This commit is contained in:
parent
e456241f18
commit
c6e35eae53
6 changed files with 46 additions and 12 deletions
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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<Range> {
|
||||
pub fn range<'a, 'b, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'b hir::Expr) -> Option<Range<'b>> {
|
||||
|
||||
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> {
|
||||
|
|
5
tests/run-pass/ice-2727.rs
Normal file
5
tests/run-pass/ice-2727.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
pub fn f(new: fn()) {
|
||||
new();
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in a new issue