Skip to content

Commit d8ecde0

Browse files
authoredFeb 19, 2025
fix: map_entry FP on struct member (rust-lang#14151)
fixes rust-lang#13934 I modified the part for checking if the map is used so that it can check field and index exprs. changelog: [`map_entry`]: fix FP on struct member
2 parents 975a813 + e2cdfed commit d8ecde0

File tree

3 files changed

+62
-1
lines changed

3 files changed

+62
-1
lines changed
 

‎clippy_lints/src/entry.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context};
3+
use clippy_utils::visitors::for_each_expr;
34
use clippy_utils::{
45
SpanlessEq, can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified,
56
peel_hir_expr_while,
@@ -12,6 +13,7 @@ use rustc_hir::{Block, Expr, ExprKind, HirId, Pat, Stmt, StmtKind, UnOp};
1213
use rustc_lint::{LateContext, LateLintPass};
1314
use rustc_session::declare_lint_pass;
1415
use rustc_span::{DUMMY_SP, Span, SyntaxContext, sym};
16+
use std::ops::ControlFlow;
1517

1618
declare_clippy_lint! {
1719
/// ### What it does
@@ -500,7 +502,7 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> {
500502
self.visit_non_tail_expr(insert_expr.value);
501503
self.is_single_insert = is_single_insert;
502504
},
503-
_ if SpanlessEq::new(self.cx).eq_expr(self.map, expr) => {
505+
_ if is_any_expr_in_map_used(self.cx, self.map, expr) => {
504506
self.is_map_used = true;
505507
},
506508
_ => match expr.kind {
@@ -562,6 +564,19 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> {
562564
}
563565
}
564566

567+
/// Check if the given expression is used for each sub-expression in the given map.
568+
/// For example, in map `a.b.c.my_map`, The expression `a.b.c.my_map`, `a.b.c`, `a.b`, and `a` are
569+
/// all checked.
570+
fn is_any_expr_in_map_used<'tcx>(cx: &LateContext<'tcx>, map: &'tcx Expr<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
571+
for_each_expr(cx, map, |e| {
572+
if SpanlessEq::new(cx).eq_expr(e, expr) {
573+
return ControlFlow::Break(());
574+
}
575+
ControlFlow::Continue(())
576+
})
577+
.is_some()
578+
}
579+
565580
struct InsertSearchResults<'tcx> {
566581
edits: Vec<Edit<'tcx>>,
567582
allow_insert_closure: bool,

‎tests/ui/entry.fixed

+23
Original file line numberDiff line numberDiff line change
@@ -195,4 +195,27 @@ fn issue12489(map: &mut HashMap<u64, u64>) -> Option<()> {
195195
Some(())
196196
}
197197

198+
mod issue13934 {
199+
use std::collections::HashMap;
200+
201+
struct Member {}
202+
203+
pub struct Foo {
204+
members: HashMap<u8, Member>,
205+
}
206+
207+
impl Foo {
208+
pub fn should_also_not_cause_lint(&mut self, input: u8) {
209+
if self.members.contains_key(&input) {
210+
todo!();
211+
} else {
212+
self.other();
213+
self.members.insert(input, Member {});
214+
}
215+
}
216+
217+
fn other(&self) {}
218+
}
219+
}
220+
198221
fn main() {}

‎tests/ui/entry.rs

+23
Original file line numberDiff line numberDiff line change
@@ -201,4 +201,27 @@ fn issue12489(map: &mut HashMap<u64, u64>) -> Option<()> {
201201
Some(())
202202
}
203203

204+
mod issue13934 {
205+
use std::collections::HashMap;
206+
207+
struct Member {}
208+
209+
pub struct Foo {
210+
members: HashMap<u8, Member>,
211+
}
212+
213+
impl Foo {
214+
pub fn should_also_not_cause_lint(&mut self, input: u8) {
215+
if self.members.contains_key(&input) {
216+
todo!();
217+
} else {
218+
self.other();
219+
self.members.insert(input, Member {});
220+
}
221+
}
222+
223+
fn other(&self) {}
224+
}
225+
}
226+
204227
fn main() {}

0 commit comments

Comments
 (0)
Please sign in to comment.