Skip to content

Commit 9c7739c

Browse files
committed
changelog: Add manual_as_slice lint
1 parent 40bead0 commit 9c7739c

File tree

7 files changed

+239
-0
lines changed

7 files changed

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

tests/ui/manual_as_slice.fixed

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#![warn(clippy::manual_as_slice)]
2+
3+
mod nested_1 {
4+
pub(crate) mod nested_2 {
5+
pub(crate) const SOME_VALUE: [u8; 4] = [1, 2, 3, 4];
6+
}
7+
}
8+
9+
fn main() {
10+
let array: [u8; 4] = [0; 4];
11+
let slice: &[u8] = array.as_slice();
12+
//~^ manual_as_slice
13+
14+
let mut array: [u8; 4] = [0; 4];
15+
let mut slice: &[u8] = array.as_mut_slice();
16+
//~^ manual_as_slice
17+
18+
let slice: &[u8] = nested_1::nested_2::SOME_VALUE.as_slice();
19+
//~^ manual_as_slice
20+
21+
let slice = b"foo";
22+
let slice: &[u8] = slice.as_slice();
23+
//~^ manual_as_slice
24+
25+
let slice = &[1, 2, 3, 4];
26+
let slice: &[u8] = slice.as_slice();
27+
//~^ manual_as_slice
28+
29+
macro_rules! perform_the_slice {
30+
($a:expr) => {
31+
$a.as_slice()
32+
//~^ manual_as_slice
33+
};
34+
}
35+
36+
perform_the_slice!([1, 2, 3]);
37+
38+
let slice: &[u8] = vec![1, 2, 3].as_slice();
39+
//~^ manual_as_slice
40+
}

tests/ui/manual_as_slice.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#![warn(clippy::manual_as_slice)]
2+
3+
mod nested_1 {
4+
pub(crate) mod nested_2 {
5+
pub(crate) const SOME_VALUE: [u8; 4] = [1, 2, 3, 4];
6+
}
7+
}
8+
9+
fn main() {
10+
let array: [u8; 4] = [0; 4];
11+
let slice: &[u8] = &array[..];
12+
//~^ manual_as_slice
13+
14+
let mut array: [u8; 4] = [0; 4];
15+
let mut slice: &[u8] = &mut array[..];
16+
//~^ manual_as_slice
17+
18+
let slice: &[u8] = &nested_1::nested_2::SOME_VALUE[..];
19+
//~^ manual_as_slice
20+
21+
let slice = b"foo";
22+
let slice: &[u8] = &slice[..];
23+
//~^ manual_as_slice
24+
25+
let slice = &[1, 2, 3, 4];
26+
let slice: &[u8] = &slice[..];
27+
//~^ manual_as_slice
28+
29+
macro_rules! perform_the_slice {
30+
($a:expr) => {
31+
&$a[..]
32+
//~^ manual_as_slice
33+
};
34+
}
35+
36+
perform_the_slice!([1, 2, 3]);
37+
38+
let slice: &[u8] = &vec![1, 2, 3][..];
39+
//~^ manual_as_slice
40+
}

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:11: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:15: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:18: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:22: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:26: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:31: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:38: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)