Skip to content

Commit a748b06

Browse files
committed
check mut: from hir to mir
just because less lines
1 parent 3045264 commit a748b06

File tree

1 file changed

+45
-71
lines changed

1 file changed

+45
-71
lines changed

clippy_lints/src/explicit_reinitialization.rs

Lines changed: 45 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::source::snippet_opt;
3-
use clippy_utils::visitors::for_each_local_use_after_expr;
4-
use clippy_utils::{fn_has_unsatisfiable_preds, get_parent_expr, is_from_proc_macro};
3+
use clippy_utils::{fn_has_unsatisfiable_preds, is_from_proc_macro};
54
use rustc_data_structures::fx::FxHashSet;
65
use rustc_data_structures::graph::dominators::Dominators;
76
use rustc_data_structures::graph::iterate::DepthFirstSearch;
@@ -11,16 +10,14 @@ use rustc_hir::def::Res;
1110
use rustc_hir::def_id::LocalDefId;
1211
use rustc_hir::{
1312
Closure, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Item, ItemKind, Mutability, Node, Path, PathSegment, QPath,
14-
StmtKind, TraitFn, TraitItem, TraitItemKind, UnOp,
13+
StmtKind, TraitFn, TraitItem, TraitItemKind,
1514
};
1615
use rustc_lint::{LateContext, LateLintPass};
1716
use rustc_middle::lint::in_external_macro;
18-
use rustc_middle::mir::visit::{PlaceContext, Visitor};
17+
use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
1918
use rustc_middle::mir::{self, BasicBlock, Body, Local, Location, Place, Statement, Terminator};
2019
use rustc_session::{declare_lint_pass, declare_tool_lint, Session};
2120
use rustc_span::Span;
22-
use std::collections::BTreeSet;
23-
use std::ops::ControlFlow;
2421

2522
declare_clippy_lint! {
2623
/// ### What it does
@@ -75,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitReinitialization {
7572
None,
7673
Path {
7774
segments: [PathSegment { args: None, .. }],
78-
res: Res::Local(local_id),
75+
res: Res::Local(_),
7976
..
8077
},
8178
)),
@@ -85,7 +82,6 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitReinitialization {
8582
right,
8683
_,
8784
),
88-
hir_id: expr_id,
8985
..
9086
},
9187
) = stmt.kind
@@ -118,65 +114,14 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitReinitialization {
118114

119115
assert!(start_location.dominates(location, dominators));
120116

121-
if dominate_all_usage(mir, dominators, local, start_location) {
122-
// copy from `vec_init_then_push.rs`
123-
let mut needs_mut = false;
124-
let _ = for_each_local_use_after_expr(cx, *local_id, *expr_id, |e| {
125-
let Some(parent) = get_parent_expr(cx, e) else {
126-
return ControlFlow::Continue(());
127-
};
128-
let adjusted_ty = cx.typeck_results().expr_ty_adjusted(e);
129-
let adjusted_mut = adjusted_ty.ref_mutability().unwrap_or(Mutability::Not);
130-
needs_mut |= adjusted_mut == Mutability::Mut;
131-
match parent.kind {
132-
ExprKind::AddrOf(_, Mutability::Mut, _) => {
133-
needs_mut = true;
134-
return ControlFlow::Break(true);
135-
},
136-
ExprKind::Unary(UnOp::Deref, _) | ExprKind::Index(..) if !needs_mut => {
137-
let mut last_place = parent;
138-
while let Some(parent) = get_parent_expr(cx, last_place) {
139-
if matches!(parent.kind, ExprKind::Unary(UnOp::Deref, _) | ExprKind::Field(..))
140-
|| matches!(parent.kind, ExprKind::Index(e, _, _) if e.hir_id == last_place.hir_id)
141-
{
142-
last_place = parent;
143-
} else {
144-
break;
145-
}
146-
}
147-
needs_mut |= cx.typeck_results().expr_ty_adjusted(last_place).ref_mutability()
148-
== Some(Mutability::Mut)
149-
|| get_parent_expr(cx, last_place)
150-
.map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(_, Mutability::Mut, _)));
151-
},
152-
ExprKind::MethodCall(_, recv, ..)
153-
if recv.hir_id == e.hir_id
154-
&& adjusted_mut == Mutability::Mut
155-
&& !adjusted_ty.peel_refs().is_slice() =>
156-
{
157-
// No need to set `needs_mut` to true. The receiver will be either explicitly borrowed, or it
158-
// will be implicitly borrowed via an adjustment. Both of these cases
159-
// are already handled by this point.
160-
return ControlFlow::Break(true);
161-
},
162-
ExprKind::Assign(lhs, ..) if e.hir_id == lhs.hir_id => {
163-
needs_mut = true;
164-
return ControlFlow::Break(false);
165-
},
166-
_ => (),
167-
}
168-
ControlFlow::Continue(())
169-
});
170-
171-
let mut_str = if needs_mut { "mut " } else { "" };
172-
117+
if let Some(mutability) = dominate_all_usage(mir, dominators, local, location) {
173118
span_lint_and_sugg(
174119
cx,
175120
EXPLICIT_REINITIALIZATION,
176121
stmt.span,
177122
"create a fresh variable is more explicit",
178123
"create a fresh variable instead of reinitialization",
179-
format!("let {mut_str}{snip}"),
124+
format!("let {}{snip}", mutability.prefix_str()),
180125
Applicability::MachineApplicable,
181126
);
182127
}
@@ -386,42 +331,71 @@ fn search_mir_by_span(
386331
accurate_visitor.result
387332
}
388333

334+
// None: doesn't dominate all usage
335+
// Some(Mut): dominate all usage, and a mut usage found
336+
// Some(Not); dominate all uagee, and no muge usage found
389337
fn dominate_all_usage(
390338
mir: &mir::Body<'_>,
391339
dominators: &Dominators<BasicBlock>,
392340
local: Local,
393341
start_location: Location,
394-
) -> bool {
342+
) -> Option<Mutability> {
395343
let mut dfs = DepthFirstSearch::new(&mir.basic_blocks);
396344
for successor in mir.basic_blocks.successors(start_location.block) {
397345
dfs.push_start_node(successor);
398346
}
399347
let reachable_bb: FxHashSet<BasicBlock> = dfs.collect();
400-
find_usage(mir, local)
348+
349+
let mut res = Mutability::Not;
350+
351+
for (location, mutability) in find_usage(mir, local)
401352
.into_iter()
402-
.filter(|location| reachable_bb.contains(&location.block))
403-
.filter(|location| !mir.basic_blocks[location.block].is_cleanup)
404-
.all(|location| start_location.dominates(location, dominators))
353+
.filter(|(location, _)| !mir.basic_blocks[location.block].is_cleanup)
354+
{
355+
if reachable_bb.contains(&location.block) {
356+
if !start_location.dominates(location, dominators) {
357+
return None;
358+
}
359+
if location != start_location && mutability == Mutability::Mut {
360+
res = Mutability::Mut;
361+
}
362+
} else if location.block == start_location.block
363+
&& location.statement_index > start_location.statement_index
364+
&& mutability == Mutability::Mut
365+
{
366+
res = Mutability::Mut;
367+
}
368+
}
369+
Some(res)
405370
}
406371

407372
// copy from https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_borrowck/diagnostics/find_all_local_uses.rs.html#1-29
408-
fn find_usage(body: &Body<'_>, local: Local) -> BTreeSet<Location> {
373+
fn find_usage(body: &Body<'_>, local: Local) -> FxHashSet<(Location, Mutability)> {
409374
struct AllLocalUsesVisitor {
410375
for_local: Local,
411-
uses: BTreeSet<Location>,
376+
uses: FxHashSet<(Location, Mutability)>,
412377
}
413378

414379
impl<'tcx> Visitor<'tcx> for AllLocalUsesVisitor {
415-
fn visit_local(&mut self, local: Local, _context: PlaceContext, location: Location) {
380+
fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) {
416381
if local == self.for_local {
417-
self.uses.insert(location);
382+
match context {
383+
PlaceContext::NonMutatingUse(_)
384+
| PlaceContext::NonUse(_)
385+
| PlaceContext::MutatingUse(MutatingUseContext::Drop) => {
386+
self.uses.insert((location, Mutability::Not));
387+
},
388+
PlaceContext::MutatingUse(_) => {
389+
self.uses.insert((location, Mutability::Mut));
390+
},
391+
}
418392
}
419393
}
420394
}
421395

422396
let mut visitor = AllLocalUsesVisitor {
423397
for_local: local,
424-
uses: BTreeSet::default(),
398+
uses: FxHashSet::default(),
425399
};
426400
visitor.visit_body(body);
427401
visitor.uses

0 commit comments

Comments
 (0)