Skip to content

Commit b528256

Browse files
committed
add some comments
1 parent 1a640ab commit b528256

File tree

1 file changed

+33
-11
lines changed

1 file changed

+33
-11
lines changed

clippy_lints/src/missing_assert_for_indexing.rs

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ enum LengthComparison {
9191
IntLessThanOrEqualLength,
9292
}
9393

94+
/// Extracts parts out of a length comparison expression.
95+
///
96+
/// E.g. for `v.len() > 5` this returns `Some((LengthComparison::IntLessThanLength, 5, `v.len()`))`
9497
fn len_comparison<'hir>(
9598
bin_op: BinOp,
9699
left: &'hir Expr<'hir>,
@@ -105,7 +108,7 @@ fn len_comparison<'hir>(
105108
};
106109
}
107110

108-
// normalize comparison, `v.len() > 4` becomes `4 <= v.len()`
111+
// normalize comparison, `v.len() > 4` becomes `4 < v.len()`
109112
// this simplifies the logic a bit
110113
let (op, left, right) = normalize_comparison(bin_op.node, left, right)?;
111114
match (op, &left.kind, &right.kind) {
@@ -117,6 +120,8 @@ fn len_comparison<'hir>(
117120
}
118121
}
119122

123+
/// Attempts to extract parts out of an `assert!`-like expression
124+
/// in the form `assert!(some_slice.len() > 5)`.
120125
fn assert_len_expr<'hir>(
121126
cx: &LateContext<'_>,
122127
expr: &'hir Expr<'hir>,
@@ -142,12 +147,17 @@ fn assert_len_expr<'hir>(
142147

143148
#[derive(Debug)]
144149
enum IndexEntry {
150+
/// `assert!` without any indexing (so far)
145151
StrayAssert {
146152
asserted_len: usize,
147153
cmp: LengthComparison,
148154
assert_span: Span,
149155
slice_span: Span,
150156
},
157+
/// `assert!` with indexing
158+
///
159+
/// We also store the highest index to be able to check
160+
/// if the `assert!` asserts the right length.
151161
AssertWithIndex {
152162
highest_index: usize,
153163
asserted_len: usize,
@@ -156,7 +166,8 @@ enum IndexEntry {
156166
indexes: Vec<Span>,
157167
cmp: LengthComparison,
158168
},
159-
AssertWithoutIndex {
169+
/// Indexing without an `assert!`
170+
IndexWithoutAssert {
160171
highest_index: usize,
161172
indexes: Vec<Span>,
162173
slice_span: Span,
@@ -167,13 +178,17 @@ impl IndexEntry {
167178
pub fn spans(&self) -> Option<&[Span]> {
168179
match self {
169180
IndexEntry::StrayAssert { .. } => None,
170-
IndexEntry::AssertWithIndex { indexes, .. } | IndexEntry::AssertWithoutIndex { indexes, .. } => {
181+
IndexEntry::AssertWithIndex { indexes, .. } | IndexEntry::IndexWithoutAssert { indexes, .. } => {
171182
Some(indexes)
172183
},
173184
}
174185
}
175186
}
176187

188+
/// Extracts the upper index of a slice indexing expression.
189+
///
190+
/// E.g. for `5` this returns `Some(5)`, for `..5` this returns `Some(4)`,
191+
/// for `..=5` this returns `Some(5)`
177192
fn upper_index_expr(expr: &Expr<'_>) -> Option<usize> {
178193
if let ExprKind::Lit(lit) = &expr.kind && let LitKind::Int(index, _) = lit.node {
179194
Some(index as usize)
@@ -190,35 +205,36 @@ fn upper_index_expr(expr: &Expr<'_>) -> Option<usize> {
190205
}
191206
}
192207

208+
/// Checks if the expression is an index into a slice and adds it to the `indexes` map
193209
fn check_index(cx: &LateContext<'_>, expr: &Expr<'_>, indexes: &mut FxHashMap<u64, IndexEntry>) {
194210
if let ExprKind::Index(target, index_lit) = expr.kind
195211
&& cx.typeck_results().expr_ty(target).peel_refs().is_slice()
196212
&& let Some(index) = upper_index_expr(index_lit)
197213
{
198214
let hash = hash_expr(cx, target);
199215
let entry = indexes.entry(hash)
200-
.or_insert_with(|| IndexEntry::AssertWithoutIndex {
216+
.or_insert_with(|| IndexEntry::IndexWithoutAssert {
201217
highest_index: index,
202218
slice_span: target.span,
203219
indexes: Vec::new(),
204220
});
205221

206222
match entry {
207-
IndexEntry::StrayAssert { asserted_len, cmp, assert_span, slice_span: receiver_span } => {
223+
IndexEntry::StrayAssert { asserted_len, cmp, assert_span, slice_span } => {
208224
let asserted_len = *asserted_len;
209225
let cmp = *cmp;
210226
let assert_span = *assert_span;
211-
let receiver_span = *receiver_span;
227+
let slice_span = *slice_span;
212228
*entry = IndexEntry::AssertWithIndex {
213229
highest_index: index,
214230
asserted_len,
215231
indexes: vec![expr.span],
216232
assert_span,
217233
cmp,
218-
slice_span: receiver_span
234+
slice_span
219235
};
220236
}
221-
IndexEntry::AssertWithoutIndex { highest_index, indexes, .. }
237+
IndexEntry::IndexWithoutAssert { highest_index, indexes, .. }
222238
| IndexEntry::AssertWithIndex { highest_index, indexes, .. } => {
223239
indexes.push(expr.span);
224240
*highest_index = (*highest_index).max(index);
@@ -227,6 +243,7 @@ fn check_index(cx: &LateContext<'_>, expr: &Expr<'_>, indexes: &mut FxHashMap<u6
227243
}
228244
}
229245

246+
/// Checks if the expression is an `assert!` expression and adds it to the `indexes` map
230247
fn check_assert(cx: &LateContext<'_>, expr: &Expr<'_>, indexes: &mut FxHashMap<u64, IndexEntry>) {
231248
if let Some((cmp, asserted_len, slice)) = assert_len_expr(cx, expr) {
232249
let hash = hash_expr(cx, slice);
@@ -240,7 +257,7 @@ fn check_assert(cx: &LateContext<'_>, expr: &Expr<'_>, indexes: &mut FxHashMap<u
240257
});
241258
},
242259
Entry::Occupied(mut entry) => {
243-
if let IndexEntry::AssertWithoutIndex {
260+
if let IndexEntry::IndexWithoutAssert {
244261
highest_index, indexes, ..
245262
} = entry.get_mut()
246263
{
@@ -261,6 +278,9 @@ fn check_assert(cx: &LateContext<'_>, expr: &Expr<'_>, indexes: &mut FxHashMap<u
261278
}
262279
}
263280

281+
/// Inspects indexes and reports lints.
282+
///
283+
/// Called at the end of this lint after all indexing and `assert!` expressions have been collected.
264284
fn report_indexes(cx: &LateContext<'_>, indexes: &mut FxHashMap<u64, IndexEntry>) {
265285
for entry in indexes.values() {
266286
let Some(full_span) = entry
@@ -280,7 +300,7 @@ fn report_indexes(cx: &LateContext<'_>, indexes: &mut FxHashMap<u64, IndexEntry>
280300
slice_span: receiver_span,
281301
} if indexes.len() > 1 => {
282302
// if we have found an `assert!`, let's also check that it's actually right
283-
// and convers the highest index and if not, suggest the correct length
303+
// and if it convers the highest index and if not, suggest the correct length
284304
let sugg = match cmp {
285305
// `v.len() < 5` and `v.len() <= 5` does nothing in terms of bounds checks.
286306
// The user probably meant `v.len() > 5`
@@ -318,11 +338,13 @@ fn report_indexes(cx: &LateContext<'_>, indexes: &mut FxHashMap<u64, IndexEntry>
318338
);
319339
}
320340
},
321-
IndexEntry::AssertWithoutIndex {
341+
IndexEntry::IndexWithoutAssert {
322342
indexes,
323343
highest_index,
324344
slice_span: receiver_span,
325345
} if indexes.len() > 1 => {
346+
// if there was no `assert!` but more than one index, suggest
347+
// adding an `assert!` that covers the highest index
326348
report_lint(
327349
cx,
328350
full_span,

0 commit comments

Comments
 (0)