From 7fbf808a5056f63da5d2ae86ebeb32fb21f45b50 Mon Sep 17 00:00:00 2001 From: Red Rapious Date: Mon, 21 Aug 2023 18:50:53 +0200 Subject: [PATCH 1/9] Added new lint: `reserve_after_initialization` --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + .../src/reserve_after_initialization.rs | 242 ++++++++++++++++++ tests/ui/reserve_after_initialization.fixed | 5 + tests/ui/reserve_after_initialization.rs | 6 + tests/ui/reserve_after_initialization.stderr | 11 + 7 files changed, 268 insertions(+) create mode 100644 clippy_lints/src/reserve_after_initialization.rs create mode 100644 tests/ui/reserve_after_initialization.fixed create mode 100644 tests/ui/reserve_after_initialization.rs create mode 100644 tests/ui/reserve_after_initialization.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index fe64283462d1..4e33cb7b4570 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5299,6 +5299,7 @@ Released 2018-09-13 [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts +[`reserve_after_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#reserve_after_initialization [`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs [`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used [`result_large_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index bab77f912691..1be9720fbbf8 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -579,6 +579,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::reference::DEREF_ADDROF_INFO, crate::regex::INVALID_REGEX_INFO, crate::regex::TRIVIAL_REGEX_INFO, + crate::reserve_after_initialization::RESERVE_AFTER_INITIALIZATION_INFO, crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO, crate::returns::LET_AND_RETURN_INFO, crate::returns::NEEDLESS_RETURN_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 358004cf460b..791fb96453d0 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -285,6 +285,7 @@ mod ref_option_ref; mod ref_patterns; mod reference; mod regex; +mod reserve_after_initialization; mod return_self_not_must_use; mod returns; mod same_name_method; @@ -1095,6 +1096,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); store.register_late_pass(|_| Box::new(redundant_locals::RedundantLocals)); store.register_late_pass(|_| Box::new(ignored_unit_patterns::IgnoredUnitPatterns)); + store.register_late_pass(|_| Box::new(reserve_after_initialization::ReserveAfterInitialization::default())); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/reserve_after_initialization.rs b/clippy_lints/src/reserve_after_initialization.rs new file mode 100644 index 000000000000..073f810048c1 --- /dev/null +++ b/clippy_lints/src/reserve_after_initialization.rs @@ -0,0 +1,242 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; +use clippy_utils::source::snippet; +use clippy_utils::visitors::for_each_local_use_after_expr; +use clippy_utils::{get_parent_expr, path_to_local_id}; +use core::ops::ControlFlow; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::def::Res; +use rustc_hir::{ + BindingAnnotation, Block, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp, +}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{Span, Symbol}; + +declare_clippy_lint! { + /// ### What it does + /// Informs the user about a more concise way to create a vector with a known capacity. + /// + /// ### Why is this bad? + /// The `Vec::with_capacity` constructor is easier to understand. + /// + /// ### Example + /// ```rust + /// { + /// let mut v = vec![]; + /// v.reserve(space_hint); + /// v + /// } + /// ``` + /// Use instead: + /// ```rust + /// Vec::with_capacity(space_hint) + /// ``` + #[clippy::version = "1.73.0"] + pub RESERVE_AFTER_INITIALIZATION, + complexity, + "`reserve` called immediatly after `Vec` creation" +} +impl_lint_pass!(ReserveAfterInitialization => [RESERVE_AFTER_INITIALIZATION]); + +/*impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'_>) { + if let ExprKind::Assign(left, right, _) = expr.kind + && let ExprKind::Path(QPath::Resolved(None, path)) = left.kind + && let [name] = &path.segments + && let Res::Local(id) = path.res + && let Some(init) = get_vec_init_kind(cx, right) + && !matches!(init, VecInitKind::WithExprCapacity(_)) { + span_lint_and_help( + cx, + RESERVE_AFTER_INITIALIZATION, + expr.span, + "`reserve` called just after the initialisation of the vector", + None, + "use `Vec::with_capacity(space_hint)` instead" + ); + } + } + + /*fn check_block(&mut self, cx: &LateContext<'_>, block: &'_ rustc_hir::Block<'_>) { + span_lint_and_help( + cx, + RESERVE_AFTER_INITIALIZATION, + block.span, + "`reserve` called just after the initialisation of the vector", + None, + "use `Vec::with_capacity(space_hint)` instead" + ); + }*/ +}*/ + +#[derive(Default)] +pub struct ReserveAfterInitialization { + searcher: Option, +} + +struct VecReserveSearcher { + local_id: HirId, + lhs_is_let: bool, + let_ty_span: Option, + name: Symbol, + err_span: Span, + last_reserve_expr: HirId, + space_hint: usize, +} +impl VecReserveSearcher { + fn display_err(&self, cx: &LateContext<'_>) { + if self.space_hint == 0 { + return; + } + + let mut needs_mut = false; + let _res = for_each_local_use_after_expr(cx, self.local_id, self.last_reserve_expr, |e| { + let Some(parent) = get_parent_expr(cx, e) else { + return ControlFlow::Continue(()); + }; + let adjusted_ty = cx.typeck_results().expr_ty_adjusted(e); + let adjusted_mut = adjusted_ty.ref_mutability().unwrap_or(Mutability::Not); + needs_mut |= adjusted_mut == Mutability::Mut; + match parent.kind { + ExprKind::AddrOf(_, Mutability::Mut, _) => { + needs_mut = true; + return ControlFlow::Break(true); + }, + ExprKind::Unary(UnOp::Deref, _) | ExprKind::Index(..) if !needs_mut => { + let mut last_place = parent; + while let Some(parent) = get_parent_expr(cx, last_place) { + if matches!(parent.kind, ExprKind::Unary(UnOp::Deref, _) | ExprKind::Field(..)) + || matches!(parent.kind, ExprKind::Index(e, _, _) if e.hir_id == last_place.hir_id) + { + last_place = parent; + } else { + break; + } + } + needs_mut |= cx.typeck_results().expr_ty_adjusted(last_place).ref_mutability() + == Some(Mutability::Mut) + || get_parent_expr(cx, last_place) + .map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(_, Mutability::Mut, _))); + }, + ExprKind::MethodCall(_, recv, ..) + if recv.hir_id == e.hir_id + && adjusted_mut == Mutability::Mut + && !adjusted_ty.peel_refs().is_slice() => + { + // No need to set `needs_mut` to true. The receiver will be either explicitly borrowed, or it will + // be implicitly borrowed via an adjustment. Both of these cases are already handled by this point. + return ControlFlow::Break(true); + }, + ExprKind::Assign(lhs, ..) if e.hir_id == lhs.hir_id => { + needs_mut = true; + return ControlFlow::Break(false); + }, + _ => (), + } + ControlFlow::Continue(()) + }); + + let mut s = if self.lhs_is_let { + String::from("let ") + } else { + String::new() + }; + if needs_mut { + s.push_str("mut "); + } + s.push_str(self.name.as_str()); + if let Some(span) = self.let_ty_span { + s.push_str(": "); + s.push_str(&snippet(cx, span, "_")); + } + s.push_str(format!(" = Vec::with_capacity({});", self.space_hint).as_str()); + + span_lint_and_sugg( + cx, + RESERVE_AFTER_INITIALIZATION, + self.err_span, + "calls to `reverse` immediately after creation", + "consider using `Vec::with_capacity(space_hint)`", + s, + Applicability::HasPlaceholders, + ); + } +} + +impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { + fn check_block(&mut self, _: &LateContext<'tcx>, _: &'tcx Block<'tcx>) { + self.searcher = None; + } + + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { + if let Some(init_expr) = local.init + && let PatKind::Binding(BindingAnnotation::MUT, id, name, None) = local.pat.kind + && !in_external_macro(cx.sess(), local.span) + && let Some(init) = get_vec_init_kind(cx, init_expr) + && !matches!(init, VecInitKind::WithExprCapacity(_)) + { + self.searcher = Some(VecReserveSearcher { + local_id: id, + lhs_is_let: true, + name: name.name, + let_ty_span: local.ty.map(|ty| ty.span), + err_span: local.span, + last_reserve_expr: init_expr.hir_id, + space_hint: 0 + }); + } + } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if self.searcher.is_none() + && let ExprKind::Assign(left, right, _) = expr.kind + && let ExprKind::Path(QPath::Resolved(None, path)) = left.kind + && let [name] = &path.segments + && let Res::Local(id) = path.res + && !in_external_macro(cx.sess(), expr.span) + && let Some(init) = get_vec_init_kind(cx, right) + && !matches!(init, VecInitKind::WithExprCapacity(_)) + { + self.searcher = Some(VecReserveSearcher { + local_id: id, + lhs_is_let: false, + let_ty_span: None, + name: name.ident.name, + err_span: expr.span, + last_reserve_expr: expr.hir_id, + space_hint: 0 + }); + } + } + + fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { + if let Some(searcher) = self.searcher.take() { + if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind + && let ExprKind::MethodCall(name, self_arg, other_args, _) = expr.kind + && other_args.len() == 1 + && let ExprKind::Lit(lit) = other_args[0].kind + && let LitKind::Int(space_hint, _) = lit.node + && path_to_local_id(self_arg, searcher.local_id) + && name.ident.as_str() == "reserve" + { + self.searcher = Some(VecReserveSearcher { + err_span: searcher.err_span.to(stmt.span), + last_reserve_expr: expr.hir_id, + space_hint: space_hint as usize, + .. searcher + }); + } else { + searcher.display_err(cx); + } + } + } + + fn check_block_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx Block<'tcx>) { + if let Some(searcher) = self.searcher.take() { + searcher.display_err(cx); + } + } +} diff --git a/tests/ui/reserve_after_initialization.fixed b/tests/ui/reserve_after_initialization.fixed new file mode 100644 index 000000000000..fe1f7ff174e5 --- /dev/null +++ b/tests/ui/reserve_after_initialization.fixed @@ -0,0 +1,5 @@ +#![warn(clippy::reserve_after_initialization)] + +fn main() { + let v: Vec = Vec::with_capacity(10); +} diff --git a/tests/ui/reserve_after_initialization.rs b/tests/ui/reserve_after_initialization.rs new file mode 100644 index 000000000000..469b951b1c42 --- /dev/null +++ b/tests/ui/reserve_after_initialization.rs @@ -0,0 +1,6 @@ +#![warn(clippy::reserve_after_initialization)] + +fn main() { + let mut v: Vec = vec![]; + v.reserve(10); +} diff --git a/tests/ui/reserve_after_initialization.stderr b/tests/ui/reserve_after_initialization.stderr new file mode 100644 index 000000000000..da8c7d693f0b --- /dev/null +++ b/tests/ui/reserve_after_initialization.stderr @@ -0,0 +1,11 @@ +error: calls to `reverse` immediately after creation + --> $DIR/reserve_after_initialization.rs:4:5 + | +LL | / let mut v: Vec = vec![]; +LL | | v.reserve(10); + | |__________________^ help: consider using `Vec::with_capacity(space_hint)`: `let v: Vec = Vec::with_capacity(10);` + | + = note: `-D clippy::reserve-after-initialization` implied by `-D warnings` + +error: aborting due to previous error + From e33a17e33c0201f8fe00a17e875fe8f8b7210ce5 Mon Sep 17 00:00:00 2001 From: Red Rapious Date: Mon, 21 Aug 2023 19:05:59 +0200 Subject: [PATCH 2/9] Changed Box --- clippy_lints/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 791fb96453d0..f50019f3cf76 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1096,7 +1096,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); store.register_late_pass(|_| Box::new(redundant_locals::RedundantLocals)); store.register_late_pass(|_| Box::new(ignored_unit_patterns::IgnoredUnitPatterns)); - store.register_late_pass(|_| Box::new(reserve_after_initialization::ReserveAfterInitialization::default())); + store.register_late_pass(|_| Box::::default()); // add lints here, do not remove this comment, it's used in `new_lint` } From 073149a7ef483b8feddacc865e935d6019272e14 Mon Sep 17 00:00:00 2001 From: Red Rapious Date: Mon, 21 Aug 2023 19:21:02 +0200 Subject: [PATCH 3/9] Changed documentation example and removed comments --- .../src/reserve_after_initialization.rs | 40 ++----------------- 1 file changed, 3 insertions(+), 37 deletions(-) diff --git a/clippy_lints/src/reserve_after_initialization.rs b/clippy_lints/src/reserve_after_initialization.rs index 073f810048c1..6a2bbd0af852 100644 --- a/clippy_lints/src/reserve_after_initialization.rs +++ b/clippy_lints/src/reserve_after_initialization.rs @@ -24,15 +24,12 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// { - /// let mut v = vec![]; - /// v.reserve(space_hint); - /// v - /// } + /// let mut v: Vec = vec![]; + /// v.reserve(10); /// ``` /// Use instead: /// ```rust - /// Vec::with_capacity(space_hint) + /// let mut v: Vec = Vec::with_capacity(10); /// ``` #[clippy::version = "1.73.0"] pub RESERVE_AFTER_INITIALIZATION, @@ -41,37 +38,6 @@ declare_clippy_lint! { } impl_lint_pass!(ReserveAfterInitialization => [RESERVE_AFTER_INITIALIZATION]); -/*impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'_>) { - if let ExprKind::Assign(left, right, _) = expr.kind - && let ExprKind::Path(QPath::Resolved(None, path)) = left.kind - && let [name] = &path.segments - && let Res::Local(id) = path.res - && let Some(init) = get_vec_init_kind(cx, right) - && !matches!(init, VecInitKind::WithExprCapacity(_)) { - span_lint_and_help( - cx, - RESERVE_AFTER_INITIALIZATION, - expr.span, - "`reserve` called just after the initialisation of the vector", - None, - "use `Vec::with_capacity(space_hint)` instead" - ); - } - } - - /*fn check_block(&mut self, cx: &LateContext<'_>, block: &'_ rustc_hir::Block<'_>) { - span_lint_and_help( - cx, - RESERVE_AFTER_INITIALIZATION, - block.span, - "`reserve` called just after the initialisation of the vector", - None, - "use `Vec::with_capacity(space_hint)` instead" - ); - }*/ -}*/ - #[derive(Default)] pub struct ReserveAfterInitialization { searcher: Option, From a1bf23f0a394788aec496e5440d8520d2807caec Mon Sep 17 00:00:00 2001 From: Red Rapious Date: Mon, 21 Aug 2023 22:22:48 +0200 Subject: [PATCH 4/9] Added more use cases --- .../src/reserve_after_initialization.rs | 43 +++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/reserve_after_initialization.rs b/clippy_lints/src/reserve_after_initialization.rs index 6a2bbd0af852..f9454bd7540b 100644 --- a/clippy_lints/src/reserve_after_initialization.rs +++ b/clippy_lints/src/reserve_after_initialization.rs @@ -50,11 +50,11 @@ struct VecReserveSearcher { name: Symbol, err_span: Span, last_reserve_expr: HirId, - space_hint: usize, + space_hint: Option, } impl VecReserveSearcher { fn display_err(&self, cx: &LateContext<'_>) { - if self.space_hint == 0 { + if self.space_hint == Some(0) { return; } @@ -118,7 +118,16 @@ impl VecReserveSearcher { s.push_str(": "); s.push_str(&snippet(cx, span, "_")); } - s.push_str(format!(" = Vec::with_capacity({});", self.space_hint).as_str()); + s.push_str( + format!( + " = Vec::with_capacity({});", + match self.space_hint { + None => "..".to_string(), + Some(hint) => hint.to_string(), + } + ) + .as_str(), + ); span_lint_and_sugg( cx, @@ -151,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { let_ty_span: local.ty.map(|ty| ty.span), err_span: local.span, last_reserve_expr: init_expr.hir_id, - space_hint: 0 + space_hint: Some(0) }); } } @@ -173,7 +182,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { name: name.ident.name, err_span: expr.span, last_reserve_expr: expr.hir_id, - space_hint: 0 + space_hint: Some(0) }); } } @@ -183,17 +192,25 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind && let ExprKind::MethodCall(name, self_arg, other_args, _) = expr.kind && other_args.len() == 1 - && let ExprKind::Lit(lit) = other_args[0].kind - && let LitKind::Int(space_hint, _) = lit.node && path_to_local_id(self_arg, searcher.local_id) && name.ident.as_str() == "reserve" { - self.searcher = Some(VecReserveSearcher { - err_span: searcher.err_span.to(stmt.span), - last_reserve_expr: expr.hir_id, - space_hint: space_hint as usize, - .. searcher - }); + if let ExprKind::Lit(lit) = other_args[0].kind + && let LitKind::Int(space_hint, _) = lit.node { + self.searcher = Some(VecReserveSearcher { + err_span: searcher.err_span.to(stmt.span), + last_reserve_expr: expr.hir_id, + space_hint: Some(space_hint as usize), // the expression is an int, so we'll display the good amount as a hint + .. searcher + }); + } else { + self.searcher = Some(VecReserveSearcher { + err_span: searcher.err_span.to(stmt.span), + last_reserve_expr: expr.hir_id, + space_hint: None, // the expression isn't an int, so we'll display ".." as hint + .. searcher + }); + } } else { searcher.display_err(cx); } From b0bd6219c8f62ea97bbc6d5580f9b847758fb195 Mon Sep 17 00:00:00 2001 From: Red Rapious Date: Mon, 21 Aug 2023 23:36:15 +0200 Subject: [PATCH 5/9] Simplified code and added tests --- .../src/reserve_after_initialization.rs | 138 ++++-------------- tests/ui/reserve_after_initialization.fixed | 14 +- tests/ui/reserve_after_initialization.rs | 17 ++- tests/ui/reserve_after_initialization.stderr | 17 ++- 4 files changed, 66 insertions(+), 120 deletions(-) diff --git a/clippy_lints/src/reserve_after_initialization.rs b/clippy_lints/src/reserve_after_initialization.rs index f9454bd7540b..d530d5758b1f 100644 --- a/clippy_lints/src/reserve_after_initialization.rs +++ b/clippy_lints/src/reserve_after_initialization.rs @@ -1,19 +1,15 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; +use clippy_utils::path_to_local_id; use clippy_utils::source::snippet; -use clippy_utils::visitors::for_each_local_use_after_expr; -use clippy_utils::{get_parent_expr, path_to_local_id}; -use core::ops::ControlFlow; -use rustc_ast::LitKind; +//use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::{ - BindingAnnotation, Block, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp, -}; +use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{Span, Symbol}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -45,89 +41,17 @@ pub struct ReserveAfterInitialization { struct VecReserveSearcher { local_id: HirId, - lhs_is_let: bool, - let_ty_span: Option, - name: Symbol, err_span: Span, - last_reserve_expr: HirId, - space_hint: Option, + init_part: String, + space_hint: String, } impl VecReserveSearcher { fn display_err(&self, cx: &LateContext<'_>) { - if self.space_hint == Some(0) { + if self.space_hint.is_empty() { return; } - let mut needs_mut = false; - let _res = for_each_local_use_after_expr(cx, self.local_id, self.last_reserve_expr, |e| { - let Some(parent) = get_parent_expr(cx, e) else { - return ControlFlow::Continue(()); - }; - let adjusted_ty = cx.typeck_results().expr_ty_adjusted(e); - let adjusted_mut = adjusted_ty.ref_mutability().unwrap_or(Mutability::Not); - needs_mut |= adjusted_mut == Mutability::Mut; - match parent.kind { - ExprKind::AddrOf(_, Mutability::Mut, _) => { - needs_mut = true; - return ControlFlow::Break(true); - }, - ExprKind::Unary(UnOp::Deref, _) | ExprKind::Index(..) if !needs_mut => { - let mut last_place = parent; - while let Some(parent) = get_parent_expr(cx, last_place) { - if matches!(parent.kind, ExprKind::Unary(UnOp::Deref, _) | ExprKind::Field(..)) - || matches!(parent.kind, ExprKind::Index(e, _, _) if e.hir_id == last_place.hir_id) - { - last_place = parent; - } else { - break; - } - } - needs_mut |= cx.typeck_results().expr_ty_adjusted(last_place).ref_mutability() - == Some(Mutability::Mut) - || get_parent_expr(cx, last_place) - .map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(_, Mutability::Mut, _))); - }, - ExprKind::MethodCall(_, recv, ..) - if recv.hir_id == e.hir_id - && adjusted_mut == Mutability::Mut - && !adjusted_ty.peel_refs().is_slice() => - { - // No need to set `needs_mut` to true. The receiver will be either explicitly borrowed, or it will - // be implicitly borrowed via an adjustment. Both of these cases are already handled by this point. - return ControlFlow::Break(true); - }, - ExprKind::Assign(lhs, ..) if e.hir_id == lhs.hir_id => { - needs_mut = true; - return ControlFlow::Break(false); - }, - _ => (), - } - ControlFlow::Continue(()) - }); - - let mut s = if self.lhs_is_let { - String::from("let ") - } else { - String::new() - }; - if needs_mut { - s.push_str("mut "); - } - s.push_str(self.name.as_str()); - if let Some(span) = self.let_ty_span { - s.push_str(": "); - s.push_str(&snippet(cx, span, "_")); - } - s.push_str( - format!( - " = Vec::with_capacity({});", - match self.space_hint { - None => "..".to_string(), - Some(hint) => hint.to_string(), - } - ) - .as_str(), - ); + let s = format!("{} = Vec::with_capacity({});", self.init_part, self.space_hint); span_lint_and_sugg( cx, @@ -148,19 +72,22 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { if let Some(init_expr) = local.init - && let PatKind::Binding(BindingAnnotation::MUT, id, name, None) = local.pat.kind + && let PatKind::Binding(BindingAnnotation::MUT, id, _name, None) = local.pat.kind && !in_external_macro(cx.sess(), local.span) && let Some(init) = get_vec_init_kind(cx, init_expr) && !matches!(init, VecInitKind::WithExprCapacity(_)) + && !matches!(init, VecInitKind::WithConstCapacity(_)) { self.searcher = Some(VecReserveSearcher { local_id: id, - lhs_is_let: true, - name: name.name, - let_ty_span: local.ty.map(|ty| ty.span), err_span: local.span, - last_reserve_expr: init_expr.hir_id, - space_hint: Some(0) + init_part: format!("let {}: {}", + snippet(cx, local.pat.span, ""), + match local.ty { + Some(type_inference) => snippet(cx, type_inference.span, "").to_string(), + None => String::new() + }), + space_hint: String::new() }); } } @@ -169,20 +96,18 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { if self.searcher.is_none() && let ExprKind::Assign(left, right, _) = expr.kind && let ExprKind::Path(QPath::Resolved(None, path)) = left.kind - && let [name] = &path.segments + && let [_name] = &path.segments && let Res::Local(id) = path.res && !in_external_macro(cx.sess(), expr.span) && let Some(init) = get_vec_init_kind(cx, right) && !matches!(init, VecInitKind::WithExprCapacity(_)) + && !matches!(init, VecInitKind::WithConstCapacity(_)) { self.searcher = Some(VecReserveSearcher { local_id: id, - lhs_is_let: false, - let_ty_span: None, - name: name.ident.name, err_span: expr.span, - last_reserve_expr: expr.hir_id, - space_hint: Some(0) + init_part: snippet(cx, left.span, "").to_string(), + space_hint: String::new() }); } } @@ -195,22 +120,11 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { && path_to_local_id(self_arg, searcher.local_id) && name.ident.as_str() == "reserve" { - if let ExprKind::Lit(lit) = other_args[0].kind - && let LitKind::Int(space_hint, _) = lit.node { - self.searcher = Some(VecReserveSearcher { - err_span: searcher.err_span.to(stmt.span), - last_reserve_expr: expr.hir_id, - space_hint: Some(space_hint as usize), // the expression is an int, so we'll display the good amount as a hint - .. searcher - }); - } else { - self.searcher = Some(VecReserveSearcher { - err_span: searcher.err_span.to(stmt.span), - last_reserve_expr: expr.hir_id, - space_hint: None, // the expression isn't an int, so we'll display ".." as hint - .. searcher - }); - } + self.searcher = Some(VecReserveSearcher { + err_span: searcher.err_span.to(stmt.span), + space_hint: snippet(cx, other_args[0].span, "").to_string(), + .. searcher + }); } else { searcher.display_err(cx); } diff --git a/tests/ui/reserve_after_initialization.fixed b/tests/ui/reserve_after_initialization.fixed index fe1f7ff174e5..e7dd8f6b14fb 100644 --- a/tests/ui/reserve_after_initialization.fixed +++ b/tests/ui/reserve_after_initialization.fixed @@ -1,5 +1,17 @@ #![warn(clippy::reserve_after_initialization)] fn main() { - let v: Vec = Vec::with_capacity(10); + // Should lint + let mut v1: Vec = Vec::with_capacity(10); + + // Should lint + let capacity = 10; + let mut v2: Vec = Vec::with_capacity(capacity); + + // Shouldn't lint + let mut v3 = vec![1]; + v3.reserve(10); + + // Shouldn't lint + let mut v4: Vec = Vec::with_capacity(10); } diff --git a/tests/ui/reserve_after_initialization.rs b/tests/ui/reserve_after_initialization.rs index 469b951b1c42..07f9377dbfe2 100644 --- a/tests/ui/reserve_after_initialization.rs +++ b/tests/ui/reserve_after_initialization.rs @@ -1,6 +1,19 @@ #![warn(clippy::reserve_after_initialization)] fn main() { - let mut v: Vec = vec![]; - v.reserve(10); + // Should lint + let mut v1: Vec = vec![]; + v1.reserve(10); + + // Should lint + let capacity = 10; + let mut v2: Vec = vec![]; + v2.reserve(capacity); + + // Shouldn't lint + let mut v3 = vec![1]; + v3.reserve(10); + + // Shouldn't lint + let mut v4: Vec = Vec::with_capacity(10); } diff --git a/tests/ui/reserve_after_initialization.stderr b/tests/ui/reserve_after_initialization.stderr index da8c7d693f0b..ab2753cdd600 100644 --- a/tests/ui/reserve_after_initialization.stderr +++ b/tests/ui/reserve_after_initialization.stderr @@ -1,11 +1,18 @@ error: calls to `reverse` immediately after creation - --> $DIR/reserve_after_initialization.rs:4:5 + --> $DIR/reserve_after_initialization.rs:5:5 | -LL | / let mut v: Vec = vec![]; -LL | | v.reserve(10); - | |__________________^ help: consider using `Vec::with_capacity(space_hint)`: `let v: Vec = Vec::with_capacity(10);` +LL | / let mut v1: Vec = vec![]; +LL | | v1.reserve(10); + | |___________________^ help: consider using `Vec::with_capacity(space_hint)`: `let mut v1: Vec = Vec::with_capacity(10);` | = note: `-D clippy::reserve-after-initialization` implied by `-D warnings` -error: aborting due to previous error +error: calls to `reverse` immediately after creation + --> $DIR/reserve_after_initialization.rs:10:5 + | +LL | / let mut v2: Vec = vec![]; +LL | | v2.reserve(capacity); + | |_________________________^ help: consider using `Vec::with_capacity(space_hint)`: `let mut v2: Vec = Vec::with_capacity(capacity);` + +error: aborting due to 2 previous errors From df8bb47f1711d0db0dd6e9e8446b15b394721126 Mon Sep 17 00:00:00 2001 From: Red Rapious Date: Tue, 22 Aug 2023 18:46:16 +0200 Subject: [PATCH 6/9] Improved snippets and added tests --- .../src/reserve_after_initialization.rs | 36 ++++++------- tests/ui/reserve_after_initialization.fixed | 53 +++++++++++++++--- tests/ui/reserve_after_initialization.rs | 54 ++++++++++++++++--- tests/ui/reserve_after_initialization.stderr | 21 +++++--- 4 files changed, 124 insertions(+), 40 deletions(-) diff --git a/clippy_lints/src/reserve_after_initialization.rs b/clippy_lints/src/reserve_after_initialization.rs index d530d5758b1f..17ca9c8aab87 100644 --- a/clippy_lints/src/reserve_after_initialization.rs +++ b/clippy_lints/src/reserve_after_initialization.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; use clippy_utils::path_to_local_id; use clippy_utils::source::snippet; -//use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, QPath, Stmt, StmtKind}; @@ -16,7 +15,7 @@ declare_clippy_lint! { /// Informs the user about a more concise way to create a vector with a known capacity. /// /// ### Why is this bad? - /// The `Vec::with_capacity` constructor is easier to understand. + /// The `Vec::with_capacity` constructor is less complex. /// /// ### Example /// ```rust @@ -51,14 +50,14 @@ impl VecReserveSearcher { return; } - let s = format!("{} = Vec::with_capacity({});", self.init_part, self.space_hint); + let s = format!("{}Vec::with_capacity({});", self.init_part, self.space_hint); span_lint_and_sugg( cx, RESERVE_AFTER_INITIALIZATION, self.err_span, - "calls to `reverse` immediately after creation", - "consider using `Vec::with_capacity(space_hint)`", + "call to `reserve` immediately after creation", + "consider using `Vec::with_capacity(/* Space hint */)`", s, Applicability::HasPlaceholders, ); @@ -72,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { if let Some(init_expr) = local.init - && let PatKind::Binding(BindingAnnotation::MUT, id, _name, None) = local.pat.kind + && let PatKind::Binding(BindingAnnotation::MUT, id, _, None) = local.pat.kind && !in_external_macro(cx.sess(), local.span) && let Some(init) = get_vec_init_kind(cx, init_expr) && !matches!(init, VecInitKind::WithExprCapacity(_)) @@ -81,12 +80,9 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { self.searcher = Some(VecReserveSearcher { local_id: id, err_span: local.span, - init_part: format!("let {}: {}", - snippet(cx, local.pat.span, ""), - match local.ty { - Some(type_inference) => snippet(cx, type_inference.span, "").to_string(), - None => String::new() - }), + init_part: snippet(cx, local.span.shrink_to_lo() + .to(init_expr.span.source_callsite().shrink_to_lo()), "..") + .into_owned(), space_hint: String::new() }); } @@ -96,17 +92,20 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { if self.searcher.is_none() && let ExprKind::Assign(left, right, _) = expr.kind && let ExprKind::Path(QPath::Resolved(None, path)) = left.kind - && let [_name] = &path.segments + && let [_] = &path.segments && let Res::Local(id) = path.res && !in_external_macro(cx.sess(), expr.span) && let Some(init) = get_vec_init_kind(cx, right) - && !matches!(init, VecInitKind::WithExprCapacity(_)) - && !matches!(init, VecInitKind::WithConstCapacity(_)) + && !matches!(init, VecInitKind::WithExprCapacity(_) + | VecInitKind::WithConstCapacity(_) + ) { self.searcher = Some(VecReserveSearcher { local_id: id, err_span: expr.span, - init_part: snippet(cx, left.span, "").to_string(), + init_part: snippet(cx, left.span.shrink_to_lo() + .to(right.span.source_callsite().shrink_to_lo()), "..") + .into_owned(), // see `assign_expression` test space_hint: String::new() }); } @@ -115,14 +114,13 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if let Some(searcher) = self.searcher.take() { if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind - && let ExprKind::MethodCall(name, self_arg, other_args, _) = expr.kind - && other_args.len() == 1 + && let ExprKind::MethodCall(name, self_arg, [space_hint], _) = expr.kind && path_to_local_id(self_arg, searcher.local_id) && name.ident.as_str() == "reserve" { self.searcher = Some(VecReserveSearcher { err_span: searcher.err_span.to(stmt.span), - space_hint: snippet(cx, other_args[0].span, "").to_string(), + space_hint: snippet(cx, space_hint.span, "..").to_string(), .. searcher }); } else { diff --git a/tests/ui/reserve_after_initialization.fixed b/tests/ui/reserve_after_initialization.fixed index e7dd8f6b14fb..5ef848ed8cf4 100644 --- a/tests/ui/reserve_after_initialization.fixed +++ b/tests/ui/reserve_after_initialization.fixed @@ -1,17 +1,56 @@ #![warn(clippy::reserve_after_initialization)] +#![no_main] -fn main() { - // Should lint +// Should lint +fn standard() { let mut v1: Vec = Vec::with_capacity(10); +} - // Should lint +// Should lint +fn capacity_as_expr() { let capacity = 10; let mut v2: Vec = Vec::with_capacity(capacity); +} - // Shouldn't lint +// Shouldn't lint +fn vec_init_with_argument() { let mut v3 = vec![1]; v3.reserve(10); - - // Shouldn't lint - let mut v4: Vec = Vec::with_capacity(10); } + +// Shouldn't lint +fn called_with_capacity() { + let _v4: Vec = Vec::with_capacity(10); +} + +// Should lint +fn assign_expression() { + let mut v5: Vec = Vec::new(); + v5 = Vec::with_capacity(10); +} + +/*fn in_macros() { + external! { + // Should lint + let mut v1: Vec = vec![]; + v1.reserve(10); + + // Should lint + let capacity = 10; + let mut v2: Vec = vec![]; + v2.reserve(capacity); + } + + with_span! { + span + + // Should lint + let mut v1: Vec = vec![]; + v1.reserve(10); + + // Should lint + let capacity = 10; + let mut v2: Vec = vec![]; + v2.reserve(capacity); + } +}*/ diff --git a/tests/ui/reserve_after_initialization.rs b/tests/ui/reserve_after_initialization.rs index 07f9377dbfe2..eba7bc8dab33 100644 --- a/tests/ui/reserve_after_initialization.rs +++ b/tests/ui/reserve_after_initialization.rs @@ -1,19 +1,59 @@ #![warn(clippy::reserve_after_initialization)] +#![no_main] -fn main() { - // Should lint +// Should lint +fn standard() { let mut v1: Vec = vec![]; v1.reserve(10); +} - // Should lint +// Should lint +fn capacity_as_expr() { let capacity = 10; let mut v2: Vec = vec![]; v2.reserve(capacity); +} - // Shouldn't lint +// Shouldn't lint +fn vec_init_with_argument() { let mut v3 = vec![1]; v3.reserve(10); - - // Shouldn't lint - let mut v4: Vec = Vec::with_capacity(10); } + +// Shouldn't lint +fn called_with_capacity() { + let _v4: Vec = Vec::with_capacity(10); +} + +// Should lint +fn assign_expression() { + let mut v5: Vec = Vec::new(); + v5 = Vec::new(); + v5.reserve(10); +} + +/*fn in_macros() { + external! { + // Should lint + let mut v1: Vec = vec![]; + v1.reserve(10); + + // Should lint + let capacity = 10; + let mut v2: Vec = vec![]; + v2.reserve(capacity); + } + + with_span! { + span + + // Should lint + let mut v1: Vec = vec![]; + v1.reserve(10); + + // Should lint + let capacity = 10; + let mut v2: Vec = vec![]; + v2.reserve(capacity); + } +}*/ diff --git a/tests/ui/reserve_after_initialization.stderr b/tests/ui/reserve_after_initialization.stderr index ab2753cdd600..e50a8a065ba6 100644 --- a/tests/ui/reserve_after_initialization.stderr +++ b/tests/ui/reserve_after_initialization.stderr @@ -1,18 +1,25 @@ -error: calls to `reverse` immediately after creation - --> $DIR/reserve_after_initialization.rs:5:5 +error: call to `reserve` immediately after creation + --> $DIR/reserve_after_initialization.rs:6:5 | LL | / let mut v1: Vec = vec![]; LL | | v1.reserve(10); - | |___________________^ help: consider using `Vec::with_capacity(space_hint)`: `let mut v1: Vec = Vec::with_capacity(10);` + | |___________________^ help: consider using `Vec::with_capacity(/* Space hint */)`: `let mut v1: Vec = Vec::with_capacity(10);` | = note: `-D clippy::reserve-after-initialization` implied by `-D warnings` -error: calls to `reverse` immediately after creation - --> $DIR/reserve_after_initialization.rs:10:5 +error: call to `reserve` immediately after creation + --> $DIR/reserve_after_initialization.rs:13:5 | LL | / let mut v2: Vec = vec![]; LL | | v2.reserve(capacity); - | |_________________________^ help: consider using `Vec::with_capacity(space_hint)`: `let mut v2: Vec = Vec::with_capacity(capacity);` + | |_________________________^ help: consider using `Vec::with_capacity(/* Space hint */)`: `let mut v2: Vec = Vec::with_capacity(capacity);` -error: aborting due to 2 previous errors +error: call to `reserve` immediately after creation + --> $DIR/reserve_after_initialization.rs:31:5 + | +LL | / v5 = Vec::new(); +LL | | v5.reserve(10); + | |___________________^ help: consider using `Vec::with_capacity(/* Space hint */)`: `v5 = Vec::with_capacity(10);` + +error: aborting due to 3 previous errors From 7977d209b27c14769c8e50b5f189cd27a716be3e Mon Sep 17 00:00:00 2001 From: Red Rapious Date: Tue, 22 Aug 2023 19:36:58 +0200 Subject: [PATCH 7/9] Do not lint inside macros --- .../src/reserve_after_initialization.rs | 8 ++++-- tests/ui/reserve_after_initialization.fixed | 28 +++++++------------ tests/ui/reserve_after_initialization.rs | 28 +++++++------------ tests/ui/reserve_after_initialization.stderr | 6 ++-- 4 files changed, 28 insertions(+), 42 deletions(-) diff --git a/clippy_lints/src/reserve_after_initialization.rs b/clippy_lints/src/reserve_after_initialization.rs index 17ca9c8aab87..15f8c5da1060 100644 --- a/clippy_lints/src/reserve_after_initialization.rs +++ b/clippy_lints/src/reserve_after_initialization.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; -use clippy_utils::path_to_local_id; use clippy_utils::source::snippet; +use clippy_utils::{is_from_proc_macro, path_to_local_id}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, QPath, Stmt, StmtKind}; @@ -74,8 +74,9 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { && let PatKind::Binding(BindingAnnotation::MUT, id, _, None) = local.pat.kind && !in_external_macro(cx.sess(), local.span) && let Some(init) = get_vec_init_kind(cx, init_expr) - && !matches!(init, VecInitKind::WithExprCapacity(_)) - && !matches!(init, VecInitKind::WithConstCapacity(_)) + && !matches!(init, VecInitKind::WithExprCapacity(_) + | VecInitKind::WithConstCapacity(_) + ) { self.searcher = Some(VecReserveSearcher { local_id: id, @@ -116,6 +117,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind && let ExprKind::MethodCall(name, self_arg, [space_hint], _) = expr.kind && path_to_local_id(self_arg, searcher.local_id) + && !is_from_proc_macro(cx, expr) && name.ident.as_str() == "reserve" { self.searcher = Some(VecReserveSearcher { diff --git a/tests/ui/reserve_after_initialization.fixed b/tests/ui/reserve_after_initialization.fixed index 5ef848ed8cf4..0675277849ad 100644 --- a/tests/ui/reserve_after_initialization.fixed +++ b/tests/ui/reserve_after_initialization.fixed @@ -1,6 +1,10 @@ +//@aux-build:proc_macros.rs #![warn(clippy::reserve_after_initialization)] #![no_main] +extern crate proc_macros; +use proc_macros::{external, with_span}; + // Should lint fn standard() { let mut v1: Vec = Vec::with_capacity(10); @@ -29,28 +33,16 @@ fn assign_expression() { v5 = Vec::with_capacity(10); } -/*fn in_macros() { +fn in_macros() { external! { - // Should lint - let mut v1: Vec = vec![]; - v1.reserve(10); - - // Should lint - let capacity = 10; - let mut v2: Vec = vec![]; - v2.reserve(capacity); + let mut v: Vec = vec![]; + v.reserve(10); } with_span! { span - // Should lint - let mut v1: Vec = vec![]; - v1.reserve(10); - - // Should lint - let capacity = 10; - let mut v2: Vec = vec![]; - v2.reserve(capacity); + let mut v: Vec = vec![]; + v.reserve(10); } -}*/ +} diff --git a/tests/ui/reserve_after_initialization.rs b/tests/ui/reserve_after_initialization.rs index eba7bc8dab33..b57a8e162c53 100644 --- a/tests/ui/reserve_after_initialization.rs +++ b/tests/ui/reserve_after_initialization.rs @@ -1,6 +1,10 @@ +//@aux-build:proc_macros.rs #![warn(clippy::reserve_after_initialization)] #![no_main] +extern crate proc_macros; +use proc_macros::{external, with_span}; + // Should lint fn standard() { let mut v1: Vec = vec![]; @@ -32,28 +36,16 @@ fn assign_expression() { v5.reserve(10); } -/*fn in_macros() { +fn in_macros() { external! { - // Should lint - let mut v1: Vec = vec![]; - v1.reserve(10); - - // Should lint - let capacity = 10; - let mut v2: Vec = vec![]; - v2.reserve(capacity); + let mut v: Vec = vec![]; + v.reserve(10); } with_span! { span - // Should lint - let mut v1: Vec = vec![]; - v1.reserve(10); - - // Should lint - let capacity = 10; - let mut v2: Vec = vec![]; - v2.reserve(capacity); + let mut v: Vec = vec![]; + v.reserve(10); } -}*/ +} diff --git a/tests/ui/reserve_after_initialization.stderr b/tests/ui/reserve_after_initialization.stderr index e50a8a065ba6..4a6164d8ebc9 100644 --- a/tests/ui/reserve_after_initialization.stderr +++ b/tests/ui/reserve_after_initialization.stderr @@ -1,5 +1,5 @@ error: call to `reserve` immediately after creation - --> $DIR/reserve_after_initialization.rs:6:5 + --> $DIR/reserve_after_initialization.rs:10:5 | LL | / let mut v1: Vec = vec![]; LL | | v1.reserve(10); @@ -8,14 +8,14 @@ LL | | v1.reserve(10); = note: `-D clippy::reserve-after-initialization` implied by `-D warnings` error: call to `reserve` immediately after creation - --> $DIR/reserve_after_initialization.rs:13:5 + --> $DIR/reserve_after_initialization.rs:17:5 | LL | / let mut v2: Vec = vec![]; LL | | v2.reserve(capacity); | |_________________________^ help: consider using `Vec::with_capacity(/* Space hint */)`: `let mut v2: Vec = Vec::with_capacity(capacity);` error: call to `reserve` immediately after creation - --> $DIR/reserve_after_initialization.rs:31:5 + --> $DIR/reserve_after_initialization.rs:35:5 | LL | / v5 = Vec::new(); LL | | v5.reserve(10); From e9a222beb5153024c0c0f2491274272ab00c7d7a Mon Sep 17 00:00:00 2001 From: Red Rapious Date: Tue, 22 Aug 2023 23:41:06 +0200 Subject: [PATCH 8/9] Minor changes --- clippy_lints/src/reserve_after_initialization.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/reserve_after_initialization.rs b/clippy_lints/src/reserve_after_initialization.rs index 15f8c5da1060..7ba10c975950 100644 --- a/clippy_lints/src/reserve_after_initialization.rs +++ b/clippy_lints/src/reserve_after_initialization.rs @@ -74,9 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { && let PatKind::Binding(BindingAnnotation::MUT, id, _, None) = local.pat.kind && !in_external_macro(cx.sess(), local.span) && let Some(init) = get_vec_init_kind(cx, init_expr) - && !matches!(init, VecInitKind::WithExprCapacity(_) - | VecInitKind::WithConstCapacity(_) - ) + && !matches!(init, VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_)) { self.searcher = Some(VecReserveSearcher { local_id: id, @@ -93,13 +91,10 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { if self.searcher.is_none() && let ExprKind::Assign(left, right, _) = expr.kind && let ExprKind::Path(QPath::Resolved(None, path)) = left.kind - && let [_] = &path.segments && let Res::Local(id) = path.res && !in_external_macro(cx.sess(), expr.span) && let Some(init) = get_vec_init_kind(cx, right) - && !matches!(init, VecInitKind::WithExprCapacity(_) - | VecInitKind::WithConstCapacity(_) - ) + && !matches!(init, VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_)) { self.searcher = Some(VecReserveSearcher { local_id: id, @@ -122,7 +117,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { { self.searcher = Some(VecReserveSearcher { err_span: searcher.err_span.to(stmt.span), - space_hint: snippet(cx, space_hint.span, "..").to_string(), + space_hint: snippet(cx, space_hint.span, "..").into_owned(), .. searcher }); } else { From f3c58773026bf042142be2bf8ed1e8b8797a4f68 Mon Sep 17 00:00:00 2001 From: Red Rapious Date: Wed, 23 Aug 2023 13:46:12 +0200 Subject: [PATCH 9/9] Put `is_from_proc_macro` last --- clippy_lints/src/reserve_after_initialization.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/reserve_after_initialization.rs b/clippy_lints/src/reserve_after_initialization.rs index 7ba10c975950..0c8c904e3745 100644 --- a/clippy_lints/src/reserve_after_initialization.rs +++ b/clippy_lints/src/reserve_after_initialization.rs @@ -112,8 +112,8 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind && let ExprKind::MethodCall(name, self_arg, [space_hint], _) = expr.kind && path_to_local_id(self_arg, searcher.local_id) - && !is_from_proc_macro(cx, expr) && name.ident.as_str() == "reserve" + && !is_from_proc_macro(cx, expr) { self.searcher = Some(VecReserveSearcher { err_span: searcher.err_span.to(stmt.span),