|
1 | 1 | use clippy_utils::diagnostics::span_lint_and_note; |
2 | | -use clippy_utils::{is_uninit_ty_valid, match_def_path, path_to_local_id, paths, peel_hir_expr_while, SpanlessEq}; |
| 2 | +use clippy_utils::ty::is_type_diagnostic_item; |
| 3 | +use clippy_utils::{ |
| 4 | + match_def_path, path_to_local_id, paths, peel_hir_expr_while, ty::is_uninit_value_valid_for_ty, SpanlessEq, |
| 5 | +}; |
3 | 6 | use rustc_hir::def::Res; |
4 | 7 | use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; |
5 | 8 | use rustc_lint::{LateContext, LateLintPass}; |
6 | 9 | use rustc_middle::ty; |
7 | 10 | use rustc_session::{declare_lint_pass, declare_tool_lint}; |
8 | | -use rustc_span::Span; |
| 11 | +use rustc_span::{sym, Span}; |
9 | 12 |
|
10 | 13 | declare_clippy_lint! { |
11 | 14 | /// ### What it does |
@@ -44,32 +47,36 @@ impl<'tcx> LateLintPass<'tcx> for UninitVec { |
44 | 47 | fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { |
45 | 48 | for w in block.stmts.windows(2) { |
46 | 49 | if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = w[1].kind { |
47 | | - handle_pair(cx, &w[0], expr); |
| 50 | + handle_uninit_vec_pair(cx, &w[0], expr); |
48 | 51 | } |
49 | 52 | } |
50 | 53 |
|
51 | 54 | if let (Some(stmt), Some(expr)) = (block.stmts.last(), block.expr) { |
52 | | - handle_pair(cx, stmt, expr); |
| 55 | + handle_uninit_vec_pair(cx, stmt, expr); |
53 | 56 | } |
54 | 57 | } |
55 | 58 | } |
56 | 59 |
|
57 | | -fn handle_pair(cx: &LateContext<'tcx>, first: &'tcx Stmt<'tcx>, second: &'tcx Expr<'tcx>) { |
| 60 | +fn handle_uninit_vec_pair( |
| 61 | + cx: &LateContext<'tcx>, |
| 62 | + maybe_with_capacity_or_reserve: &'tcx Stmt<'tcx>, |
| 63 | + maybe_set_len: &'tcx Expr<'tcx>, |
| 64 | +) { |
58 | 65 | if_chain! { |
59 | | - if let Some(vec) = extract_with_capacity_or_reserve_target(cx, first); |
60 | | - if let Some((set_len_self, call_span)) = extract_set_len_self(cx, second); |
| 66 | + if let Some(vec) = extract_with_capacity_or_reserve_target(cx, maybe_with_capacity_or_reserve); |
| 67 | + if let Some((set_len_self, call_span)) = extract_set_len_self(cx, maybe_set_len); |
61 | 68 | if vec.eq_expr(cx, set_len_self); |
62 | 69 | if let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind(); |
63 | 70 | if let ty::Adt(_, substs) = vec_ty.kind(); |
64 | 71 | // Check T of Vec<T> |
65 | | - if !is_uninit_ty_valid(cx, substs.type_at(0)); |
| 72 | + if !is_uninit_value_valid_for_ty(cx, substs.type_at(0)); |
66 | 73 | then { |
67 | 74 | span_lint_and_note( |
68 | 75 | cx, |
69 | 76 | UNINIT_VEC, |
70 | 77 | call_span, |
71 | 78 | "calling `set_len()` immediately after reserving a buffer creates uninitialized values", |
72 | | - Some(first.span), |
| 79 | + Some(maybe_with_capacity_or_reserve.span), |
73 | 80 | "the buffer is reserved here" |
74 | 81 | ); |
75 | 82 | } |
@@ -113,16 +120,14 @@ fn extract_with_capacity_or_reserve_target(cx: &LateContext<'_>, stmt: &'tcx Stm |
113 | 120 | // self.vec = Vec::with_capacity() |
114 | 121 | Some(LocalOrExpr::Expr(lhs)) |
115 | 122 | }, |
116 | | - ExprKind::MethodCall(_, _, [vec_expr, _], _) => { |
| 123 | + ExprKind::MethodCall(path, _, [self_expr, _], _) => { |
117 | 124 | // self.vec.reserve() |
118 | | - if_chain! { |
119 | | - if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); |
120 | | - if match_def_path(cx, id, &paths::VEC_RESERVE); |
121 | | - then { |
122 | | - Some(LocalOrExpr::Expr(vec_expr)) |
123 | | - } else { |
124 | | - None |
125 | | - } |
| 125 | + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), sym::vec_type) |
| 126 | + && path.ident.name.as_str() == "reserve" |
| 127 | + { |
| 128 | + Some(LocalOrExpr::Expr(self_expr)) |
| 129 | + } else { |
| 130 | + None |
126 | 131 | } |
127 | 132 | }, |
128 | 133 | _ => None, |
|
0 commit comments