Skip to content

Commit 816cc54

Browse files
committed
clean-up, add some comments
1 parent aa1fa10 commit 816cc54

File tree

10 files changed

+98
-89
lines changed

10 files changed

+98
-89
lines changed

clippy_lints/src/entry.rs

Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
8787

8888
let lint_msg = format!("usage of `contains_key` followed by `insert` on a `{}`", map_ty.name());
8989
let mut app = Applicability::MachineApplicable;
90-
let map_str = snippet_with_context(cx, contains_expr.map.span, contains_expr.call_ctxt, "..", &mut app).0;
91-
let key_str = snippet_with_context(cx, contains_expr.key.span, contains_expr.call_ctxt, "..", &mut app).0;
90+
let map_str = snippet_with_context(cx, contains_expr.map.span, contains_expr.call_ctxt, "(_)", &mut app).0;
91+
let key_str = snippet_with_context(cx, contains_expr.key.span, contains_expr.call_ctxt, "_", &mut app).0;
9292

9393
let sugg = if let Some(else_expr) = else_expr {
9494
let Some(else_search) = find_insert_calls(cx, &contains_expr, else_expr) else {
@@ -142,8 +142,11 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
142142
let indent_str = snippet_indent(cx, expr.span);
143143
let indent_str = indent_str.as_deref().unwrap_or("");
144144
Some(format!(
145-
"match {map_str}.entry({key_str}) {{\n{indent_str} {entry}::{then_entry} => {}\n\
146-
{indent_str} {entry}::{else_entry} => {}\n{indent_str}}}",
145+
"\
146+
match {map_str}.entry({key_str}) {{
147+
{indent_str} {entry}::{then_entry} => {}
148+
{indent_str} {entry}::{else_entry} => {}
149+
{indent_str}}}",
147150
reindent_multiline(&then_str, true, Some(4 + indent_str.len())),
148151
reindent_multiline(&else_str, true, Some(4 + indent_str.len())),
149152
entry = map_ty.entry_path(),
@@ -167,7 +170,7 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
167170
map_ty.entry_path(),
168171
))
169172
} else if let Some(insertion) = then_search.as_single_insertion() {
170-
let value_str = snippet_with_context(cx, insertion.value.span, then_expr.span.ctxt(), "..", &mut app).0;
173+
let value_str = snippet_with_context(cx, insertion.value.span, then_expr.span.ctxt(), "_", &mut app).0;
171174
if contains_expr.negated {
172175
if insertion.value.can_have_side_effects() {
173176
Some(format!("{map_str}.entry({key_str}).or_insert_with(|| {value_str});"))
@@ -312,15 +315,12 @@ struct InsertExpr<'tcx> {
312315
///
313316
/// If the given expression is not an `insert` call into a `BTreeMap` or a `HashMap`, return `None`.
314317
fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> {
315-
if let ExprKind::MethodCall(_, map, [key, value], _) = expr.kind {
316-
let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
317-
if let Some(insert) = cx.tcx.get_diagnostic_name(id)
318-
&& matches!(insert, sym::btreemap_insert | sym::hashmap_insert)
319-
{
320-
Some(InsertExpr { map, key, value })
321-
} else {
322-
None
323-
}
318+
if let ExprKind::MethodCall(_, map, [key, value], _) = expr.kind
319+
&& let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
320+
&& let Some(insert) = cx.tcx.get_diagnostic_name(id)
321+
&& matches!(insert, sym::btreemap_insert | sym::hashmap_insert)
322+
{
323+
Some(InsertExpr { map, key, value })
324324
} else {
325325
None
326326
}
@@ -524,15 +524,15 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> {
524524
ExprKind::If(cond_expr, then_expr, Some(else_expr)) => {
525525
self.is_single_insert = false;
526526
self.visit_non_tail_expr(cond_expr);
527-
// Each branch may contain it's own insert expression.
527+
// Each branch may contain its own insert expression.
528528
let mut is_map_used = self.visit_cond_arm(then_expr);
529529
is_map_used |= self.visit_cond_arm(else_expr);
530530
self.is_map_used = is_map_used;
531531
},
532532
ExprKind::Match(scrutinee_expr, arms, _) => {
533533
self.is_single_insert = false;
534534
self.visit_non_tail_expr(scrutinee_expr);
535-
// Each branch may contain it's own insert expression.
535+
// Each branch may contain its own insert expression.
536536
let mut is_map_used = self.is_map_used;
537537
for arm in arms {
538538
self.visit_pat(arm.pat);
@@ -609,6 +609,25 @@ impl<'tcx> InsertSearchResults<'tcx> {
609609
self.is_single_insert.then(|| self.edits[0].as_insertion().unwrap())
610610
}
611611

612+
/// Create a snippet with all the `insert`s on the map replaced with `insert`s on the entry.
613+
///
614+
/// `write_wrapped` will be called whenever the `insert` is an expression that is used, or has
615+
/// its type unified with another branch -- for example, in cases like:
616+
/// ```ignore
617+
/// let _ = if !m.contains(&k) {
618+
/// m.insert(k, v)
619+
/// } else {
620+
/// None
621+
/// };
622+
///
623+
/// let _ = if m.contains(&k) {
624+
/// if true { m.insert(k, v) } else { m.insert(k, v2) }
625+
/// } else {
626+
/// m.insert(k, v3)
627+
/// }
628+
/// ```
629+
/// The idea is that it will wrap the `insert` call so that it still type-checks with the code
630+
/// surrounding it.
612631
fn snippet(
613632
&self,
614633
cx: &LateContext<'_>,
@@ -619,6 +638,7 @@ impl<'tcx> InsertSearchResults<'tcx> {
619638
let ctxt = span.ctxt();
620639
let mut res = String::new();
621640
for insertion in self.edits.iter().filter_map(|e| e.as_insertion()) {
641+
// Take everything until the call verbatim
622642
res.push_str(&snippet_with_applicability(
623643
cx,
624644
span.until(insertion.call.span),
@@ -628,11 +648,8 @@ impl<'tcx> InsertSearchResults<'tcx> {
628648
if is_expr_used_or_unified(cx.tcx, insertion.call) {
629649
write_wrapped(&mut res, insertion, ctxt, app);
630650
} else {
631-
let _: fmt::Result = write!(
632-
res,
633-
"e.insert({})",
634-
snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0
635-
);
651+
let value_str = snippet_with_context(cx, insertion.value.span, ctxt, "_", app).0;
652+
let _: fmt::Result = write!(res, "e.insert({value_str})");
636653
}
637654
span = span.trim_start(insertion.call.span).unwrap_or(DUMMY_SP);
638655
}
@@ -644,11 +661,8 @@ impl<'tcx> InsertSearchResults<'tcx> {
644661
(
645662
self.snippet(cx, span, app, |res, insertion, ctxt, app| {
646663
// Insertion into a map would return `Some(&mut value)`, but the entry returns `&mut value`
647-
let _: fmt::Result = write!(
648-
res,
649-
"Some(e.insert({}))",
650-
snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0
651-
);
664+
let value_str = snippet_with_context(cx, insertion.value.span, ctxt, "_", app).0;
665+
let _: fmt::Result = write!(res, "Some(e.insert({value_str}))");
652666
}),
653667
"Occupied(mut e)",
654668
)
@@ -658,19 +672,15 @@ impl<'tcx> InsertSearchResults<'tcx> {
658672
(
659673
self.snippet(cx, span, app, |res, insertion, ctxt, app| {
660674
// Insertion into a map would return `None`, but the entry returns a mutable reference.
675+
let value_str = snippet_with_context(cx, insertion.value.span, ctxt, "_", app).0;
661676
let _: fmt::Result = if is_expr_final_block_expr(cx.tcx, insertion.call) {
662677
write!(
663678
res,
664-
"e.insert({});\n{}None",
665-
snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0,
666-
snippet_indent(cx, insertion.call.span).as_deref().unwrap_or(""),
679+
"e.insert({value_str});\n{indent}None",
680+
indent = snippet_indent(cx, insertion.call.span).as_deref().unwrap_or(""),
667681
)
668682
} else {
669-
write!(
670-
res,
671-
"{{ e.insert({}); None }}",
672-
snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0,
673-
)
683+
write!(res, "{{ e.insert({value_str}); None }}")
674684
};
675685
}),
676686
"Vacant(e)",
@@ -683,14 +693,15 @@ impl<'tcx> InsertSearchResults<'tcx> {
683693
for edit in &self.edits {
684694
match *edit {
685695
Edit::Insertion(insertion) => {
686-
// Cut out the value from `map.insert(key, value)`
696+
// Take everything until the call verbatim
687697
res.push_str(&snippet_with_applicability(
688698
cx,
689699
span.until(insertion.call.span),
690700
"..",
691701
app,
692702
));
693-
res.push_str(&snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0);
703+
let value_str = snippet_with_context(cx, insertion.value.span, ctxt, "_", app).0;
704+
res.push_str(&value_str);
694705
span = span.trim_start(insertion.call.span).unwrap_or(DUMMY_SP);
695706
},
696707
Edit::RemoveSemi(semi_span) => {

tests/ui/entry.fixed

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@needs-asm-support
22

3-
#![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)]
3+
#![allow(clippy::needless_pass_by_value, clippy::collapsible_if)]
44
#![warn(clippy::map_entry)]
55

66
use std::arch::asm;

tests/ui/entry.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@needs-asm-support
22

3-
#![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)]
3+
#![allow(clippy::needless_pass_by_value, clippy::collapsible_if)]
44
#![warn(clippy::map_entry)]
55

66
use std::arch::asm;

tests/ui/entry_btree.fixed

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#![warn(clippy::map_entry)]
2-
#![allow(dead_code)]
32

43
use std::collections::BTreeMap;
54

tests/ui/entry_btree.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#![warn(clippy::map_entry)]
2-
#![allow(dead_code)]
32

43
use std::collections::BTreeMap;
54

tests/ui/entry_btree.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: usage of `contains_key` followed by `insert` on a `BTreeMap`
2-
--> tests/ui/entry_btree.rs:10:5
2+
--> tests/ui/entry_btree.rs:9:5
33
|
44
LL | / if !m.contains_key(&k) {
55
LL | |

tests/ui/entry_unfixable.rs

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,40 +14,6 @@ macro_rules! insert {
1414
};
1515
}
1616

17-
mod issue13306 {
18-
use std::collections::HashMap;
19-
20-
struct Env {
21-
enclosing: Option<Box<Env>>,
22-
values: HashMap<String, usize>,
23-
}
24-
25-
impl Env {
26-
fn assign(&mut self, name: String, value: usize) -> bool {
27-
if !self.values.contains_key(&name) {
28-
//~^ map_entry
29-
self.values.insert(name, value);
30-
true
31-
} else if let Some(enclosing) = &mut self.enclosing {
32-
enclosing.assign(name, value)
33-
} else {
34-
false
35-
}
36-
}
37-
}
38-
}
39-
40-
fn issue9925(mut hm: HashMap<String, bool>) {
41-
let key = "hello".to_string();
42-
if hm.contains_key(&key) {
43-
//~^ map_entry
44-
let bval = hm.get_mut(&key).unwrap();
45-
*bval = false;
46-
} else {
47-
hm.insert(key, true);
48-
}
49-
}
50-
5117
mod issue9470 {
5218
use std::collections::HashMap;
5319
use std::sync::Mutex;
@@ -90,4 +56,38 @@ mod issue9470 {
9056
}
9157
}
9258

59+
fn issue9925(mut hm: HashMap<String, bool>) {
60+
let key = "hello".to_string();
61+
if hm.contains_key(&key) {
62+
//~^ map_entry
63+
let bval = hm.get_mut(&key).unwrap();
64+
*bval = false;
65+
} else {
66+
hm.insert(key, true);
67+
}
68+
}
69+
70+
mod issue13306 {
71+
use std::collections::HashMap;
72+
73+
struct Env {
74+
enclosing: Option<Box<Env>>,
75+
values: HashMap<String, usize>,
76+
}
77+
78+
impl Env {
79+
fn assign(&mut self, name: String, value: usize) -> bool {
80+
if !self.values.contains_key(&name) {
81+
//~^ map_entry
82+
self.values.insert(name, value);
83+
true
84+
} else if let Some(enclosing) = &mut self.enclosing {
85+
enclosing.assign(name, value)
86+
} else {
87+
false
88+
}
89+
}
90+
}
91+
}
92+
9393
fn main() {}

tests/ui/entry_unfixable.stderr

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
error: usage of `contains_key` followed by `insert` on a `HashMap`
2-
--> tests/ui/entry_unfixable.rs:27:13
2+
--> tests/ui/entry_unfixable.rs:46:13
33
|
4-
LL | / if !self.values.contains_key(&name) {
4+
LL | / if self.globals.contains_key(&name) {
55
LL | |
6-
LL | | self.values.insert(name, value);
7-
LL | | true
8-
... |
9-
LL | | false
6+
LL | | self.globals.insert(name, value);
7+
LL | | } else {
8+
LL | | let interner = INTERNER.lock().unwrap();
9+
LL | | return Err(interner.resolve(name).unwrap().to_owned());
1010
LL | | }
1111
| |_____________^
1212
|
@@ -15,7 +15,7 @@ LL | | }
1515
= help: to override `-D warnings` add `#[allow(clippy::map_entry)]`
1616

1717
error: usage of `contains_key` followed by `insert` on a `HashMap`
18-
--> tests/ui/entry_unfixable.rs:42:5
18+
--> tests/ui/entry_unfixable.rs:61:5
1919
|
2020
LL | / if hm.contains_key(&key) {
2121
LL | |
@@ -31,12 +31,12 @@ LL | | }
3131
error: usage of `contains_key` followed by `insert` on a `HashMap`
3232
--> tests/ui/entry_unfixable.rs:80:13
3333
|
34-
LL | / if self.globals.contains_key(&name) {
34+
LL | / if !self.values.contains_key(&name) {
3535
LL | |
36-
LL | | self.globals.insert(name, value);
37-
LL | | } else {
38-
LL | | let interner = INTERNER.lock().unwrap();
39-
LL | | return Err(interner.resolve(name).unwrap().to_owned());
36+
LL | | self.values.insert(name, value);
37+
LL | | true
38+
... |
39+
LL | | false
4040
LL | | }
4141
| |_____________^
4242
|

tests/ui/entry_with_else.fixed

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)]
1+
#![allow(clippy::needless_pass_by_value, clippy::collapsible_if)]
22
#![warn(clippy::map_entry)]
33

44
use std::collections::{BTreeMap, HashMap};

tests/ui/entry_with_else.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)]
1+
#![allow(clippy::needless_pass_by_value, clippy::collapsible_if)]
22
#![warn(clippy::map_entry)]
33

44
use std::collections::{BTreeMap, HashMap};

0 commit comments

Comments
 (0)