Skip to content

Commit 3e1cf27

Browse files
committed
changelog: Add manual_as_slice lint
1 parent 40bead0 commit 3e1cf27

File tree

7 files changed

+280
-0
lines changed

7 files changed

+280
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5943,6 +5943,7 @@ Released 2018-09-13
59435943
[`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports
59445944
[`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
59455945
[`manual_abs_diff`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_abs_diff
5946+
[`manual_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_as_slice
59465947
[`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert
59475948
[`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
59485949
[`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
288288
crate::macro_use::MACRO_USE_IMPORTS_INFO,
289289
crate::main_recursion::MAIN_RECURSION_INFO,
290290
crate::manual_abs_diff::MANUAL_ABS_DIFF_INFO,
291+
crate::manual_as_slice::MANUAL_AS_SLICE_INFO,
291292
crate::manual_assert::MANUAL_ASSERT_INFO,
292293
crate::manual_async_fn::MANUAL_ASYNC_FN_INFO,
293294
crate::manual_bits::MANUAL_BITS_INFO,

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ mod macro_metavars_in_unsafe;
204204
mod macro_use;
205205
mod main_recursion;
206206
mod manual_abs_diff;
207+
mod manual_as_slice;
207208
mod manual_assert;
208209
mod manual_async_fn;
209210
mod manual_bits;
@@ -944,5 +945,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
944945
store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap));
945946
store.register_late_pass(move |_| Box::new(redundant_test_prefix::RedundantTestPrefix));
946947
store.register_late_pass(|_| Box::new(cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf)));
948+
store.register_late_pass(|_| Box::new(manual_as_slice::ManualAsSlice));
947949
// add lints here, do not remove this comment, it's used in `new_lint`
948950
}

clippy_lints/src/manual_as_slice.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use clippy_utils::diagnostics::span_lint_and_then;
2+
use rustc_errors::Applicability;
3+
use rustc_hir::{Expr, ExprKind, LangItem, Mutability, QPath};
4+
use rustc_lint::{LateContext, LateLintPass};
5+
use rustc_middle::ty::TyKind;
6+
use rustc_session::declare_lint_pass;
7+
use rustc_span::symbol::sym;
8+
9+
declare_clippy_lint! {
10+
/// ### What it does
11+
///
12+
/// Detects if a full range slice reference is used instead of using the `.as_slice()` method.
13+
///
14+
/// ### Why is this bad?
15+
///
16+
/// Using the `some_value.as_slice()` method is more explicit then using `&some_value[..]`
17+
///
18+
/// ### Example
19+
/// ```no_run
20+
/// let array: [u8; 4] = [0; 4];
21+
/// let slice = &array[..];
22+
/// ```
23+
/// Use instead:
24+
/// ```no_run
25+
/// let array: [u8; 4] = [0; 4];
26+
/// let slice = array.as_slice();
27+
/// ```
28+
#[clippy::version = "1.88.0"]
29+
pub MANUAL_AS_SLICE,
30+
nursery,
31+
"Use as slice instead of borrow full range."
32+
}
33+
declare_lint_pass!(ManualAsSlice => [MANUAL_AS_SLICE]);
34+
35+
impl LateLintPass<'_> for ManualAsSlice {
36+
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
37+
if let ExprKind::AddrOf(_, mutability, borrow) = expr.kind
38+
&& let ExprKind::Index(value, index, index_span) = borrow.kind
39+
&& let ExprKind::Struct(qpath, _, _) = index.kind
40+
&& let QPath::LangItem(LangItem::RangeFull, _) = qpath
41+
{
42+
let sugg_tail = match mutability {
43+
Mutability::Not => ".as_slice()",
44+
Mutability::Mut => ".as_mut_slice()",
45+
};
46+
47+
let borrow_span = expr.span.until(borrow.span);
48+
let app = Applicability::MachineApplicable;
49+
50+
match cx.typeck_results().expr_ty(value).kind() {
51+
TyKind::Array(_, _) | TyKind::Slice(_) => {},
52+
TyKind::Ref(_, t, _) if let TyKind::Array(_, _) | TyKind::Slice(_) = t.kind() => {},
53+
TyKind::Adt(adt, _) if cx.tcx.is_diagnostic_item(sym::Vec, adt.did()) => {},
54+
_ => return,
55+
}
56+
57+
span_lint_and_then(
58+
cx,
59+
MANUAL_AS_SLICE,
60+
expr.span,
61+
format!("use `{sugg_tail}` instead of full range slice"),
62+
|diag| {
63+
diag.multipart_suggestion(
64+
"try",
65+
vec![(borrow_span, String::new()), (index_span, sugg_tail.to_string())],
66+
app,
67+
);
68+
},
69+
);
70+
}
71+
}
72+
}

tests/ui/manual_as_slice.fixed

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#![feature(new_range_api)]
2+
#![allow(clippy::redundant_slicing)]
3+
#![warn(clippy::manual_as_slice)]
4+
5+
mod nested_1 {
6+
pub(crate) mod nested_2 {
7+
pub(crate) const SOME_VALUE: [u8; 4] = [1, 2, 3, 4];
8+
}
9+
}
10+
11+
fn main() {
12+
let array: [u8; 4] = [0; 4];
13+
let slice: &[u8] = array.as_slice();
14+
//~^ manual_as_slice
15+
16+
let mut array: [u8; 4] = [0; 4];
17+
let mut slice: &[u8] = array.as_mut_slice();
18+
//~^ manual_as_slice
19+
20+
let slice: &[u8] = nested_1::nested_2::SOME_VALUE.as_slice();
21+
//~^ manual_as_slice
22+
23+
let slice = b"foo";
24+
let slice: &[u8] = slice.as_slice();
25+
//~^ manual_as_slice
26+
27+
let slice = &[1, 2, 3, 4];
28+
let slice: &[u8] = slice.as_slice();
29+
//~^ manual_as_slice
30+
31+
macro_rules! perform_the_slice {
32+
($a:expr) => {
33+
$a.as_slice()
34+
//~^ manual_as_slice
35+
};
36+
}
37+
38+
perform_the_slice!([1, 2, 3]);
39+
40+
let slice: &[u8] = vec![1, 2, 3].as_slice();
41+
//~^ manual_as_slice
42+
43+
let slice = &"foo"[..];
44+
45+
struct Count;
46+
47+
impl<R: std::range::RangeBounds<()>> std::ops::Index<R> for Count {
48+
type Output = ();
49+
50+
fn index(&self, _: R) -> &Self::Output {
51+
&()
52+
}
53+
}
54+
55+
let count = &Count[..];
56+
}

tests/ui/manual_as_slice.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#![feature(new_range_api)]
2+
#![allow(clippy::redundant_slicing)]
3+
#![warn(clippy::manual_as_slice)]
4+
5+
mod nested_1 {
6+
pub(crate) mod nested_2 {
7+
pub(crate) const SOME_VALUE: [u8; 4] = [1, 2, 3, 4];
8+
}
9+
}
10+
11+
fn main() {
12+
let array: [u8; 4] = [0; 4];
13+
let slice: &[u8] = &array[..];
14+
//~^ manual_as_slice
15+
16+
let mut array: [u8; 4] = [0; 4];
17+
let mut slice: &[u8] = &mut array[..];
18+
//~^ manual_as_slice
19+
20+
let slice: &[u8] = &nested_1::nested_2::SOME_VALUE[..];
21+
//~^ manual_as_slice
22+
23+
let slice = b"foo";
24+
let slice: &[u8] = &slice[..];
25+
//~^ manual_as_slice
26+
27+
let slice = &[1, 2, 3, 4];
28+
let slice: &[u8] = &slice[..];
29+
//~^ manual_as_slice
30+
31+
macro_rules! perform_the_slice {
32+
($a:expr) => {
33+
&$a[..]
34+
//~^ manual_as_slice
35+
};
36+
}
37+
38+
perform_the_slice!([1, 2, 3]);
39+
40+
let slice: &[u8] = &vec![1, 2, 3][..];
41+
//~^ manual_as_slice
42+
43+
let slice = &"foo"[..];
44+
45+
struct Count;
46+
47+
impl<R: std::range::RangeBounds<()>> std::ops::Index<R> for Count {
48+
type Output = ();
49+
50+
fn index(&self, _: R) -> &Self::Output {
51+
&()
52+
}
53+
}
54+
55+
let count = &Count[..];
56+
}

tests/ui/manual_as_slice.stderr

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
error: use `.as_slice()` instead of full range slice
2+
--> tests/ui/manual_as_slice.rs:13:24
3+
|
4+
LL | let slice: &[u8] = &array[..];
5+
| ^^^^^^^^^^
6+
|
7+
= note: `-D clippy::manual-as-slice` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::manual_as_slice)]`
9+
help: try
10+
|
11+
LL - let slice: &[u8] = &array[..];
12+
LL + let slice: &[u8] = array.as_slice();
13+
|
14+
15+
error: use `.as_mut_slice()` instead of full range slice
16+
--> tests/ui/manual_as_slice.rs:17:28
17+
|
18+
LL | let mut slice: &[u8] = &mut array[..];
19+
| ^^^^^^^^^^^^^^
20+
|
21+
help: try
22+
|
23+
LL - let mut slice: &[u8] = &mut array[..];
24+
LL + let mut slice: &[u8] = array.as_mut_slice();
25+
|
26+
27+
error: use `.as_slice()` instead of full range slice
28+
--> tests/ui/manual_as_slice.rs:20:24
29+
|
30+
LL | let slice: &[u8] = &nested_1::nested_2::SOME_VALUE[..];
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
32+
|
33+
help: try
34+
|
35+
LL - let slice: &[u8] = &nested_1::nested_2::SOME_VALUE[..];
36+
LL + let slice: &[u8] = nested_1::nested_2::SOME_VALUE.as_slice();
37+
|
38+
39+
error: use `.as_slice()` instead of full range slice
40+
--> tests/ui/manual_as_slice.rs:24:24
41+
|
42+
LL | let slice: &[u8] = &slice[..];
43+
| ^^^^^^^^^^
44+
|
45+
help: try
46+
|
47+
LL - let slice: &[u8] = &slice[..];
48+
LL + let slice: &[u8] = slice.as_slice();
49+
|
50+
51+
error: use `.as_slice()` instead of full range slice
52+
--> tests/ui/manual_as_slice.rs:28:24
53+
|
54+
LL | let slice: &[u8] = &slice[..];
55+
| ^^^^^^^^^^
56+
|
57+
help: try
58+
|
59+
LL - let slice: &[u8] = &slice[..];
60+
LL + let slice: &[u8] = slice.as_slice();
61+
|
62+
63+
error: use `.as_slice()` instead of full range slice
64+
--> tests/ui/manual_as_slice.rs:33:13
65+
|
66+
LL | &$a[..]
67+
| ^^^^^^^
68+
...
69+
LL | perform_the_slice!([1, 2, 3]);
70+
| ----------------------------- in this macro invocation
71+
|
72+
= note: this error originates in the macro `perform_the_slice` (in Nightly builds, run with -Z macro-backtrace for more info)
73+
help: try
74+
|
75+
LL - &$a[..]
76+
LL + $a.as_slice()
77+
|
78+
79+
error: use `.as_slice()` instead of full range slice
80+
--> tests/ui/manual_as_slice.rs:40:24
81+
|
82+
LL | let slice: &[u8] = &vec![1, 2, 3][..];
83+
| ^^^^^^^^^^^^^^^^^^
84+
|
85+
help: try
86+
|
87+
LL - let slice: &[u8] = &vec![1, 2, 3][..];
88+
LL + let slice: &[u8] = vec![1, 2, 3].as_slice();
89+
|
90+
91+
error: aborting due to 7 previous errors
92+

0 commit comments

Comments
 (0)