Skip to content

Commit e0f2d88

Browse files
committed
add unnecessary_split_off lint
Signed-off-by: André Vennberg <[email protected]>
1 parent 40bead0 commit e0f2d88

File tree

6 files changed

+109
-0
lines changed

6 files changed

+109
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6399,6 +6399,7 @@ Released 2018-09-13
63996399
[`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports
64006400
[`unnecessary_semicolon`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_semicolon
64016401
[`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
6402+
[`unnecessary_split_off`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_split_off
64026403
[`unnecessary_struct_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_struct_initialization
64036404
[`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned
64046405
[`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
746746
crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO,
747747
crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO,
748748
crate::unnecessary_semicolon::UNNECESSARY_SEMICOLON_INFO,
749+
crate::unnecessary_split_off::UNNECESSARY_SPLIT_OFF_INFO,
749750
crate::unnecessary_struct_initialization::UNNECESSARY_STRUCT_INITIALIZATION_INFO,
750751
crate::unnecessary_wraps::UNNECESSARY_WRAPS_INFO,
751752
crate::unneeded_struct_pattern::UNNEEDED_STRUCT_PATTERN_INFO,

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ mod unnecessary_map_on_constructor;
376376
mod unnecessary_owned_empty_strings;
377377
mod unnecessary_self_imports;
378378
mod unnecessary_semicolon;
379+
mod unnecessary_split_off;
379380
mod unnecessary_struct_initialization;
380381
mod unnecessary_wraps;
381382
mod unneeded_struct_pattern;
@@ -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(unnecessary_split_off::UnnecessarySplitOff));
947949
// add lints here, do not remove this comment, it's used in `new_lint`
948950
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::sym;
3+
use rustc_errors::Applicability;
4+
use rustc_hir::*;
5+
use rustc_lint::{LateContext, LateLintPass};
6+
use rustc_session::declare_lint_pass;
7+
8+
declare_clippy_lint! {
9+
/// ### What it does
10+
/// Suggests using `drain(..).collect()` when a `split_off(0)` is being called on a `vec`.
11+
/// ### Why is this bad?
12+
/// Because splitting implies dividing the vec into two parts, so the modified vector being emptied could be unexpected.
13+
/// ### Example
14+
/// ```no_run
15+
/// let mut vec = vec![1, 2, 3];
16+
/// let vec1 = vec.split_off(0);
17+
/// ```
18+
/// Use instead:
19+
/// ```no_run
20+
/// let mut vec = vec![1, 2, 3];
21+
/// let vec1 = vec.drain(..).collect();
22+
/// ```
23+
#[clippy::version = "1.88.0"]
24+
pub UNNECESSARY_SPLIT_OFF,
25+
style,
26+
"unnecessary `split_off(0)`"
27+
}
28+
declare_lint_pass!(UnnecessarySplitOff => [UNNECESSARY_SPLIT_OFF]);
29+
30+
impl<'tcx> LateLintPass<'tcx> for UnnecessarySplitOff {
31+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
32+
if let ExprKind::MethodCall(path, value, args, span) = &expr.kind
33+
&& path.ident.name.as_str() == "split_off"
34+
{
35+
let ty = cx.typeck_results().expr_ty(value);
36+
if clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Vec) {
37+
let &[arg] = args else {
38+
return;
39+
};
40+
if clippy_utils::is_integer_literal(&arg, 0) || clippy_utils::is_integer_const(cx, &arg, 0) {
41+
span_lint_and_sugg(
42+
cx,
43+
UNNECESSARY_SPLIT_OFF,
44+
*span,
45+
"unnecessary `split_off(0)`",
46+
"use",
47+
"drain(..).collect()".to_string(),
48+
Applicability::MachineApplicable,
49+
);
50+
}
51+
}
52+
}
53+
}
54+
}

tests/ui/unnecessary_split_off.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//@no-rustfix
2+
#![warn(clippy::unnecessary_split_off)]
3+
#![allow(unused)]
4+
5+
struct A;
6+
impl A {
7+
fn split_off(&mut self, _: usize) {}
8+
}
9+
10+
const ZERO: usize = 0;
11+
12+
fn main() {
13+
let mut vec1 = vec![1, 2, 3];
14+
15+
let vec2: Vec<_> = vec1.split_off(0);
16+
//~^ unnecessary_split_off
17+
18+
let vec3: Vec<_> = vec1.split_off(1);
19+
20+
let vec4: Vec<_> = vec1.split_off(ZERO);
21+
//~^ unnecessary_split_off
22+
23+
let vec5: Vec<_> = vec1.split_off(const { 0 });
24+
//~^ unnecessary_split_off
25+
26+
let mut a = A;
27+
a.split_off(0);
28+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error: unnecessary `split_off(0)`
2+
--> tests/ui/unnecessary_split_off.rs:15:29
3+
|
4+
LL | let vec2: Vec<_> = vec1.split_off(0);
5+
| ^^^^^^^^^^^^ help: use: `drain(..).collect()`
6+
|
7+
= note: `-D clippy::unnecessary-split-off` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_split_off)]`
9+
10+
error: unnecessary `split_off(0)`
11+
--> tests/ui/unnecessary_split_off.rs:20:29
12+
|
13+
LL | let vec4: Vec<_> = vec1.split_off(ZERO);
14+
| ^^^^^^^^^^^^^^^ help: use: `drain(..).collect()`
15+
16+
error: unnecessary `split_off(0)`
17+
--> tests/ui/unnecessary_split_off.rs:23:29
18+
|
19+
LL | let vec5: Vec<_> = vec1.split_off(const { 0 });
20+
| ^^^^^^^^^^^^^^^^^^^^^^ help: use: `drain(..).collect()`
21+
22+
error: aborting due to 3 previous errors
23+

0 commit comments

Comments
 (0)