diff --git a/README.md b/README.md index 015a7d9adf26..dc8fd37dfc9c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 84 lints included in this crate: +There are 85 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -58,6 +58,7 @@ name [option_map_unwrap_or](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or) | warn | using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)`) [option_map_unwrap_or_else](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or_else) | warn | using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`) [option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` +[out_of_bounds_indexing](https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing) | deny | out of bound constant indexing [precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught [ptr_arg](https://github.com/Manishearth/rust-clippy/wiki#ptr_arg) | warn | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively [range_step_by_zero](https://github.com/Manishearth/rust-clippy/wiki#range_step_by_zero) | warn | using Range::step_by(0), which produces an infinite iterator diff --git a/src/array_indexing.rs b/src/array_indexing.rs new file mode 100644 index 000000000000..d72adac943f4 --- /dev/null +++ b/src/array_indexing.rs @@ -0,0 +1,52 @@ +use rustc::lint::*; +use rustc::middle::const_eval::EvalHint::ExprTypeChecked; +use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; +use rustc::middle::ty::TyArray; +use rustc_front::hir::*; +use utils::span_lint; + +/// **What it does:** Check for out of bounds array indexing with a constant index. +/// +/// **Why is this bad?** This will always panic at runtime. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** +/// +/// ``` +/// let x = [1,2,3,4]; +/// ... +/// x[9]; +/// ``` +declare_lint! { + pub OUT_OF_BOUNDS_INDEXING, + Deny, + "out of bound constant indexing" +} + +#[derive(Copy,Clone)] +pub struct ArrayIndexing; + +impl LintPass for ArrayIndexing { + fn get_lints(&self) -> LintArray { + lint_array!(OUT_OF_BOUNDS_INDEXING) + } +} + +impl LateLintPass for ArrayIndexing { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if let ExprIndex(ref array, ref index) = e.node { + let ty = cx.tcx.expr_ty(array); + + if let TyArray(_, size) = ty.sty { + let index = eval_const_expr_partial(cx.tcx, &index, ExprTypeChecked, None); + if let Ok(ConstVal::Uint(index)) = index { + if size as u64 <= index { + span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, + "const index-expr is out of bounds"); + } + } + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 05181e69b2ce..29b911a0cb24 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,6 +66,7 @@ pub mod transmute; pub mod cyclomatic_complexity; pub mod escape; pub mod misc_early; +pub mod array_indexing; mod reexport { pub use syntax::ast::{Name, NodeId}; @@ -121,6 +122,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box escape::EscapePass); reg.register_early_lint_pass(box misc_early::MiscEarly); reg.register_late_lint_pass(box misc::UsedUnderscoreBinding); + reg.register_late_lint_pass(box array_indexing::ArrayIndexing); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -143,6 +145,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_group("clippy", vec![ approx_const::APPROX_CONSTANT, + array_indexing::OUT_OF_BOUNDS_INDEXING, attrs::INLINE_ALWAYS, bit_mask::BAD_BIT_MASK, bit_mask::INEFFECTIVE_BIT_MASK, diff --git a/tests/compile-fail/array_indexing.rs b/tests/compile-fail/array_indexing.rs new file mode 100755 index 000000000000..68ab71da586c --- /dev/null +++ b/tests/compile-fail/array_indexing.rs @@ -0,0 +1,12 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(out_of_bounds_indexing)] + +fn main() { + let x = [1,2,3,4]; + x[0]; + x[3]; + x[4]; //~ERROR: const index-expr is out of bounds + x[1 << 3]; //~ERROR: const index-expr is out of bounds +}