Skip to content

Commit b0bd621

Browse files
committed
Simplified code and added tests
1 parent a1bf23f commit b0bd621

File tree

4 files changed

+66
-120
lines changed

4 files changed

+66
-120
lines changed

clippy_lints/src/reserve_after_initialization.rs

Lines changed: 26 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::higher::{get_vec_init_kind, VecInitKind};
3+
use clippy_utils::path_to_local_id;
34
use clippy_utils::source::snippet;
4-
use clippy_utils::visitors::for_each_local_use_after_expr;
5-
use clippy_utils::{get_parent_expr, path_to_local_id};
6-
use core::ops::ControlFlow;
7-
use rustc_ast::LitKind;
5+
//use rustc_ast::LitKind;
86
use rustc_errors::Applicability;
97
use rustc_hir::def::Res;
10-
use rustc_hir::{
11-
BindingAnnotation, Block, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp,
12-
};
8+
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, QPath, Stmt, StmtKind};
139
use rustc_lint::{LateContext, LateLintPass, LintContext};
1410
use rustc_middle::lint::in_external_macro;
1511
use rustc_session::{declare_tool_lint, impl_lint_pass};
16-
use rustc_span::{Span, Symbol};
12+
use rustc_span::Span;
1713

1814
declare_clippy_lint! {
1915
/// ### What it does
@@ -45,89 +41,17 @@ pub struct ReserveAfterInitialization {
4541

4642
struct VecReserveSearcher {
4743
local_id: HirId,
48-
lhs_is_let: bool,
49-
let_ty_span: Option<Span>,
50-
name: Symbol,
5144
err_span: Span,
52-
last_reserve_expr: HirId,
53-
space_hint: Option<usize>,
45+
init_part: String,
46+
space_hint: String,
5447
}
5548
impl VecReserveSearcher {
5649
fn display_err(&self, cx: &LateContext<'_>) {
57-
if self.space_hint == Some(0) {
50+
if self.space_hint.is_empty() {
5851
return;
5952
}
6053

61-
let mut needs_mut = false;
62-
let _res = for_each_local_use_after_expr(cx, self.local_id, self.last_reserve_expr, |e| {
63-
let Some(parent) = get_parent_expr(cx, e) else {
64-
return ControlFlow::Continue(());
65-
};
66-
let adjusted_ty = cx.typeck_results().expr_ty_adjusted(e);
67-
let adjusted_mut = adjusted_ty.ref_mutability().unwrap_or(Mutability::Not);
68-
needs_mut |= adjusted_mut == Mutability::Mut;
69-
match parent.kind {
70-
ExprKind::AddrOf(_, Mutability::Mut, _) => {
71-
needs_mut = true;
72-
return ControlFlow::Break(true);
73-
},
74-
ExprKind::Unary(UnOp::Deref, _) | ExprKind::Index(..) if !needs_mut => {
75-
let mut last_place = parent;
76-
while let Some(parent) = get_parent_expr(cx, last_place) {
77-
if matches!(parent.kind, ExprKind::Unary(UnOp::Deref, _) | ExprKind::Field(..))
78-
|| matches!(parent.kind, ExprKind::Index(e, _, _) if e.hir_id == last_place.hir_id)
79-
{
80-
last_place = parent;
81-
} else {
82-
break;
83-
}
84-
}
85-
needs_mut |= cx.typeck_results().expr_ty_adjusted(last_place).ref_mutability()
86-
== Some(Mutability::Mut)
87-
|| get_parent_expr(cx, last_place)
88-
.map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(_, Mutability::Mut, _)));
89-
},
90-
ExprKind::MethodCall(_, recv, ..)
91-
if recv.hir_id == e.hir_id
92-
&& adjusted_mut == Mutability::Mut
93-
&& !adjusted_ty.peel_refs().is_slice() =>
94-
{
95-
// No need to set `needs_mut` to true. The receiver will be either explicitly borrowed, or it will
96-
// be implicitly borrowed via an adjustment. Both of these cases are already handled by this point.
97-
return ControlFlow::Break(true);
98-
},
99-
ExprKind::Assign(lhs, ..) if e.hir_id == lhs.hir_id => {
100-
needs_mut = true;
101-
return ControlFlow::Break(false);
102-
},
103-
_ => (),
104-
}
105-
ControlFlow::Continue(())
106-
});
107-
108-
let mut s = if self.lhs_is_let {
109-
String::from("let ")
110-
} else {
111-
String::new()
112-
};
113-
if needs_mut {
114-
s.push_str("mut ");
115-
}
116-
s.push_str(self.name.as_str());
117-
if let Some(span) = self.let_ty_span {
118-
s.push_str(": ");
119-
s.push_str(&snippet(cx, span, "_"));
120-
}
121-
s.push_str(
122-
format!(
123-
" = Vec::with_capacity({});",
124-
match self.space_hint {
125-
None => "..".to_string(),
126-
Some(hint) => hint.to_string(),
127-
}
128-
)
129-
.as_str(),
130-
);
54+
let s = format!("{} = Vec::with_capacity({});", self.init_part, self.space_hint);
13155

13256
span_lint_and_sugg(
13357
cx,
@@ -148,19 +72,22 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization {
14872

14973
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
15074
if let Some(init_expr) = local.init
151-
&& let PatKind::Binding(BindingAnnotation::MUT, id, name, None) = local.pat.kind
75+
&& let PatKind::Binding(BindingAnnotation::MUT, id, _name, None) = local.pat.kind
15276
&& !in_external_macro(cx.sess(), local.span)
15377
&& let Some(init) = get_vec_init_kind(cx, init_expr)
15478
&& !matches!(init, VecInitKind::WithExprCapacity(_))
79+
&& !matches!(init, VecInitKind::WithConstCapacity(_))
15580
{
15681
self.searcher = Some(VecReserveSearcher {
15782
local_id: id,
158-
lhs_is_let: true,
159-
name: name.name,
160-
let_ty_span: local.ty.map(|ty| ty.span),
16183
err_span: local.span,
162-
last_reserve_expr: init_expr.hir_id,
163-
space_hint: Some(0)
84+
init_part: format!("let {}: {}",
85+
snippet(cx, local.pat.span, ""),
86+
match local.ty {
87+
Some(type_inference) => snippet(cx, type_inference.span, "").to_string(),
88+
None => String::new()
89+
}),
90+
space_hint: String::new()
16491
});
16592
}
16693
}
@@ -169,20 +96,18 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization {
16996
if self.searcher.is_none()
17097
&& let ExprKind::Assign(left, right, _) = expr.kind
17198
&& let ExprKind::Path(QPath::Resolved(None, path)) = left.kind
172-
&& let [name] = &path.segments
99+
&& let [_name] = &path.segments
173100
&& let Res::Local(id) = path.res
174101
&& !in_external_macro(cx.sess(), expr.span)
175102
&& let Some(init) = get_vec_init_kind(cx, right)
176103
&& !matches!(init, VecInitKind::WithExprCapacity(_))
104+
&& !matches!(init, VecInitKind::WithConstCapacity(_))
177105
{
178106
self.searcher = Some(VecReserveSearcher {
179107
local_id: id,
180-
lhs_is_let: false,
181-
let_ty_span: None,
182-
name: name.ident.name,
183108
err_span: expr.span,
184-
last_reserve_expr: expr.hir_id,
185-
space_hint: Some(0)
109+
init_part: snippet(cx, left.span, "").to_string(),
110+
space_hint: String::new()
186111
});
187112
}
188113
}
@@ -195,22 +120,11 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization {
195120
&& path_to_local_id(self_arg, searcher.local_id)
196121
&& name.ident.as_str() == "reserve"
197122
{
198-
if let ExprKind::Lit(lit) = other_args[0].kind
199-
&& let LitKind::Int(space_hint, _) = lit.node {
200-
self.searcher = Some(VecReserveSearcher {
201-
err_span: searcher.err_span.to(stmt.span),
202-
last_reserve_expr: expr.hir_id,
203-
space_hint: Some(space_hint as usize), // the expression is an int, so we'll display the good amount as a hint
204-
.. searcher
205-
});
206-
} else {
207-
self.searcher = Some(VecReserveSearcher {
208-
err_span: searcher.err_span.to(stmt.span),
209-
last_reserve_expr: expr.hir_id,
210-
space_hint: None, // the expression isn't an int, so we'll display ".." as hint
211-
.. searcher
212-
});
213-
}
123+
self.searcher = Some(VecReserveSearcher {
124+
err_span: searcher.err_span.to(stmt.span),
125+
space_hint: snippet(cx, other_args[0].span, "").to_string(),
126+
.. searcher
127+
});
214128
} else {
215129
searcher.display_err(cx);
216130
}
Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
#![warn(clippy::reserve_after_initialization)]
22

33
fn main() {
4-
let v: Vec<usize> = Vec::with_capacity(10);
4+
// Should lint
5+
let mut v1: Vec<usize> = Vec::with_capacity(10);
6+
7+
// Should lint
8+
let capacity = 10;
9+
let mut v2: Vec<usize> = Vec::with_capacity(capacity);
10+
11+
// Shouldn't lint
12+
let mut v3 = vec![1];
13+
v3.reserve(10);
14+
15+
// Shouldn't lint
16+
let mut v4: Vec<usize> = Vec::with_capacity(10);
517
}
Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
#![warn(clippy::reserve_after_initialization)]
22

33
fn main() {
4-
let mut v: Vec<usize> = vec![];
5-
v.reserve(10);
4+
// Should lint
5+
let mut v1: Vec<usize> = vec![];
6+
v1.reserve(10);
7+
8+
// Should lint
9+
let capacity = 10;
10+
let mut v2: Vec<usize> = vec![];
11+
v2.reserve(capacity);
12+
13+
// Shouldn't lint
14+
let mut v3 = vec![1];
15+
v3.reserve(10);
16+
17+
// Shouldn't lint
18+
let mut v4: Vec<usize> = Vec::with_capacity(10);
619
}
Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
error: calls to `reverse` immediately after creation
2-
--> $DIR/reserve_after_initialization.rs:4:5
2+
--> $DIR/reserve_after_initialization.rs:5:5
33
|
4-
LL | / let mut v: Vec<usize> = vec![];
5-
LL | | v.reserve(10);
6-
| |__________________^ help: consider using `Vec::with_capacity(space_hint)`: `let v: Vec<usize> = Vec::with_capacity(10);`
4+
LL | / let mut v1: Vec<usize> = vec![];
5+
LL | | v1.reserve(10);
6+
| |___________________^ help: consider using `Vec::with_capacity(space_hint)`: `let mut v1: Vec<usize> = Vec::with_capacity(10);`
77
|
88
= note: `-D clippy::reserve-after-initialization` implied by `-D warnings`
99

10-
error: aborting due to previous error
10+
error: calls to `reverse` immediately after creation
11+
--> $DIR/reserve_after_initialization.rs:10:5
12+
|
13+
LL | / let mut v2: Vec<usize> = vec![];
14+
LL | | v2.reserve(capacity);
15+
| |_________________________^ help: consider using `Vec::with_capacity(space_hint)`: `let mut v2: Vec<usize> = Vec::with_capacity(capacity);`
16+
17+
error: aborting due to 2 previous errors
1118

0 commit comments

Comments
 (0)