rust/tests/ui/entry.fixed
Ethiraric 03bb7908b9 [map_entry]: Check insert expression for map use
The lint makes sure that the map is not used (borrowed) before the call
to `insert`. Since the lint creates a mutable borrow on the map with the
`Entry`, it wouldn't be possible to replace such code with `Entry`.
However, expressions up to the `insert` call are checked, but not
expressions for the arguments of the `insert` call itself. This commit
fixes that.

Fixes #11935
2024-02-27 15:20:49 +01:00

180 lines
3.7 KiB
Rust

//@needs-asm-support
#![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)]
#![warn(clippy::map_entry)]
use std::arch::asm;
use std::collections::HashMap;
use std::hash::Hash;
macro_rules! m {
($e:expr) => {{ $e }};
}
macro_rules! insert {
($map:expr, $key:expr, $val:expr) => {
$map.insert($key, $val)
};
}
fn foo() {}
fn hash_map<K: Eq + Hash + Copy, V: Copy>(m: &mut HashMap<K, V>, m2: &mut HashMap<K, V>, k: K, k2: K, v: V, v2: V) {
// or_insert(v)
m.entry(k).or_insert(v);
// semicolon on insert, use or_insert_with(..)
m.entry(k).or_insert_with(|| {
if true {
v
} else {
v2
}
});
// semicolon on if, use or_insert_with(..)
m.entry(k).or_insert_with(|| {
if true {
v
} else {
v2
}
});
// early return, use if let
if let std::collections::hash_map::Entry::Vacant(e) = m.entry(k) {
if true {
e.insert(v);
} else {
e.insert(v2);
return;
}
}
// use or_insert_with(..)
m.entry(k).or_insert_with(|| {
foo();
v
});
// semicolon on insert and match, use or_insert_with(..)
m.entry(k).or_insert_with(|| {
match 0 {
1 if true => {
v
},
_ => {
v2
},
}
});
// one branch doesn't insert, use if let
if let std::collections::hash_map::Entry::Vacant(e) = m.entry(k) {
match 0 {
0 => foo(),
_ => {
e.insert(v2);
},
};
}
// use or_insert_with
m.entry(k).or_insert_with(|| {
foo();
match 0 {
0 if false => {
v
},
1 => {
foo();
v
},
2 | 3 => {
for _ in 0..2 {
foo();
}
if true {
v
} else {
v2
}
},
_ => {
v2
},
}
});
// ok, insert in loop
if !m.contains_key(&k) {
for _ in 0..2 {
m.insert(k, v);
}
}
// macro_expansion test, use or_insert(..)
m.entry(m!(k)).or_insert_with(|| m!(v));
// ok, map used before insertion
if !m.contains_key(&k) {
let _ = m.len();
m.insert(k, v);
}
// ok, inline asm
if !m.contains_key(&k) {
unsafe { asm!("nop") }
m.insert(k, v);
}
// ok, different keys.
if !m.contains_key(&k) {
m.insert(k2, v);
}
// ok, different maps
if !m.contains_key(&k) {
m2.insert(k, v);
}
// ok, insert in macro
if !m.contains_key(&k) {
insert!(m, k, v);
}
// or_insert_with. Partial move of a local declared in the closure is ok.
m.entry(k).or_insert_with(|| {
let x = (String::new(), String::new());
let _ = x.0;
v
});
}
// Issue 10331
// do not suggest a bad expansion because the compiler unrolls the first
// occurrence of the loop
pub fn issue_10331() {
let mut m = HashMap::new();
let mut i = 0;
let mut x = 0;
while !m.contains_key(&x) {
m.insert(x, i);
i += 1;
x += 1;
}
}
/// Issue 11935
/// Do not suggest using entries if the map is used inside the `insert` expression.
pub fn issue_11935() {
let mut counts: HashMap<u64, u64> = HashMap::new();
if !counts.contains_key(&1) {
counts.insert(1, 1);
} else {
counts.insert(1, counts.get(&1).unwrap() + 1);
}
}
fn main() {}