mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
refactor(clippy_utils::mir::visit_local_usage): use const generics
encodes the direct relationship between the lengths of `locals` and the returned list, making the code more type-safe
This commit is contained in:
@@ -38,15 +38,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver
|
||||
.local_decls
|
||||
.iter_enumerated()
|
||||
.find(|(_, decl)| local.span.contains(decl.source_info.span))
|
||||
&& let Some(usages) = visit_local_usage(
|
||||
&[local],
|
||||
&& let Some([usage]) = visit_local_usage(
|
||||
[local],
|
||||
mir,
|
||||
Location {
|
||||
block: START_BLOCK,
|
||||
statement_index: 0,
|
||||
},
|
||||
)
|
||||
&& let [usage] = usages.as_slice()
|
||||
{
|
||||
let writer_never_mutated = usage.local_consume_or_mutate_locs.is_empty();
|
||||
|
||||
|
||||
@@ -368,25 +368,25 @@ struct CloneUsage {
|
||||
}
|
||||
|
||||
fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>, bb: mir::BasicBlock) -> CloneUsage {
|
||||
if let Some((
|
||||
LocalUsage {
|
||||
local_use_locs: cloned_use_locs,
|
||||
local_consume_or_mutate_locs: cloned_consume_or_mutate_locs,
|
||||
},
|
||||
LocalUsage {
|
||||
local_use_locs: _,
|
||||
local_consume_or_mutate_locs: clone_consume_or_mutate_locs,
|
||||
},
|
||||
)) = visit_local_usage(
|
||||
&[cloned, clone],
|
||||
if let Some(
|
||||
[
|
||||
LocalUsage {
|
||||
local_use_locs: cloned_use_locs,
|
||||
local_consume_or_mutate_locs: cloned_consume_or_mutate_locs,
|
||||
},
|
||||
LocalUsage {
|
||||
local_use_locs: _,
|
||||
local_consume_or_mutate_locs: clone_consume_or_mutate_locs,
|
||||
},
|
||||
],
|
||||
) = visit_local_usage(
|
||||
[cloned, clone],
|
||||
mir,
|
||||
mir::Location {
|
||||
block: bb,
|
||||
statement_index: mir.basic_blocks[bb].statements.len(),
|
||||
},
|
||||
)
|
||||
.map(|mut vec| (vec.remove(0), vec.remove(0)))
|
||||
{
|
||||
) {
|
||||
CloneUsage {
|
||||
cloned_use_loc: cloned_use_locs.first().copied().into(),
|
||||
cloned_consume_or_mutate_loc: cloned_consume_or_mutate_locs.first().copied(),
|
||||
|
||||
+22
-17
@@ -1,3 +1,5 @@
|
||||
use std::iter;
|
||||
|
||||
use rustc_data_structures::either::Either;
|
||||
use rustc_hir::{Expr, HirId};
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
@@ -22,14 +24,17 @@ pub struct LocalUsage {
|
||||
pub local_consume_or_mutate_locs: Vec<Location>,
|
||||
}
|
||||
|
||||
pub fn visit_local_usage(locals: &[Local], mir: &Body<'_>, location: Location) -> Option<Vec<LocalUsage>> {
|
||||
let init = vec![
|
||||
pub fn visit_local_usage<const N: usize>(
|
||||
locals: [Local; N],
|
||||
mir: &Body<'_>,
|
||||
location: Location,
|
||||
) -> Option<[LocalUsage; N]> {
|
||||
let init = [const {
|
||||
LocalUsage {
|
||||
local_use_locs: Vec::new(),
|
||||
local_consume_or_mutate_locs: Vec::new(),
|
||||
};
|
||||
locals.len()
|
||||
];
|
||||
}
|
||||
}; N];
|
||||
|
||||
traversal::Postorder::new(&mir.basic_blocks, location.block, None)
|
||||
.collect::<Vec<_>>()
|
||||
@@ -44,7 +49,7 @@ pub fn visit_local_usage(locals: &[Local], mir: &Body<'_>, location: Location) -
|
||||
}
|
||||
|
||||
let mut v = V {
|
||||
locals,
|
||||
locals: &locals,
|
||||
location,
|
||||
results: usage,
|
||||
};
|
||||
@@ -53,13 +58,13 @@ pub fn visit_local_usage(locals: &[Local], mir: &Body<'_>, location: Location) -
|
||||
})
|
||||
}
|
||||
|
||||
struct V<'a> {
|
||||
locals: &'a [Local],
|
||||
struct V<'a, const N: usize> {
|
||||
locals: &'a [Local; N],
|
||||
location: Location,
|
||||
results: Vec<LocalUsage>,
|
||||
results: [LocalUsage; N],
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for V<'_> {
|
||||
impl<'tcx, const N: usize> Visitor<'tcx> for V<'_, N> {
|
||||
fn visit_place(&mut self, place: &Place<'tcx>, ctx: PlaceContext, loc: Location) {
|
||||
if loc.block == self.location.block && loc.statement_index <= self.location.statement_index {
|
||||
return;
|
||||
@@ -67,20 +72,20 @@ fn visit_place(&mut self, place: &Place<'tcx>, ctx: PlaceContext, loc: Location)
|
||||
|
||||
let local = place.local;
|
||||
|
||||
for (i, self_local) in self.locals.iter().enumerate() {
|
||||
for (self_local, result) in iter::zip(self.locals, &mut self.results) {
|
||||
if local == *self_local {
|
||||
if !matches!(
|
||||
ctx,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Drop) | PlaceContext::NonUse(_)
|
||||
) {
|
||||
self.results[i].local_use_locs.push(loc);
|
||||
result.local_use_locs.push(loc);
|
||||
}
|
||||
if matches!(
|
||||
ctx,
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move | NonMutatingUseContext::Inspect)
|
||||
| PlaceContext::MutatingUse(MutatingUseContext::Borrow)
|
||||
) {
|
||||
self.results[i].local_consume_or_mutate_locs.push(loc);
|
||||
result.local_consume_or_mutate_locs.push(loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,16 +119,16 @@ pub fn block_in_cycle(body: &Body<'_>, block: BasicBlock) -> bool {
|
||||
/// Convenience wrapper around `visit_local_usage`.
|
||||
pub fn used_exactly_once(mir: &Body<'_>, local: Local) -> Option<bool> {
|
||||
visit_local_usage(
|
||||
&[local],
|
||||
[local],
|
||||
mir,
|
||||
Location {
|
||||
block: START_BLOCK,
|
||||
statement_index: 0,
|
||||
},
|
||||
)
|
||||
.map(|mut vec| {
|
||||
let LocalUsage { local_use_locs, .. } = vec.remove(0);
|
||||
let mut locations = local_use_locs
|
||||
.map(|[local_usage]| {
|
||||
let mut locations = local_usage
|
||||
.local_use_locs
|
||||
.into_iter()
|
||||
.filter(|&location| !is_local_assignment(mir, local, location));
|
||||
if let Some(location) = locations.next() {
|
||||
|
||||
Reference in New Issue
Block a user