]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/array_indexing.rs
New upstream version 1.26.0+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / array_indexing.rs
CommitLineData
ea8adc8c 1use rustc::lint::*;
ea8adc8c 2use rustc::ty;
ea8adc8c
XL
3use rustc::hir;
4use syntax::ast::RangeLimits;
5use utils::{self, higher};
0531ce1d 6use consts::{constant, Constant};
ea8adc8c
XL
7
8/// **What it does:** Checks for out of bounds array indexing with a constant
9/// index.
10///
11/// **Why is this bad?** This will always panic at runtime.
12///
13/// **Known problems:** Hopefully none.
14///
15/// **Example:**
16/// ```rust
17/// let x = [1,2,3,4];
18/// ...
19/// x[9];
20/// &x[2..9];
21/// ```
0531ce1d 22declare_clippy_lint! {
ea8adc8c 23 pub OUT_OF_BOUNDS_INDEXING,
0531ce1d 24 correctness,
ea8adc8c
XL
25 "out of bounds constant indexing"
26}
27
28/// **What it does:** Checks for usage of indexing or slicing.
29///
30/// **Why is this bad?** Usually, this can be safely allowed. However, in some
31/// domains such as kernel development, a panic can cause the whole operating
32/// system to crash.
33///
34/// **Known problems:** Hopefully none.
35///
36/// **Example:**
37/// ```rust
38/// ...
39/// x[2];
40/// &x[0..2];
41/// ```
0531ce1d 42declare_clippy_lint! {
ea8adc8c 43 pub INDEXING_SLICING,
0531ce1d 44 restriction,
ea8adc8c
XL
45 "indexing/slicing usage"
46}
47
48#[derive(Copy, Clone)]
49pub struct ArrayIndexing;
50
51impl LintPass for ArrayIndexing {
52 fn get_lints(&self) -> LintArray {
53 lint_array!(INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING)
54 }
55}
56
57impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIndexing {
58 fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) {
59 if let hir::ExprIndex(ref array, ref index) = e.node {
60 // Array with known size can be checked statically
61 let ty = cx.tables.expr_ty(array);
62 if let ty::TyArray(_, size) = ty.sty {
0531ce1d 63 let size = size.val.to_raw_bits().unwrap();
ea8adc8c
XL
64
65 // Index is a constant uint
0531ce1d
XL
66 if let Some((Constant::Int(const_index), _)) = constant(cx, index) {
67 if size <= const_index {
68 utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "const index is out of bounds");
abe05a73 69 }
0531ce1d
XL
70
71 return;
ea8adc8c
XL
72 }
73
74 // Index is a constant range
75 if let Some(range) = higher::range(index) {
0531ce1d
XL
76 let start = range.start.map(|start| constant(cx, start).map(|(c, _)| c));
77 let end = range.end.map(|end| constant(cx, end).map(|(c, _)| c));
ea8adc8c
XL
78
79 if let Some((start, end)) = to_const_range(&start, &end, range.limits, size) {
80 if start > size || end > size {
81 utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "range is out of bounds");
82 }
83 return;
84 }
85 }
86 }
87
88 if let Some(range) = higher::range(index) {
89 // Full ranges are always valid
90 if range.start.is_none() && range.end.is_none() {
91 return;
92 }
93
94 // Impossible to know if indexing or slicing is correct
95 utils::span_lint(cx, INDEXING_SLICING, e.span, "slicing may panic");
96 } else {
97 utils::span_lint(cx, INDEXING_SLICING, e.span, "indexing may panic");
98 }
99 }
100 }
101}
102
103/// Returns an option containing a tuple with the start and end (exclusive) of
104/// the range.
105fn to_const_range(
0531ce1d
XL
106 start: &Option<Option<Constant>>,
107 end: &Option<Option<Constant>>,
ea8adc8c 108 limits: RangeLimits,
0531ce1d
XL
109 array_size: u128,
110) -> Option<(u128, u128)> {
ea8adc8c 111 let start = match *start {
0531ce1d 112 Some(Some(Constant::Int(x))) => x,
ea8adc8c 113 Some(_) => return None,
0531ce1d 114 None => 0,
ea8adc8c
XL
115 };
116
117 let end = match *end {
0531ce1d
XL
118 Some(Some(Constant::Int(x))) => if limits == RangeLimits::Closed {
119 x + 1
abe05a73
XL
120 } else {
121 x
ea8adc8c
XL
122 },
123 Some(_) => return None,
124 None => array_size,
125 };
126
127 Some((start, end))
128}