Skip to content

Commit dc4e07b

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

File tree

7 files changed

+185
-0
lines changed

7 files changed

+185
-0
lines changed

CHANGELOG.md

+1
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

+1
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

+2
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

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::source::snippet_with_applicability;
3+
use rustc_errors::Applicability;
4+
use rustc_hir::{Expr, ExprKind, LangItem, Mutability, QPath};
5+
use rustc_lint::{LateContext, LateLintPass};
6+
use rustc_session::declare_lint_pass;
7+
8+
declare_clippy_lint! {
9+
/// ### What it does
10+
///
11+
/// Detects if a full range slice reference is used instead of using the `.as_slice()` method.
12+
///
13+
/// ### Why is this bad?
14+
///
15+
/// Using the `some_value.as_slice()` method is more explicit then using `&some_value[..]`
16+
///
17+
/// ### Example
18+
/// ```no_run
19+
/// let array: [u8; 4] = [0; 4];
20+
/// let slice = &array[..];
21+
/// ```
22+
/// Use instead:
23+
/// ```no_run
24+
/// let array: [u8; 4] = [0; 4];
25+
/// let slice = array.as_slice();
26+
/// ```
27+
#[clippy::version = "1.88.0"]
28+
pub MANUAL_AS_SLICE,
29+
nursery,
30+
"Use as slice instead of borrow full range."
31+
}
32+
declare_lint_pass!(ManualAsSlice => [MANUAL_AS_SLICE]);
33+
34+
impl LateLintPass<'_> for ManualAsSlice {
35+
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
36+
if let ExprKind::AddrOf(_, mutability, borrow) = expr.kind
37+
&& let ExprKind::Index(name, indexing, _) = borrow.kind
38+
&& !name.span.from_expansion()
39+
&& let ExprKind::Struct(qpath, _, _) = indexing.kind
40+
&& let QPath::LangItem(LangItem::RangeFull, _) = qpath
41+
{
42+
let mut app = Applicability::MachineApplicable;
43+
let snippet = snippet_with_applicability(cx, name.span, "..", &mut app);
44+
45+
let (msg, sugg) = match mutability {
46+
Mutability::Not => (
47+
"use `.as_slice()` instead of full range slice",
48+
format!("{snippet}.as_slice()"),
49+
),
50+
Mutability::Mut => (
51+
"use `.as_mut_slice()` instead of full range slice",
52+
format!("{snippet}.as_mut_slice()"),
53+
),
54+
};
55+
56+
span_lint_and_sugg(cx, MANUAL_AS_SLICE, expr.span, msg, "try", sugg, app);
57+
}
58+
}
59+
}

tests/ui/manual_as_slice.fixed

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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+
let slice: &[u8] = &vec![1, 2, 3][..];
30+
31+
macro_rules! perform_the_slice {
32+
($a:expr) => {
33+
[1, 2, 3].as_slice()
34+
//~^ manual_as_slice
35+
};
36+
}
37+
38+
perform_the_slice!([1, 2, 3]);
39+
}

tests/ui/manual_as_slice.rs

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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+
}

tests/ui/manual_as_slice.stderr

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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+
| ^^^^^^^^^^ help: try: `array.as_slice()`
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+
10+
error: use `.as_mut_slice()` instead of full range slice
11+
--> tests/ui/manual_as_slice.rs:15:28
12+
|
13+
LL | let mut slice: &[u8] = &mut array[..];
14+
| ^^^^^^^^^^^^^^ help: try: `array.as_mut_slice()`
15+
16+
error: use `.as_slice()` instead of full range slice
17+
--> tests/ui/manual_as_slice.rs:18:24
18+
|
19+
LL | let slice: &[u8] = &nested_1::nested_2::SOME_VALUE[..];
20+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `nested_1::nested_2::SOME_VALUE.as_slice()`
21+
22+
error: use `.as_slice()` instead of full range slice
23+
--> tests/ui/manual_as_slice.rs:22:24
24+
|
25+
LL | let slice: &[u8] = &slice[..];
26+
| ^^^^^^^^^^ help: try: `slice.as_slice()`
27+
28+
error: use `.as_slice()` instead of full range slice
29+
--> tests/ui/manual_as_slice.rs:26:24
30+
|
31+
LL | let slice: &[u8] = &slice[..];
32+
| ^^^^^^^^^^ help: try: `slice.as_slice()`
33+
34+
error: use `.as_slice()` instead of full range slice
35+
--> tests/ui/manual_as_slice.rs:33:13
36+
|
37+
LL | &$a[..]
38+
| ^^^^^^^ help: try: `[1, 2, 3].as_slice()`
39+
...
40+
LL | perform_the_slice!([1, 2, 3]);
41+
| ----------------------------- in this macro invocation
42+
|
43+
= note: this error originates in the macro `perform_the_slice` (in Nightly builds, run with -Z macro-backtrace for more info)
44+
45+
error: aborting due to 6 previous errors
46+

0 commit comments

Comments
 (0)