Skip to content

Commit 93b39d8

Browse files
committed
disable indexing_slicing for custom Index impls
1 parent 03654ba commit 93b39d8

File tree

5 files changed

+80
-47
lines changed

5 files changed

+80
-47
lines changed

clippy_lints/src/indexing_slicing.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use clippy_utils::consts::{constant, Constant};
44
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
55
use clippy_utils::higher;
6+
use clippy_utils::ty::{adt_has_inherent_method, deref_chain};
67
use rustc_ast::ast::RangeLimits;
78
use rustc_hir::{Expr, ExprKind};
89
use rustc_lint::{LateContext, LateLintPass};
@@ -104,7 +105,15 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
104105
return;
105106
}
106107

107-
if let ExprKind::Index(array, index, _) = &expr.kind {
108+
if let ExprKind::Index(array, index, _) = &expr.kind
109+
&& let expr_ty = cx.typeck_results().expr_ty(array)
110+
&& let mut deref = deref_chain(cx, expr_ty)
111+
&& deref.any(|l| {
112+
l.peel_refs().is_slice()
113+
|| l.peel_refs().is_array()
114+
|| adt_has_inherent_method(cx, l.peel_refs(), sym!(get))
115+
})
116+
{
108117
let note = "the suggestion might not be applicable in constant blocks";
109118
let ty = cx.typeck_results().expr_ty(array).peel_refs();
110119
if let Some(range) = higher::Range::hir(index) {

clippy_lints/src/iter_without_into_iter.rs

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::get_parent_as_impl;
33
use clippy_utils::source::snippet;
4-
use clippy_utils::ty::{implements_trait, make_normalized_projection};
4+
use clippy_utils::ty::{adt_has_inherent_method, deref_chain, implements_trait, make_normalized_projection};
55
use rustc_ast::Mutability;
66
use rustc_errors::Applicability;
77
use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind};
88
use rustc_lint::{LateContext, LateLintPass, LintContext};
99
use rustc_middle::lint::in_external_macro;
1010
use rustc_middle::ty::{self, Ty};
1111
use rustc_session::declare_lint_pass;
12-
use rustc_span::{sym, Symbol};
13-
use std::iter;
12+
use rustc_span::sym;
1413

1514
declare_clippy_lint! {
1615
/// ### What it does
@@ -124,33 +123,6 @@ fn is_ty_exported(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
124123
.is_some_and(|did| cx.effective_visibilities.is_exported(did))
125124
}
126125

127-
/// Returns the deref chain of a type, starting with the type itself.
128-
fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iterator<Item = Ty<'tcx>> + 'cx {
129-
iter::successors(Some(ty), |&ty| {
130-
if let Some(deref_did) = cx.tcx.lang_items().deref_trait()
131-
&& implements_trait(cx, ty, deref_did, &[])
132-
{
133-
make_normalized_projection(cx.tcx, cx.param_env, deref_did, sym::Target, [ty])
134-
} else {
135-
None
136-
}
137-
})
138-
}
139-
140-
fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool {
141-
if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) {
142-
cx.tcx.inherent_impls(ty_did).into_iter().flatten().any(|&did| {
143-
cx.tcx
144-
.associated_items(did)
145-
.filter_by_name_unhygienic(method_name)
146-
.next()
147-
.is_some_and(|item| item.kind == ty::AssocKind::Fn)
148-
})
149-
} else {
150-
false
151-
}
152-
}
153-
154126
impl LateLintPass<'_> for IterWithoutIntoIter {
155127
fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
156128
if !in_external_macro(cx.sess(), item.span)

clippy_utils/src/ty.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,3 +1328,33 @@ pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>
13281328
pub fn is_manually_drop(ty: Ty<'_>) -> bool {
13291329
ty.ty_adt_def().map_or(false, AdtDef::is_manually_drop)
13301330
}
1331+
1332+
/// Returns the deref chain of a type, starting with the type itself.
1333+
pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iterator<Item = Ty<'tcx>> + 'cx {
1334+
iter::successors(Some(ty), |&ty| {
1335+
if let Some(deref_did) = cx.tcx.lang_items().deref_trait()
1336+
&& implements_trait(cx, ty, deref_did, &[])
1337+
{
1338+
make_normalized_projection(cx.tcx, cx.param_env, deref_did, sym::Target, [ty])
1339+
} else {
1340+
None
1341+
}
1342+
})
1343+
}
1344+
1345+
/// Checks if a Ty<'_> has some inherent method Symbol.
1346+
/// This does not look for impls in the type's Deref::Target type.
1347+
/// If you need this, you should wrap this call in clippy_utils::ty::deref_chain().any(...).
1348+
pub fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool {
1349+
if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) {
1350+
cx.tcx.inherent_impls(ty_did).into_iter().flatten().any(|&did| {
1351+
cx.tcx
1352+
.associated_items(did)
1353+
.filter_by_name_unhygienic(method_name)
1354+
.next()
1355+
.is_some_and(|item| item.kind == ty::AssocKind::Fn)
1356+
})
1357+
} else {
1358+
false
1359+
}
1360+
}

tests/ui/indexing_slicing_slice.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,21 @@
33
// we want to avoid false positives.
44
#![warn(clippy::out_of_bounds_indexing)]
55
#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::useless_vec)]
6+
#![warn(clippy::indexing_slicing)]
7+
8+
use std::ops::Index;
9+
10+
struct BoolMap<T> {
11+
false_value: T,
12+
true_value: T,
13+
}
14+
15+
impl<T> Index<bool> for BoolMap<T> {
16+
type Output = T;
17+
fn index(&self, index: bool) -> &T {
18+
if index { &self.true_value } else { &self.false_value }
19+
}
20+
}
621

722
fn main() {
823
let x = [1, 2, 3, 4];
@@ -51,4 +66,11 @@ fn main() {
5166
//~^ ERROR: slicing may panic
5267

5368
&v[..]; // Ok, should not produce stderr.
69+
70+
let map = BoolMap {
71+
false_value: 2,
72+
true_value: 4,
73+
};
74+
75+
map[true]; // Ok, because `get` does not exist (custom indexing)
5476
}

tests/ui/indexing_slicing_slice.stderr

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: slicing may panic
2-
--> tests/ui/indexing_slicing_slice.rs:12:6
2+
--> tests/ui/indexing_slicing_slice.rs:27:6
33
|
44
LL | &x[index..];
55
| ^^^^^^^^^^
@@ -9,47 +9,47 @@ LL | &x[index..];
99
= help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]`
1010

1111
error: slicing may panic
12-
--> tests/ui/indexing_slicing_slice.rs:14:6
12+
--> tests/ui/indexing_slicing_slice.rs:29:6
1313
|
1414
LL | &x[..index];
1515
| ^^^^^^^^^^
1616
|
1717
= help: consider using `.get(..n)`or `.get_mut(..n)` instead
1818

1919
error: slicing may panic
20-
--> tests/ui/indexing_slicing_slice.rs:16:6
20+
--> tests/ui/indexing_slicing_slice.rs:31:6
2121
|
2222
LL | &x[index_from..index_to];
2323
| ^^^^^^^^^^^^^^^^^^^^^^^
2424
|
2525
= help: consider using `.get(n..m)` or `.get_mut(n..m)` instead
2626

2727
error: slicing may panic
28-
--> tests/ui/indexing_slicing_slice.rs:18:6
28+
--> tests/ui/indexing_slicing_slice.rs:33:6
2929
|
3030
LL | &x[index_from..][..index_to];
3131
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
3232
|
3333
= help: consider using `.get(..n)`or `.get_mut(..n)` instead
3434

3535
error: slicing may panic
36-
--> tests/ui/indexing_slicing_slice.rs:18:6
36+
--> tests/ui/indexing_slicing_slice.rs:33:6
3737
|
3838
LL | &x[index_from..][..index_to];
3939
| ^^^^^^^^^^^^^^^
4040
|
4141
= help: consider using `.get(n..)` or .get_mut(n..)` instead
4242

4343
error: slicing may panic
44-
--> tests/ui/indexing_slicing_slice.rs:21:6
44+
--> tests/ui/indexing_slicing_slice.rs:36:6
4545
|
4646
LL | &x[5..][..10];
4747
| ^^^^^^^^^^^^
4848
|
4949
= help: consider using `.get(..n)`or `.get_mut(..n)` instead
5050

5151
error: range is out of bounds
52-
--> tests/ui/indexing_slicing_slice.rs:21:8
52+
--> tests/ui/indexing_slicing_slice.rs:36:8
5353
|
5454
LL | &x[5..][..10];
5555
| ^
@@ -58,65 +58,65 @@ LL | &x[5..][..10];
5858
= help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]`
5959

6060
error: slicing may panic
61-
--> tests/ui/indexing_slicing_slice.rs:25:6
61+
--> tests/ui/indexing_slicing_slice.rs:40:6
6262
|
6363
LL | &x[0..][..3];
6464
| ^^^^^^^^^^^
6565
|
6666
= help: consider using `.get(..n)`or `.get_mut(..n)` instead
6767

6868
error: slicing may panic
69-
--> tests/ui/indexing_slicing_slice.rs:27:6
69+
--> tests/ui/indexing_slicing_slice.rs:42:6
7070
|
7171
LL | &x[1..][..5];
7272
| ^^^^^^^^^^^
7373
|
7474
= help: consider using `.get(..n)`or `.get_mut(..n)` instead
7575

7676
error: range is out of bounds
77-
--> tests/ui/indexing_slicing_slice.rs:35:12
77+
--> tests/ui/indexing_slicing_slice.rs:50:12
7878
|
7979
LL | &y[0..=4];
8080
| ^
8181

8282
error: range is out of bounds
83-
--> tests/ui/indexing_slicing_slice.rs:37:11
83+
--> tests/ui/indexing_slicing_slice.rs:52:11
8484
|
8585
LL | &y[..=4];
8686
| ^
8787

8888
error: slicing may panic
89-
--> tests/ui/indexing_slicing_slice.rs:43:6
89+
--> tests/ui/indexing_slicing_slice.rs:58:6
9090
|
9191
LL | &v[10..100];
9292
| ^^^^^^^^^^
9393
|
9494
= help: consider using `.get(n..m)` or `.get_mut(n..m)` instead
9595

9696
error: slicing may panic
97-
--> tests/ui/indexing_slicing_slice.rs:45:6
97+
--> tests/ui/indexing_slicing_slice.rs:60:6
9898
|
9999
LL | &x[10..][..100];
100100
| ^^^^^^^^^^^^^^
101101
|
102102
= help: consider using `.get(..n)`or `.get_mut(..n)` instead
103103

104104
error: range is out of bounds
105-
--> tests/ui/indexing_slicing_slice.rs:45:8
105+
--> tests/ui/indexing_slicing_slice.rs:60:8
106106
|
107107
LL | &x[10..][..100];
108108
| ^^
109109

110110
error: slicing may panic
111-
--> tests/ui/indexing_slicing_slice.rs:48:6
111+
--> tests/ui/indexing_slicing_slice.rs:63:6
112112
|
113113
LL | &v[10..];
114114
| ^^^^^^^
115115
|
116116
= help: consider using `.get(n..)` or .get_mut(n..)` instead
117117

118118
error: slicing may panic
119-
--> tests/ui/indexing_slicing_slice.rs:50:6
119+
--> tests/ui/indexing_slicing_slice.rs:65:6
120120
|
121121
LL | &v[..100];
122122
| ^^^^^^^^

0 commit comments

Comments
 (0)