mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-14 17:48:10 +00:00
Auto merge of #8717 - Alexendoo:manual-split-once-manual-iter, r=dswij,xFrednet
`manual_split_once`: lint manual iteration of `SplitN` changelog: `manual_split_once`: lint manual iteration of `SplitN` Now lints: ```rust let mut iter = "a.b.c".splitn(2, '.'); let first = iter.next().unwrap(); let second = iter.next().unwrap(); let mut iter = "a.b.c".splitn(2, '.'); let first = iter.next()?; let second = iter.next()?; let mut iter = "a.b.c".rsplitn(2, '.'); let first = iter.next().unwrap(); let second = iter.next().unwrap(); let mut iter = "a.b.c".rsplitn(2, '.'); let first = iter.next()?; let second = iter.next()?; ``` It suggests (minus leftover whitespace): ```rust let (first, second) = "a.b.c".split_once('.').unwrap(); let (first, second) = "a.b.c".split_once('.')?; let (second, first) = "a.b.c".rsplit_once('.').unwrap(); let (second, first) = "a.b.c".rsplit_once('.')?; ``` Currently only lints if the statements are next to each other, as detecting the various kinds of shadowing was tricky, so the following won't lint ```rust let mut iter = "a.b.c".splitn(2, '.'); let something_else = 1; let first = iter.next()?; let second = iter.next()?; ```
This commit is contained in:
commit
ed22428b72
@ -2009,13 +2009,27 @@ declare_clippy_lint! {
|
|||||||
/// ### Example
|
/// ### Example
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
/// // Bad
|
/// // Bad
|
||||||
/// let (key, value) = _.splitn(2, '=').next_tuple()?;
|
/// let s = "key=value=add";
|
||||||
/// let value = _.splitn(2, '=').nth(1)?;
|
/// let (key, value) = s.splitn(2, '=').next_tuple()?;
|
||||||
|
/// let value = s.splitn(2, '=').nth(1)?;
|
||||||
///
|
///
|
||||||
/// // Good
|
/// let mut parts = s.splitn(2, '=');
|
||||||
/// let (key, value) = _.split_once('=')?;
|
/// let key = parts.next()?;
|
||||||
/// let value = _.split_once('=')?.1;
|
/// let value = parts.next()?;
|
||||||
/// ```
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// // Good
|
||||||
|
/// let s = "key=value=add";
|
||||||
|
/// let (key, value) = s.split_once('=')?;
|
||||||
|
/// let value = s.split_once('=')?.1;
|
||||||
|
///
|
||||||
|
/// let (key, value) = s.split_once('=')?;
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ### Limitations
|
||||||
|
/// The multiple statement variant currently only detects `iter.next()?`/`iter.next().unwrap()`
|
||||||
|
/// in two separate `let` statements that immediately follow the `splitn()`
|
||||||
#[clippy::version = "1.57.0"]
|
#[clippy::version = "1.57.0"]
|
||||||
pub MANUAL_SPLIT_ONCE,
|
pub MANUAL_SPLIT_ONCE,
|
||||||
complexity,
|
complexity,
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
use clippy_utils::consts::{constant, Constant};
|
use clippy_utils::consts::{constant, Constant};
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||||
use clippy_utils::source::snippet_with_context;
|
use clippy_utils::source::snippet_with_context;
|
||||||
use clippy_utils::{is_diag_item_method, match_def_path, meets_msrv, msrvs, paths};
|
use clippy_utils::usage::local_used_after_expr;
|
||||||
|
use clippy_utils::visitors::expr_visitor;
|
||||||
|
use clippy_utils::{is_diag_item_method, match_def_path, meets_msrv, msrvs, path_to_local_id, paths};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath};
|
use rustc_hir::intravisit::Visitor;
|
||||||
|
use rustc_hir::{
|
||||||
|
BindingAnnotation, Expr, ExprKind, HirId, LangItem, Local, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind,
|
||||||
|
};
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
use rustc_semver::RustcVersion;
|
use rustc_semver::RustcVersion;
|
||||||
use rustc_span::{symbol::sym, Span, SyntaxContext};
|
use rustc_span::{sym, Span, Symbol, SyntaxContext};
|
||||||
|
|
||||||
use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN};
|
use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN};
|
||||||
|
|
||||||
@ -25,40 +30,41 @@ pub(super) fn check(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ctxt = expr.span.ctxt();
|
let needless = |usage_kind| match usage_kind {
|
||||||
let Some(usage) = parse_iter_usage(cx, ctxt, cx.tcx.hir().parent_iter(expr.hir_id)) else { return };
|
|
||||||
|
|
||||||
let needless = match usage.kind {
|
|
||||||
IterUsageKind::Nth(n) => count > n + 1,
|
IterUsageKind::Nth(n) => count > n + 1,
|
||||||
IterUsageKind::NextTuple => count > 2,
|
IterUsageKind::NextTuple => count > 2,
|
||||||
};
|
};
|
||||||
|
let manual = count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE);
|
||||||
|
|
||||||
if needless {
|
match parse_iter_usage(cx, expr.span.ctxt(), cx.tcx.hir().parent_iter(expr.hir_id)) {
|
||||||
let mut app = Applicability::MachineApplicable;
|
Some(usage) if needless(usage.kind) => lint_needless(cx, method_name, expr, self_arg, pat_arg),
|
||||||
let (r, message) = if method_name == "splitn" {
|
Some(usage) if manual => check_manual_split_once(cx, method_name, expr, self_arg, pat_arg, &usage),
|
||||||
("", "unnecessary use of `splitn`")
|
None if manual => {
|
||||||
} else {
|
check_manual_split_once_indirect(cx, method_name, expr, self_arg, pat_arg);
|
||||||
("r", "unnecessary use of `rsplitn`")
|
},
|
||||||
};
|
_ => {},
|
||||||
|
|
||||||
span_lint_and_sugg(
|
|
||||||
cx,
|
|
||||||
NEEDLESS_SPLITN,
|
|
||||||
expr.span,
|
|
||||||
message,
|
|
||||||
"try this",
|
|
||||||
format!(
|
|
||||||
"{}.{r}split({})",
|
|
||||||
snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0,
|
|
||||||
snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0,
|
|
||||||
),
|
|
||||||
app,
|
|
||||||
);
|
|
||||||
} else if count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE) {
|
|
||||||
check_manual_split_once(cx, method_name, expr, self_arg, pat_arg, &usage);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>) {
|
||||||
|
let mut app = Applicability::MachineApplicable;
|
||||||
|
let r = if method_name == "splitn" { "" } else { "r" };
|
||||||
|
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
NEEDLESS_SPLITN,
|
||||||
|
expr.span,
|
||||||
|
&format!("unnecessary use of `{r}splitn`"),
|
||||||
|
"try this",
|
||||||
|
format!(
|
||||||
|
"{}.{r}split({})",
|
||||||
|
snippet_with_context(cx, self_arg.span, expr.span.ctxt(), "..", &mut app).0,
|
||||||
|
snippet_with_context(cx, pat_arg.span, expr.span.ctxt(), "..", &mut app).0,
|
||||||
|
),
|
||||||
|
app,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn check_manual_split_once(
|
fn check_manual_split_once(
|
||||||
cx: &LateContext<'_>,
|
cx: &LateContext<'_>,
|
||||||
method_name: &str,
|
method_name: &str,
|
||||||
@ -107,16 +113,171 @@ fn check_manual_split_once(
|
|||||||
span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try this", sugg, app);
|
span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try this", sugg, app);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// checks for
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let mut iter = "a.b.c".splitn(2, '.');
|
||||||
|
/// let a = iter.next();
|
||||||
|
/// let b = iter.next();
|
||||||
|
/// ```
|
||||||
|
fn check_manual_split_once_indirect(
|
||||||
|
cx: &LateContext<'_>,
|
||||||
|
method_name: &str,
|
||||||
|
expr: &Expr<'_>,
|
||||||
|
self_arg: &Expr<'_>,
|
||||||
|
pat_arg: &Expr<'_>,
|
||||||
|
) -> Option<()> {
|
||||||
|
let ctxt = expr.span.ctxt();
|
||||||
|
let mut parents = cx.tcx.hir().parent_iter(expr.hir_id);
|
||||||
|
if let (_, Node::Local(local)) = parents.next()?
|
||||||
|
&& let PatKind::Binding(BindingAnnotation::Mutable, iter_binding_id, iter_ident, None) = local.pat.kind
|
||||||
|
&& let (iter_stmt_id, Node::Stmt(_)) = parents.next()?
|
||||||
|
&& let (_, Node::Block(enclosing_block)) = parents.next()?
|
||||||
|
|
||||||
|
&& let mut stmts = enclosing_block
|
||||||
|
.stmts
|
||||||
|
.iter()
|
||||||
|
.skip_while(|stmt| stmt.hir_id != iter_stmt_id)
|
||||||
|
.skip(1)
|
||||||
|
|
||||||
|
&& let first = indirect_usage(cx, stmts.next()?, iter_binding_id, ctxt)?
|
||||||
|
&& let second = indirect_usage(cx, stmts.next()?, iter_binding_id, ctxt)?
|
||||||
|
&& first.unwrap_kind == second.unwrap_kind
|
||||||
|
&& first.name != second.name
|
||||||
|
&& !local_used_after_expr(cx, iter_binding_id, second.init_expr)
|
||||||
|
{
|
||||||
|
let (r, lhs, rhs) = if method_name == "splitn" {
|
||||||
|
("", first.name, second.name)
|
||||||
|
} else {
|
||||||
|
("r", second.name, first.name)
|
||||||
|
};
|
||||||
|
let msg = format!("manual implementation of `{r}split_once`");
|
||||||
|
|
||||||
|
let mut app = Applicability::MachineApplicable;
|
||||||
|
let self_snip = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0;
|
||||||
|
let pat_snip = snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0;
|
||||||
|
|
||||||
|
span_lint_and_then(cx, MANUAL_SPLIT_ONCE, local.span, &msg, |diag| {
|
||||||
|
diag.span_label(first.span, "first usage here");
|
||||||
|
diag.span_label(second.span, "second usage here");
|
||||||
|
|
||||||
|
let unwrap = match first.unwrap_kind {
|
||||||
|
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};"),
|
||||||
|
app,
|
||||||
|
);
|
||||||
|
|
||||||
|
let remove_msg = format!("remove the `{iter_ident}` usages");
|
||||||
|
diag.span_suggestion(
|
||||||
|
first.span,
|
||||||
|
&remove_msg,
|
||||||
|
String::new(),
|
||||||
|
app,
|
||||||
|
);
|
||||||
|
diag.span_suggestion(
|
||||||
|
second.span,
|
||||||
|
&remove_msg,
|
||||||
|
String::new(),
|
||||||
|
app,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct IndirectUsage<'a> {
|
||||||
|
name: Symbol,
|
||||||
|
span: Span,
|
||||||
|
init_expr: &'a Expr<'a>,
|
||||||
|
unwrap_kind: UnwrapKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns `Some(IndirectUsage)` for e.g.
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// let name = binding.next()?;
|
||||||
|
/// let name = binding.next().unwrap();
|
||||||
|
/// ```
|
||||||
|
fn indirect_usage<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
stmt: &Stmt<'tcx>,
|
||||||
|
binding: HirId,
|
||||||
|
ctxt: SyntaxContext,
|
||||||
|
) -> Option<IndirectUsage<'tcx>> {
|
||||||
|
if let StmtKind::Local(Local {
|
||||||
|
pat:
|
||||||
|
Pat {
|
||||||
|
kind: PatKind::Binding(BindingAnnotation::Unannotated, _, ident, None),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
init: Some(init_expr),
|
||||||
|
hir_id: local_hir_id,
|
||||||
|
..
|
||||||
|
}) = stmt.kind
|
||||||
|
{
|
||||||
|
let mut path_to_binding = None;
|
||||||
|
expr_visitor(cx, |expr| {
|
||||||
|
if path_to_local_id(expr, binding) {
|
||||||
|
path_to_binding = Some(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
path_to_binding.is_none()
|
||||||
|
})
|
||||||
|
.visit_expr(init_expr);
|
||||||
|
|
||||||
|
let mut parents = cx.tcx.hir().parent_iter(path_to_binding?.hir_id);
|
||||||
|
let iter_usage = parse_iter_usage(cx, ctxt, &mut parents)?;
|
||||||
|
|
||||||
|
let (parent_id, _) = parents.find(|(_, node)| {
|
||||||
|
!matches!(
|
||||||
|
node,
|
||||||
|
Node::Expr(Expr {
|
||||||
|
kind: ExprKind::Match(.., MatchSource::TryDesugar),
|
||||||
|
..
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if let IterUsage {
|
||||||
|
kind: IterUsageKind::Nth(0),
|
||||||
|
unwrap_kind: Some(unwrap_kind),
|
||||||
|
..
|
||||||
|
} = iter_usage
|
||||||
|
{
|
||||||
|
if parent_id == *local_hir_id {
|
||||||
|
return Some(IndirectUsage {
|
||||||
|
name: ident.name,
|
||||||
|
span: stmt.span,
|
||||||
|
init_expr,
|
||||||
|
unwrap_kind,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum IterUsageKind {
|
enum IterUsageKind {
|
||||||
Nth(u128),
|
Nth(u128),
|
||||||
NextTuple,
|
NextTuple,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
enum UnwrapKind {
|
enum UnwrapKind {
|
||||||
Unwrap,
|
Unwrap,
|
||||||
QuestionMark,
|
QuestionMark,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct IterUsage {
|
struct IterUsage {
|
||||||
kind: IterUsageKind,
|
kind: IterUsageKind,
|
||||||
unwrap_kind: Option<UnwrapKind>,
|
unwrap_kind: Option<UnwrapKind>,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#![feature(custom_inner_attributes)]
|
#![feature(custom_inner_attributes)]
|
||||||
#![warn(clippy::manual_split_once)]
|
#![warn(clippy::manual_split_once)]
|
||||||
#![allow(clippy::iter_skip_next, clippy::iter_nth_zero)]
|
#![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)]
|
||||||
|
|
||||||
extern crate itertools;
|
extern crate itertools;
|
||||||
|
|
||||||
@ -41,13 +41,107 @@ fn main() {
|
|||||||
let _ = s.rsplit_once('=').map(|x| x.0);
|
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
|
||||||
|
}
|
||||||
|
|
||||||
fn _msrv_1_51() {
|
fn _msrv_1_51() {
|
||||||
#![clippy::msrv = "1.51"]
|
#![clippy::msrv = "1.51"]
|
||||||
// `str::split_once` was stabilized in 1.52. Do not lint this
|
// `str::split_once` was stabilized in 1.52. Do not lint this
|
||||||
let _ = "key=value".splitn(2, '=').nth(1).unwrap();
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _msrv_1_52() {
|
fn _msrv_1_52() {
|
||||||
#![clippy::msrv = "1.52"]
|
#![clippy::msrv = "1.52"]
|
||||||
let _ = "key=value".split_once('=').unwrap().1;
|
let _ = "key=value".split_once('=').unwrap().1;
|
||||||
|
|
||||||
|
let (a, b) = "a.b.c".split_once('.').unwrap();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#![feature(custom_inner_attributes)]
|
#![feature(custom_inner_attributes)]
|
||||||
#![warn(clippy::manual_split_once)]
|
#![warn(clippy::manual_split_once)]
|
||||||
#![allow(clippy::iter_skip_next, clippy::iter_nth_zero)]
|
#![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)]
|
||||||
|
|
||||||
extern crate itertools;
|
extern crate itertools;
|
||||||
|
|
||||||
@ -41,13 +41,107 @@ fn main() {
|
|||||||
let _ = s.rsplitn(2, '=').nth(1);
|
let _ = s.rsplitn(2, '=').nth(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn indirect() -> Option<()> {
|
||||||
|
let mut iter = "a.b.c".splitn(2, '.');
|
||||||
|
let l = iter.next().unwrap();
|
||||||
|
let r = iter.next().unwrap();
|
||||||
|
|
||||||
|
let mut iter = "a.b.c".splitn(2, '.');
|
||||||
|
let l = iter.next()?;
|
||||||
|
let r = iter.next()?;
|
||||||
|
|
||||||
|
let mut iter = "a.b.c".rsplitn(2, '.');
|
||||||
|
let r = iter.next().unwrap();
|
||||||
|
let l = iter.next().unwrap();
|
||||||
|
|
||||||
|
let mut iter = "a.b.c".rsplitn(2, '.');
|
||||||
|
let r = iter.next()?;
|
||||||
|
let l = iter.next()?;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
fn _msrv_1_51() {
|
fn _msrv_1_51() {
|
||||||
#![clippy::msrv = "1.51"]
|
#![clippy::msrv = "1.51"]
|
||||||
// `str::split_once` was stabilized in 1.52. Do not lint this
|
// `str::split_once` was stabilized in 1.52. Do not lint this
|
||||||
let _ = "key=value".splitn(2, '=').nth(1).unwrap();
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _msrv_1_52() {
|
fn _msrv_1_52() {
|
||||||
#![clippy::msrv = "1.52"]
|
#![clippy::msrv = "1.52"]
|
||||||
let _ = "key=value".splitn(2, '=').nth(1).unwrap();
|
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();
|
||||||
}
|
}
|
||||||
|
@ -79,10 +79,135 @@ LL | let _ = s.rsplitn(2, '=').nth(1);
|
|||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit_once('=').map(|x| x.0)`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit_once('=').map(|x| x.0)`
|
||||||
|
|
||||||
error: manual implementation of `split_once`
|
error: manual implementation of `split_once`
|
||||||
--> $DIR/manual_split_once.rs:52:13
|
--> $DIR/manual_split_once.rs:45:5
|
||||||
|
|
|
||||||
|
LL | let mut iter = "a.b.c".splitn(2, '.');
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | let l = iter.next().unwrap();
|
||||||
|
| ----------------------------- first usage here
|
||||||
|
LL | let r = iter.next().unwrap();
|
||||||
|
| ----------------------------- second usage here
|
||||||
|
|
|
||||||
|
help: try `split_once`
|
||||||
|
|
|
||||||
|
LL | let (l, r) = "a.b.c".split_once('.').unwrap();
|
||||||
|
|
|
||||||
|
help: remove the `iter` usages
|
||||||
|
|
|
||||||
|
LL - let l = iter.next().unwrap();
|
||||||
|
LL +
|
||||||
|
|
|
||||||
|
help: remove the `iter` usages
|
||||||
|
|
|
||||||
|
LL - let r = iter.next().unwrap();
|
||||||
|
LL +
|
||||||
|
|
|
||||||
|
|
||||||
|
error: manual implementation of `split_once`
|
||||||
|
--> $DIR/manual_split_once.rs:49:5
|
||||||
|
|
|
||||||
|
LL | let mut iter = "a.b.c".splitn(2, '.');
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | let l = iter.next()?;
|
||||||
|
| --------------------- first usage here
|
||||||
|
LL | let r = iter.next()?;
|
||||||
|
| --------------------- second usage here
|
||||||
|
|
|
||||||
|
help: try `split_once`
|
||||||
|
|
|
||||||
|
LL | let (l, r) = "a.b.c".split_once('.')?;
|
||||||
|
|
|
||||||
|
help: remove the `iter` usages
|
||||||
|
|
|
||||||
|
LL - let l = iter.next()?;
|
||||||
|
LL +
|
||||||
|
|
|
||||||
|
help: remove the `iter` usages
|
||||||
|
|
|
||||||
|
LL - let r = iter.next()?;
|
||||||
|
LL +
|
||||||
|
|
|
||||||
|
|
||||||
|
error: manual implementation of `rsplit_once`
|
||||||
|
--> $DIR/manual_split_once.rs:53:5
|
||||||
|
|
|
||||||
|
LL | let mut iter = "a.b.c".rsplitn(2, '.');
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | let r = iter.next().unwrap();
|
||||||
|
| ----------------------------- first usage here
|
||||||
|
LL | let l = iter.next().unwrap();
|
||||||
|
| ----------------------------- second usage here
|
||||||
|
|
|
||||||
|
help: try `rsplit_once`
|
||||||
|
|
|
||||||
|
LL | let (l, r) = "a.b.c".rsplit_once('.').unwrap();
|
||||||
|
|
|
||||||
|
help: remove the `iter` usages
|
||||||
|
|
|
||||||
|
LL - let r = iter.next().unwrap();
|
||||||
|
LL +
|
||||||
|
|
|
||||||
|
help: remove the `iter` usages
|
||||||
|
|
|
||||||
|
LL - let l = iter.next().unwrap();
|
||||||
|
LL +
|
||||||
|
|
|
||||||
|
|
||||||
|
error: manual implementation of `rsplit_once`
|
||||||
|
--> $DIR/manual_split_once.rs:57:5
|
||||||
|
|
|
||||||
|
LL | let mut iter = "a.b.c".rsplitn(2, '.');
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | let r = iter.next()?;
|
||||||
|
| --------------------- first usage here
|
||||||
|
LL | let l = iter.next()?;
|
||||||
|
| --------------------- second usage here
|
||||||
|
|
|
||||||
|
help: try `rsplit_once`
|
||||||
|
|
|
||||||
|
LL | let (l, r) = "a.b.c".rsplit_once('.')?;
|
||||||
|
|
|
||||||
|
help: remove the `iter` usages
|
||||||
|
|
|
||||||
|
LL - let r = iter.next()?;
|
||||||
|
LL +
|
||||||
|
|
|
||||||
|
help: remove the `iter` usages
|
||||||
|
|
|
||||||
|
LL - let l = iter.next()?;
|
||||||
|
LL +
|
||||||
|
|
|
||||||
|
|
||||||
|
error: manual implementation of `split_once`
|
||||||
|
--> $DIR/manual_split_once.rs:142:13
|
||||||
|
|
|
|
||||||
LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap();
|
LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1`
|
||||||
|
|
||||||
error: aborting due to 14 previous errors
|
error: manual implementation of `split_once`
|
||||||
|
--> $DIR/manual_split_once.rs:144:5
|
||||||
|
|
|
||||||
|
LL | let mut iter = "a.b.c".splitn(2, '.');
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | let a = iter.next().unwrap();
|
||||||
|
| ----------------------------- first usage here
|
||||||
|
LL | let b = iter.next().unwrap();
|
||||||
|
| ----------------------------- second usage here
|
||||||
|
|
|
||||||
|
help: try `split_once`
|
||||||
|
|
|
||||||
|
LL | let (a, b) = "a.b.c".split_once('.').unwrap();
|
||||||
|
|
|
||||||
|
help: remove the `iter` usages
|
||||||
|
|
|
||||||
|
LL - let a = iter.next().unwrap();
|
||||||
|
LL +
|
||||||
|
|
|
||||||
|
help: remove the `iter` usages
|
||||||
|
|
|
||||||
|
LL - let b = iter.next().unwrap();
|
||||||
|
LL +
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 19 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user