mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-12-11 22:02:55 +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
|
// 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 let Some((start, end)) = to_const_range(cx, range, size) {
|
||||||
if start > size || end > size {
|
if start > size || end > size {
|
||||||
utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "range is out of bounds");
|
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
|
// Full ranges are always valid
|
||||||
if range.start.is_none() && range.end.is_none() {
|
if range.start.is_none() && range.end.is_none() {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -167,7 +167,7 @@ fn is_infinite(cx: &LateContext, expr: &Expr) -> Finiteness {
|
||||||
} else {
|
} else {
|
||||||
Finite
|
Finite
|
||||||
},
|
},
|
||||||
ExprStruct(..) => higher::range(expr)
|
ExprStruct(..) => higher::range(cx, expr)
|
||||||
.map_or(false, |r| r.end.is_none())
|
.map_or(false, |r| r.end.is_none())
|
||||||
.into(),
|
.into(),
|
||||||
_ => Finite,
|
_ => Finite,
|
||||||
|
|
|
@ -888,7 +888,7 @@ fn detect_manual_memcpy<'a, 'tcx>(
|
||||||
start: Some(start),
|
start: Some(start),
|
||||||
ref end,
|
ref end,
|
||||||
limits,
|
limits,
|
||||||
}) = higher::range(arg)
|
}) = higher::range(cx, arg)
|
||||||
{
|
{
|
||||||
// the var must be a single name
|
// the var must be a single name
|
||||||
if let PatKind::Binding(_, canonical_id, _, _) = pat.node {
|
if let PatKind::Binding(_, canonical_id, _, _) = pat.node {
|
||||||
|
@ -982,7 +982,7 @@ fn check_for_loop_range<'a, 'tcx>(
|
||||||
start: Some(start),
|
start: Some(start),
|
||||||
ref end,
|
ref end,
|
||||||
limits,
|
limits,
|
||||||
}) = higher::range(arg)
|
}) = higher::range(cx, arg)
|
||||||
{
|
{
|
||||||
// the var must be a single name
|
// the var must be a single name
|
||||||
if let PatKind::Binding(_, canonical_id, ref ident, _) = pat.node {
|
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),
|
start: Some(start),
|
||||||
end: Some(end),
|
end: Some(end),
|
||||||
limits,
|
limits,
|
||||||
}) = higher::range(arg)
|
}) = higher::range(cx, arg)
|
||||||
{
|
{
|
||||||
// ...and both sides are compile-time constant integers...
|
// ...and both sides are compile-time constant integers...
|
||||||
if let Some((start_idx, _)) = constant(cx, start) {
|
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),
|
start: Some(start),
|
||||||
end: Some(end),
|
end: Some(end),
|
||||||
..
|
..
|
||||||
}) = higher::range(arg)
|
}) = higher::range(cx, arg)
|
||||||
{
|
{
|
||||||
let mut_ids = vec![
|
let mut_ids = vec![
|
||||||
check_for_mutability(cx, start),
|
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 let ExprMethodCall(ref iter_path, _, ref iter_args ) = *iter;
|
||||||
if iter_path.name == "iter";
|
if iter_path.name == "iter";
|
||||||
// range expression in .zip() call: 0..x.len()
|
// 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);
|
if is_integer_literal(start, 0);
|
||||||
// .len() call
|
// .len() call
|
||||||
if let ExprMethodCall(ref len_path, _, ref len_args) = end.node;
|
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)
|
// exclusive range plus one: x..(y+1)
|
||||||
if_chain! {
|
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);
|
if let Some(y) = y_plus_one(end);
|
||||||
then {
|
then {
|
||||||
span_lint_and_then(
|
span_lint_and_then(
|
||||||
|
@ -153,7 +153,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
||||||
|
|
||||||
// inclusive range minus one: x..=(y-1)
|
// inclusive range minus one: x..=(y-1)
|
||||||
if_chain! {
|
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);
|
if let Some(y) = y_minus_one(end);
|
||||||
then {
|
then {
|
||||||
span_lint_and_then(
|
span_lint_and_then(
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#![deny(missing_docs_in_private_items)]
|
#![deny(missing_docs_in_private_items)]
|
||||||
|
|
||||||
use rustc::hir;
|
use rustc::{hir, ty};
|
||||||
use rustc::lint::LateContext;
|
use rustc::lint::LateContext;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use utils::{is_expn_of, match_def_path, match_qpath, opt_def_id, paths, resolve_node};
|
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`.
|
/// 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
|
/// Find the field named `name` in the field. Always return `Some` for
|
||||||
/// convenience.
|
/// convenience.
|
||||||
fn get_field<'a>(name: &str, fields: &'a [hir::Field]) -> Option<&'a hir::Expr> {
|
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