chore: use multipart_suggestions for str_splitn

This commit is contained in:
Scott Gerring 2024-12-06 16:04:21 +01:00
parent f83a227d39
commit dcc4025405
4 changed files with 196 additions and 80 deletions

View file

@ -129,7 +129,7 @@ fn check_manual_split_once_indirect(
let ctxt = expr.span.ctxt();
let mut parents = cx.tcx.hir().parent_iter(expr.hir_id);
if let (_, Node::LetStmt(local)) = parents.next()?
&& let PatKind::Binding(BindingMode::MUT, iter_binding_id, iter_ident, None) = local.pat.kind
&& let PatKind::Binding(BindingMode::MUT, iter_binding_id, _, None) = local.pat.kind
&& let (iter_stmt_id, Node::Stmt(_)) = parents.next()?
&& let (_, Node::Block(enclosing_block)) = parents.next()?
&& let mut stmts = enclosing_block
@ -162,16 +162,20 @@ fn check_manual_split_once_indirect(
UnwrapKind::Unwrap => ".unwrap()",
UnwrapKind::QuestionMark => "?",
};
diag.span_suggestion_verbose(
local.span,
format!("try `{r}split_once`"),
format!("let ({lhs}, {rhs}) = {self_snip}.{r}split_once({pat_snip}){unwrap};"),
// Add a multipart suggestion
diag.multipart_suggestion(
format!("replace with `{r}split_once`"),
vec![
(
local.span,
format!("let ({lhs}, {rhs}) = {self_snip}.{r}split_once({pat_snip}){unwrap};"),
),
(first.span, String::new()), // Remove the first usage
(second.span, String::new()), // Remove the second usage
],
app,
);
let remove_msg = format!("remove the `{iter_ident}` usages");
diag.span_suggestion(first.span, remove_msg.clone(), "", app);
diag.span_suggestion(second.span, remove_msg, "", app);
});
}

View file

@ -0,0 +1,144 @@
#![warn(clippy::manual_split_once)]
#![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)]
extern crate itertools;
#[allow(unused_imports)]
use itertools::Itertools;
fn main() {
let _ = "key=value".splitn(2, '=').nth(2);
let _ = "key=value".split_once('=').unwrap().1;
let _ = "key=value".split_once('=').unwrap().1;
let (_, _) = "key=value".split_once('=').unwrap();
let s = String::from("key=value");
let _ = s.split_once('=').unwrap().1;
let s = Box::<str>::from("key=value");
let _ = s.split_once('=').unwrap().1;
let s = &"key=value";
let _ = s.split_once('=').unwrap().1;
fn _f(s: &str) -> Option<&str> {
let _ = s.split_once('=')?.1;
let _ = s.split_once('=')?.1;
let _ = s.rsplit_once('=')?.0;
let _ = s.rsplit_once('=')?.0;
None
}
// Don't lint, slices don't have `split_once`
let _ = [0, 1, 2].splitn(2, |&x| x == 1).nth(1).unwrap();
// `rsplitn` gives the results in the reverse order of `rsplit_once`
let _ = "key=value".rsplit_once('=').unwrap().0;
let (_, _) = "key=value".rsplit_once('=').map(|(x, y)| (y, x)).unwrap();
let _ = s.rsplit_once('=').map(|x| x.0);
}
fn indirect() -> Option<()> {
let (l, r) = "a.b.c".split_once('.').unwrap();
let (l, r) = "a.b.c".split_once('.')?;
let (l, r) = "a.b.c".rsplit_once('.').unwrap();
let (l, r) = "a.b.c".rsplit_once('.')?;
// could lint, currently doesn't
let mut iter = "a.b.c".splitn(2, '.');
let other = 1;
let l = iter.next()?;
let r = iter.next()?;
let mut iter = "a.b.c".splitn(2, '.');
let mut mut_binding = iter.next()?;
let r = iter.next()?;
let mut iter = "a.b.c".splitn(2, '.');
let tuple = (iter.next()?, iter.next()?);
// should not lint
let mut missing_unwrap = "a.b.c".splitn(2, '.');
let l = missing_unwrap.next();
let r = missing_unwrap.next();
let mut mixed_unrap = "a.b.c".splitn(2, '.');
let unwrap = mixed_unrap.next().unwrap();
let question_mark = mixed_unrap.next()?;
let mut iter = "a.b.c".splitn(2, '.');
let same_name = iter.next()?;
let same_name = iter.next()?;
let mut iter = "a.b.c".splitn(2, '.');
let shadows_existing = "d";
let shadows_existing = iter.next()?;
let r = iter.next()?;
let mut iter = "a.b.c".splitn(2, '.');
let becomes_shadowed = iter.next()?;
let becomes_shadowed = "d";
let r = iter.next()?;
let mut iter = "a.b.c".splitn(2, '.');
let l = iter.next()?;
let r = iter.next()?;
let third_usage = iter.next()?;
let mut n_three = "a.b.c".splitn(3, '.');
let l = n_three.next()?;
let r = n_three.next()?;
let mut iter = "a.b.c".splitn(2, '.');
{
let in_block = iter.next()?;
}
let r = iter.next()?;
let mut lacks_binding = "a.b.c".splitn(2, '.');
let _ = lacks_binding.next()?;
let r = lacks_binding.next()?;
let mut mapped = "a.b.c".splitn(2, '.').map(|_| "~");
let l = iter.next()?;
let r = iter.next()?;
let mut assigned = "";
let mut iter = "a.b.c".splitn(2, '.');
let l = iter.next()?;
assigned = iter.next()?;
None
}
#[clippy::msrv = "1.51"]
fn _msrv_1_51() {
// `str::split_once` was stabilized in 1.52. Do not lint this
let _ = "key=value".splitn(2, '=').nth(1).unwrap();
let mut iter = "a.b.c".splitn(2, '.');
let a = iter.next().unwrap();
let b = iter.next().unwrap();
}
#[clippy::msrv = "1.52"]
fn _msrv_1_52() {
let _ = "key=value".split_once('=').unwrap().1;
let (a, b) = "a.b.c".split_once('.').unwrap();
}

View file

@ -1,8 +1,6 @@
#![warn(clippy::manual_split_once)]
#![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)]
//@no-rustfix: need to change the suggestion to a multipart suggestion
extern crate itertools;
#[allow(unused_imports)]

View file

@ -1,5 +1,5 @@
error: manual implementation of `split_once`
--> tests/ui/manual_split_once.rs:13:13
--> tests/ui/manual_split_once.rs:11:13
|
LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1`
@ -8,79 +8,79 @@ LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap();
= help: to override `-D warnings` add `#[allow(clippy::manual_split_once)]`
error: manual implementation of `split_once`
--> tests/ui/manual_split_once.rs:14:13
--> tests/ui/manual_split_once.rs:12:13
|
LL | let _ = "key=value".splitn(2, '=').skip(1).next().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1`
error: manual implementation of `split_once`
--> tests/ui/manual_split_once.rs:15:18
--> tests/ui/manual_split_once.rs:13:18
|
LL | let (_, _) = "key=value".splitn(2, '=').next_tuple().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=')`
error: manual implementation of `split_once`
--> tests/ui/manual_split_once.rs:18:13
--> tests/ui/manual_split_once.rs:16:13
|
LL | let _ = s.splitn(2, '=').nth(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1`
error: manual implementation of `split_once`
--> tests/ui/manual_split_once.rs:21:13
--> tests/ui/manual_split_once.rs:19:13
|
LL | let _ = s.splitn(2, '=').nth(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1`
error: manual implementation of `split_once`
--> tests/ui/manual_split_once.rs:24:13
--> tests/ui/manual_split_once.rs:22:13
|
LL | let _ = s.splitn(2, '=').skip(1).next().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1`
error: manual implementation of `split_once`
--> tests/ui/manual_split_once.rs:27:17
--> tests/ui/manual_split_once.rs:25:17
|
LL | let _ = s.splitn(2, '=').nth(1)?;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=')?.1`
error: manual implementation of `split_once`
--> tests/ui/manual_split_once.rs:28:17
--> tests/ui/manual_split_once.rs:26:17
|
LL | let _ = s.splitn(2, '=').skip(1).next()?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=')?.1`
error: manual implementation of `rsplit_once`
--> tests/ui/manual_split_once.rs:29:17
--> tests/ui/manual_split_once.rs:27:17
|
LL | let _ = s.rsplitn(2, '=').nth(1)?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=')?.0`
error: manual implementation of `rsplit_once`
--> tests/ui/manual_split_once.rs:30:17
--> tests/ui/manual_split_once.rs:28:17
|
LL | let _ = s.rsplitn(2, '=').skip(1).next()?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=')?.0`
error: manual implementation of `rsplit_once`
--> tests/ui/manual_split_once.rs:38:13
--> tests/ui/manual_split_once.rs:36:13
|
LL | let _ = "key=value".rsplitn(2, '=').nth(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".rsplit_once('=').unwrap().0`
error: manual implementation of `rsplit_once`
--> tests/ui/manual_split_once.rs:39:18
--> tests/ui/manual_split_once.rs:37:18
|
LL | let (_, _) = "key=value".rsplitn(2, '=').next_tuple().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".rsplit_once('=').map(|(x, y)| (y, x))`
error: manual implementation of `rsplit_once`
--> tests/ui/manual_split_once.rs:40:13
--> tests/ui/manual_split_once.rs:38:13
|
LL | let _ = s.rsplitn(2, '=').nth(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=').map(|x| x.0)`
error: manual implementation of `split_once`
--> tests/ui/manual_split_once.rs:44:5
--> tests/ui/manual_split_once.rs:42:5
|
LL | let mut iter = "a.b.c".splitn(2, '.');
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -89,21 +89,15 @@ LL | let l = iter.next().unwrap();
LL | let r = iter.next().unwrap();
| ----------------------------- second usage here
|
help: try `split_once`
help: replace with `split_once`
|
LL | let (l, r) = "a.b.c".split_once('.').unwrap();
|
help: remove the `iter` usages
|
LL - let l = iter.next().unwrap();
|
help: remove the `iter` usages
|
LL - let r = iter.next().unwrap();
LL ~ let (l, r) = "a.b.c".split_once('.').unwrap();
LL ~
LL ~
|
error: manual implementation of `split_once`
--> tests/ui/manual_split_once.rs:48:5
--> tests/ui/manual_split_once.rs:46:5
|
LL | let mut iter = "a.b.c".splitn(2, '.');
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -112,21 +106,15 @@ LL | let l = iter.next()?;
LL | let r = iter.next()?;
| --------------------- second usage here
|
help: try `split_once`
help: replace with `split_once`
|
LL | let (l, r) = "a.b.c".split_once('.')?;
|
help: remove the `iter` usages
|
LL - let l = iter.next()?;
|
help: remove the `iter` usages
|
LL - let r = iter.next()?;
LL ~ let (l, r) = "a.b.c".split_once('.')?;
LL ~
LL ~
|
error: manual implementation of `rsplit_once`
--> tests/ui/manual_split_once.rs:52:5
--> tests/ui/manual_split_once.rs:50:5
|
LL | let mut iter = "a.b.c".rsplitn(2, '.');
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -135,21 +123,15 @@ LL | let r = iter.next().unwrap();
LL | let l = iter.next().unwrap();
| ----------------------------- second usage here
|
help: try `rsplit_once`
help: replace with `rsplit_once`
|
LL | let (l, r) = "a.b.c".rsplit_once('.').unwrap();
|
help: remove the `iter` usages
|
LL - let r = iter.next().unwrap();
|
help: remove the `iter` usages
|
LL - let l = iter.next().unwrap();
LL ~ let (l, r) = "a.b.c".rsplit_once('.').unwrap();
LL ~
LL ~
|
error: manual implementation of `rsplit_once`
--> tests/ui/manual_split_once.rs:56:5
--> tests/ui/manual_split_once.rs:54:5
|
LL | let mut iter = "a.b.c".rsplitn(2, '.');
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -158,27 +140,21 @@ LL | let r = iter.next()?;
LL | let l = iter.next()?;
| --------------------- second usage here
|
help: try `rsplit_once`
help: replace with `rsplit_once`
|
LL | let (l, r) = "a.b.c".rsplit_once('.')?;
|
help: remove the `iter` usages
|
LL - let r = iter.next()?;
|
help: remove the `iter` usages
|
LL - let l = iter.next()?;
LL ~ let (l, r) = "a.b.c".rsplit_once('.')?;
LL ~
LL ~
|
error: manual implementation of `split_once`
--> tests/ui/manual_split_once.rs:141:13
--> tests/ui/manual_split_once.rs:139:13
|
LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1`
error: manual implementation of `split_once`
--> tests/ui/manual_split_once.rs:143:5
--> tests/ui/manual_split_once.rs:141:5
|
LL | let mut iter = "a.b.c".splitn(2, '.');
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -187,17 +163,11 @@ LL | let a = iter.next().unwrap();
LL | let b = iter.next().unwrap();
| ----------------------------- second usage here
|
help: try `split_once`
help: replace with `split_once`
|
LL | let (a, b) = "a.b.c".split_once('.').unwrap();
|
help: remove the `iter` usages
|
LL - let a = iter.next().unwrap();
|
help: remove the `iter` usages
|
LL - let b = iter.next().unwrap();
LL ~ let (a, b) = "a.b.c".split_once('.').unwrap();
LL ~
LL ~
|
error: aborting due to 19 previous errors