Skip to content

Commit 6eecd74

Browse files
committed
unnecessary_reserve: address review comments
1 parent 21b9876 commit 6eecd74

File tree

7 files changed

+67
-25
lines changed

7 files changed

+67
-25
lines changed

clippy_config/src/conf.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,7 @@ define_Conf! {
647647
unchecked_duration_subtraction,
648648
uninlined_format_args,
649649
unnecessary_lazy_evaluations,
650+
unnecessary_reserve,
650651
unnested_or_patterns,
651652
unused_trait_names,
652653
use_self,

clippy_lints/src/unnecessary_reserve.rs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use clippy_config::Conf;
22
use clippy_utils::diagnostics::span_lint_and_then;
33
use clippy_utils::msrvs::{self, Msrv};
4+
use clippy_utils::ty::adt_def_id;
45
use clippy_utils::visitors::for_each_expr;
56
use clippy_utils::{SpanlessEq, get_enclosing_block, match_def_path, paths};
67
use core::ops::ControlFlow;
78
use rustc_errors::Applicability;
89
use rustc_hir::{Block, Expr, ExprKind, PathSegment};
910
use rustc_lint::{LateContext, LateLintPass};
10-
use rustc_middle::ty;
1111
use rustc_session::impl_lint_pass;
1212
use rustc_span::sym;
1313

@@ -16,7 +16,7 @@ declare_clippy_lint! {
1616
///
1717
/// This lint checks for a call to `reserve` before `extend` on a `Vec` or `VecDeque`.
1818
/// ### Why is this bad?
19-
/// Since Rust 1.62, `extend` implicitly calls `reserve`
19+
/// `extend` implicitly calls `reserve`
2020
///
2121
/// ### Example
2222
/// ```rust
@@ -31,9 +31,9 @@ declare_clippy_lint! {
3131
/// let array: &[usize] = &[1, 2];
3232
/// vec.extend(array);
3333
/// ```
34-
#[clippy::version = "1.64.0"]
34+
#[clippy::version = "1.86.0"]
3535
pub UNNECESSARY_RESERVE,
36-
pedantic,
36+
complexity,
3737
"calling `reserve` before `extend` on a `Vec` or `VecDeque`, when it will be called implicitly"
3838
}
3939

@@ -84,13 +84,11 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryReserve {
8484
}
8585

8686
fn acceptable_type(cx: &LateContext<'_>, struct_calling_on: &Expr<'_>) -> bool {
87-
let acceptable_types = [sym::Vec, sym::VecDeque];
88-
acceptable_types.iter().any(|&acceptable_ty| {
89-
match cx.typeck_results().expr_ty(struct_calling_on).peel_refs().kind() {
90-
ty::Adt(def, _) => cx.tcx.is_diagnostic_item(acceptable_ty, def.did()),
91-
_ => false,
92-
}
93-
})
87+
if let Some(did) = adt_def_id(cx.typeck_results().expr_ty_adjusted(struct_calling_on)) {
88+
matches!(cx.tcx.get_diagnostic_name(did), Some(sym::Vec | sym::VecDeque))
89+
} else {
90+
false
91+
}
9492
}
9593

9694
#[must_use]
@@ -100,19 +98,26 @@ fn check_extend_method<'tcx>(
10098
struct_expr: &Expr<'tcx>,
10199
args_a: &Expr<'tcx>,
102100
) -> Option<rustc_span::Span> {
103-
let args_a_kind = &args_a.kind;
101+
let mut found_reserve = false;
104102
let mut read_found = false;
105103
let mut spanless_eq = SpanlessEq::new(cx);
106104

107105
let _: Option<!> = for_each_expr(cx, block, |expr: &Expr<'tcx>| {
106+
if !found_reserve {
107+
if expr.hir_id == args_a.hir_id {
108+
found_reserve = true;
109+
}
110+
return ControlFlow::Continue(());
111+
}
112+
108113
if let ExprKind::MethodCall(_, struct_calling_on, _, _) = expr.kind
109114
&& let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
110115
&& let ExprKind::MethodCall(
111116
PathSegment {
112117
ident: method_call_a, ..
113118
},
114119
..,
115-
) = args_a_kind
120+
) = args_a.kind
116121
&& method_call_a.name == sym::len
117122
&& match_def_path(cx, expr_def_id, &paths::ITER_EXTEND)
118123
&& acceptable_type(cx, struct_calling_on)

clippy_utils/src/ty/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,3 +1352,8 @@ pub fn option_arg_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
13521352
_ => None,
13531353
}
13541354
}
1355+
1356+
/// Check if `ty` with references peeled is an `Adt` and return its `DefId`.
1357+
pub fn adt_def_id(ty: Ty<'_>) -> Option<DefId> {
1358+
ty.peel_refs().ty_adt_def().map(AdtDef::did)
1359+
}

clippy_utils/src/ty/type_certainty/mod.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@
1111
//! As a heuristic, `expr_type_is_certain` may produce false negatives, but a false positive should
1212
//! be considered a bug.
1313
14+
use super::adt_def_id;
1415
use crate::def_path_res;
1516
use rustc_hir::def::{DefKind, Res};
1617
use rustc_hir::def_id::DefId;
1718
use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_qpath, walk_ty};
1819
use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, GenericArgs, HirId, Node, PathSegment, QPath, TyKind};
1920
use rustc_lint::LateContext;
20-
use rustc_middle::ty::{self, AdtDef, GenericArgKind, Ty};
21+
use rustc_middle::ty::{self, GenericArgKind, Ty};
2122
use rustc_span::{Span, Symbol};
2223

2324
mod certainty;
@@ -313,10 +314,6 @@ fn self_ty<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId) -> Ty<'tcx> {
313314
cx.tcx.fn_sig(method_def_id).skip_binder().inputs().skip_binder()[0]
314315
}
315316

316-
fn adt_def_id(ty: Ty<'_>) -> Option<DefId> {
317-
ty.peel_refs().ty_adt_def().map(AdtDef::did)
318-
}
319-
320317
fn contains_param(ty: Ty<'_>, index: u32) -> bool {
321318
ty.walk()
322319
.any(|arg| matches!(arg.unpack(), GenericArgKind::Type(ty) if ty.is_param(index)))

tests/ui/unnecessary_reserve.fixed

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ fn main() {
99
vec_deque_reserve();
1010
hash_map_reserve();
1111
msrv_1_62();
12+
box_vec_reserve();
1213
}
1314

1415
fn vec_reserve() {
@@ -97,3 +98,12 @@ fn msrv_1_62() {
9798
vec_deque.reserve(1);
9899
vec_deque.extend([1]);
99100
}
101+
102+
fn box_vec_reserve() {
103+
let mut vec: Box<Vec<usize>> = Box::default();
104+
let array: &[usize] = &[1, 2];
105+
106+
// do lint
107+
;
108+
vec.extend(array);
109+
}

tests/ui/unnecessary_reserve.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ fn main() {
99
vec_deque_reserve();
1010
hash_map_reserve();
1111
msrv_1_62();
12+
box_vec_reserve();
1213
}
1314

1415
fn vec_reserve() {
@@ -98,3 +99,12 @@ fn msrv_1_62() {
9899
vec_deque.reserve(1);
99100
vec_deque.extend([1]);
100101
}
102+
103+
fn box_vec_reserve() {
104+
let mut vec: Box<Vec<usize>> = Box::default();
105+
let array: &[usize] = &[1, 2];
106+
107+
// do lint
108+
vec.reserve(array.len());
109+
vec.extend(array);
110+
}

tests/ui/unnecessary_reserve.stderr

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | #[allow(clippy::unnecessary_operation)]
77
= note: `#[deny(clippy::useless_attribute)]` on by default
88

99
error: unnecessary call to `reserve`
10-
--> tests/ui/unnecessary_reserve.rs:14:18
10+
--> tests/ui/unnecessary_reserve.rs:15:18
1111
|
1212
LL | fn vec_reserve() {
1313
| __________________^
@@ -26,7 +26,7 @@ LL | | }
2626
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_reserve)]`
2727

2828
error: unnecessary call to `reserve`
29-
--> tests/ui/unnecessary_reserve.rs:14:18
29+
--> tests/ui/unnecessary_reserve.rs:15:18
3030
|
3131
LL | fn vec_reserve() {
3232
| __________________^
@@ -42,7 +42,7 @@ LL | | }
4242
| |_^
4343

4444
error: unnecessary call to `reserve`
45-
--> tests/ui/unnecessary_reserve.rs:32:5
45+
--> tests/ui/unnecessary_reserve.rs:33:5
4646
|
4747
LL | / {
4848
LL | | vec.reserve(array1.len());
@@ -52,7 +52,7 @@ LL | | };
5252
| |_____^
5353

5454
error: unnecessary call to `reserve`
55-
--> tests/ui/unnecessary_reserve.rs:14:18
55+
--> tests/ui/unnecessary_reserve.rs:15:18
5656
|
5757
LL | fn vec_reserve() {
5858
| __________________^
@@ -68,7 +68,7 @@ LL | | }
6868
| |_^
6969

7070
error: call to `reserve` immediately after creation
71-
--> tests/ui/unnecessary_reserve.rs:43:5
71+
--> tests/ui/unnecessary_reserve.rs:44:5
7272
|
7373
LL | / let mut other_vec: Vec<usize> = vec![];
7474
LL | | other_vec.reserve(1);
@@ -78,7 +78,7 @@ LL | | other_vec.reserve(1);
7878
= help: to override `-D warnings` add `#[allow(clippy::reserve_after_initialization)]`
7979

8080
error: unnecessary call to `reserve`
81-
--> tests/ui/unnecessary_reserve.rs:48:24
81+
--> tests/ui/unnecessary_reserve.rs:49:24
8282
|
8383
LL | fn vec_deque_reserve() {
8484
| ________________________^
@@ -92,5 +92,19 @@ LL | | vec_deque.extend([1])
9292
LL | | }
9393
| |_^
9494

95-
error: aborting due to 7 previous errors
95+
error: unnecessary call to `reserve`
96+
--> tests/ui/unnecessary_reserve.rs:103:22
97+
|
98+
LL | fn box_vec_reserve() {
99+
| ______________________^
100+
LL | | let mut vec: Box<Vec<usize>> = Box::default();
101+
LL | | let array: &[usize] = &[1, 2];
102+
... |
103+
LL | | vec.reserve(array.len());
104+
| | ------------------------ help: remove this line
105+
LL | | vec.extend(array);
106+
LL | | }
107+
| |_^
108+
109+
error: aborting due to 8 previous errors
96110

0 commit comments

Comments
 (0)