|
1 |
| -use clippy_utils::diagnostics::span_lint_and_sugg; |
| 1 | +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; |
2 | 2 | use clippy_utils::source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context};
|
| 3 | +use clippy_utils::ty::is_copy; |
3 | 4 | use clippy_utils::visitors::for_each_expr;
|
4 | 5 | use clippy_utils::{
|
5 | 6 | SpanlessEq, can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified,
|
@@ -84,14 +85,21 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
|
84 | 85 | return;
|
85 | 86 | };
|
86 | 87 |
|
| 88 | + let lint_msg = format!("usage of `contains_key` followed by `insert` on a `{}`", map_ty.name()); |
87 | 89 | let mut app = Applicability::MachineApplicable;
|
88 | 90 | let map_str = snippet_with_context(cx, contains_expr.map.span, contains_expr.call_ctxt, "..", &mut app).0;
|
89 | 91 | let key_str = snippet_with_context(cx, contains_expr.key.span, contains_expr.call_ctxt, "..", &mut app).0;
|
| 92 | + |
90 | 93 | let sugg = if let Some(else_expr) = else_expr {
|
91 | 94 | let Some(else_search) = find_insert_calls(cx, &contains_expr, else_expr) else {
|
92 | 95 | return;
|
93 | 96 | };
|
94 | 97 |
|
| 98 | + if then_search.is_key_used_and_no_copy || else_search.is_key_used_and_no_copy { |
| 99 | + span_lint(cx, MAP_ENTRY, expr.span, lint_msg); |
| 100 | + return; |
| 101 | + } |
| 102 | + |
95 | 103 | if then_search.edits.is_empty() && else_search.edits.is_empty() {
|
96 | 104 | // No insertions
|
97 | 105 | return;
|
@@ -184,15 +192,7 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
|
184 | 192 | }
|
185 | 193 | };
|
186 | 194 |
|
187 |
| - span_lint_and_sugg( |
188 |
| - cx, |
189 |
| - MAP_ENTRY, |
190 |
| - expr.span, |
191 |
| - format!("usage of `contains_key` followed by `insert` on a `{}`", map_ty.name()), |
192 |
| - "try", |
193 |
| - sugg, |
194 |
| - app, |
195 |
| - ); |
| 195 | + span_lint_and_sugg(cx, MAP_ENTRY, expr.span, lint_msg, "try", sugg, app); |
196 | 196 | }
|
197 | 197 | }
|
198 | 198 |
|
@@ -364,6 +364,8 @@ struct InsertSearcher<'cx, 'tcx> {
|
364 | 364 | is_single_insert: bool,
|
365 | 365 | /// If the visitor has seen the map being used.
|
366 | 366 | is_map_used: bool,
|
| 367 | + /// If the visitor has seen the key being used. |
| 368 | + is_key_used: bool, |
367 | 369 | /// The locations where changes need to be made for the suggestion.
|
368 | 370 | edits: Vec<Edit<'tcx>>,
|
369 | 371 | /// A stack of loops the visitor is currently in.
|
@@ -505,6 +507,9 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> {
|
505 | 507 | _ if is_any_expr_in_map_used(self.cx, self.map, expr) => {
|
506 | 508 | self.is_map_used = true;
|
507 | 509 | },
|
| 510 | + _ if SpanlessEq::new(self.cx).eq_expr(self.key, expr) => { |
| 511 | + self.is_key_used = true; |
| 512 | + }, |
508 | 513 | _ => match expr.kind {
|
509 | 514 | ExprKind::If(cond_expr, then_expr, Some(else_expr)) => {
|
510 | 515 | self.is_single_insert = false;
|
@@ -582,6 +587,7 @@ struct InsertSearchResults<'tcx> {
|
582 | 587 | edits: Vec<Edit<'tcx>>,
|
583 | 588 | allow_insert_closure: bool,
|
584 | 589 | is_single_insert: bool,
|
| 590 | + is_key_used_and_no_copy: bool, |
585 | 591 | }
|
586 | 592 | impl<'tcx> InsertSearchResults<'tcx> {
|
587 | 593 | fn as_single_insertion(&self) -> Option<Insertion<'tcx>> {
|
@@ -699,17 +705,20 @@ fn find_insert_calls<'tcx>(
|
699 | 705 | in_tail_pos: true,
|
700 | 706 | is_single_insert: true,
|
701 | 707 | is_map_used: false,
|
| 708 | + is_key_used: false, |
702 | 709 | edits: Vec::new(),
|
703 | 710 | loops: Vec::new(),
|
704 | 711 | locals: HirIdSet::default(),
|
705 | 712 | };
|
706 | 713 | s.visit_expr(expr);
|
707 | 714 | let allow_insert_closure = s.allow_insert_closure;
|
708 | 715 | let is_single_insert = s.is_single_insert;
|
| 716 | + let is_key_used_and_no_copy = s.is_key_used && !is_copy(cx, cx.typeck_results().expr_ty(contains_expr.key)); |
709 | 717 | let edits = s.edits;
|
710 | 718 | s.can_use_entry.then_some(InsertSearchResults {
|
711 | 719 | edits,
|
712 | 720 | allow_insert_closure,
|
713 | 721 | is_single_insert,
|
| 722 | + is_key_used_and_no_copy, |
714 | 723 | })
|
715 | 724 | }
|
0 commit comments