11use clippy_config:: Conf ;
22use clippy_utils:: diagnostics:: span_lint_and_then;
33use clippy_utils:: msrvs:: { self , Msrv } ;
4+ use clippy_utils:: ty:: adt_def_id;
45use clippy_utils:: visitors:: for_each_expr;
56use clippy_utils:: { SpanlessEq , get_enclosing_block, match_def_path, paths} ;
67use core:: ops:: ControlFlow ;
78use rustc_errors:: Applicability ;
89use rustc_hir:: { Block , Expr , ExprKind , PathSegment } ;
910use rustc_lint:: { LateContext , LateLintPass } ;
10- use rustc_middle:: ty;
1111use rustc_session:: impl_lint_pass;
1212use 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
8686fn 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)
0 commit comments