large_assignments: Lint on specific large args passed to functions
This commit is contained in:
parent
16ba56c242
commit
8f440f06c6
5 changed files with 134 additions and 41 deletions
|
@ -614,8 +614,8 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn check_operand_move_size(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
|
||||
let limit = self.tcx.move_size_limit().0;
|
||||
if limit == 0 {
|
||||
let limit = self.tcx.move_size_limit();
|
||||
if limit.0 == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -627,48 +627,19 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
let limit = Size::from_bytes(limit);
|
||||
let ty = operand.ty(self.body, self.tcx);
|
||||
let ty = self.monomorphize(ty);
|
||||
let Ok(layout) = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) else { return };
|
||||
if layout.size <= limit {
|
||||
return;
|
||||
}
|
||||
debug!(?layout);
|
||||
let source_info = self.body.source_info(location);
|
||||
debug!(?source_info);
|
||||
for span in &self.move_size_spans {
|
||||
if span.overlaps(source_info.span) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
let lint_root = source_info.scope.lint_root(&self.body.source_scopes);
|
||||
debug!(?lint_root);
|
||||
let Some(lint_root) = lint_root else {
|
||||
// This happens when the issue is in a function from a foreign crate that
|
||||
// we monomorphized in the current crate. We can't get a `HirId` for things
|
||||
// in other crates.
|
||||
// FIXME: Find out where to report the lint on. Maybe simply crate-level lint root
|
||||
// but correct span? This would make the lint at least accept crate-level lint attributes.
|
||||
return;
|
||||
|
||||
if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) {
|
||||
self.lint_large_assignment(limit.0, too_large_size, location, source_info.span);
|
||||
};
|
||||
self.tcx.emit_spanned_lint(
|
||||
LARGE_ASSIGNMENTS,
|
||||
lint_root,
|
||||
source_info.span,
|
||||
LargeAssignmentsLint {
|
||||
span: source_info.span,
|
||||
size: layout.size.bytes(),
|
||||
limit: limit.bytes(),
|
||||
},
|
||||
);
|
||||
self.move_size_spans.push(source_info.span);
|
||||
}
|
||||
|
||||
fn check_fn_args_move_size(
|
||||
&mut self,
|
||||
callee_ty: Ty<'tcx>,
|
||||
args: &[Spanned<mir::Operand<'tcx>>],
|
||||
fn_span: Span,
|
||||
location: Location,
|
||||
) {
|
||||
let limit = self.tcx.move_size_limit();
|
||||
|
@ -692,10 +663,65 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
debug!(?def_id, ?fn_span);
|
||||
|
||||
for arg in args {
|
||||
self.check_operand_move_size(&arg.node, location);
|
||||
if let Some(too_large_size) = self.operand_size_if_too_large(limit, &arg.node) {
|
||||
self.lint_large_assignment(limit.0, too_large_size, location, arg.span);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn operand_size_if_too_large(
|
||||
&mut self,
|
||||
limit: Limit,
|
||||
operand: &mir::Operand<'tcx>,
|
||||
) -> Option<Size> {
|
||||
let ty = operand.ty(self.body, self.tcx);
|
||||
let ty = self.monomorphize(ty);
|
||||
let Ok(layout) = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) else {
|
||||
return None;
|
||||
};
|
||||
if layout.size.bytes_usize() > limit.0 {
|
||||
debug!(?layout);
|
||||
Some(layout.size)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn lint_large_assignment(
|
||||
&mut self,
|
||||
limit: usize,
|
||||
too_large_size: Size,
|
||||
location: Location,
|
||||
span: Span,
|
||||
) {
|
||||
let source_info = self.body.source_info(location);
|
||||
debug!(?source_info);
|
||||
for reported_span in &self.move_size_spans {
|
||||
if reported_span.overlaps(span) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
let lint_root = source_info.scope.lint_root(&self.body.source_scopes);
|
||||
debug!(?lint_root);
|
||||
let Some(lint_root) = lint_root else {
|
||||
// This happens when the issue is in a function from a foreign crate that
|
||||
// we monomorphized in the current crate. We can't get a `HirId` for things
|
||||
// in other crates.
|
||||
// FIXME: Find out where to report the lint on. Maybe simply crate-level lint root
|
||||
// but correct span? This would make the lint at least accept crate-level lint attributes.
|
||||
return;
|
||||
};
|
||||
self.tcx.emit_spanned_lint(
|
||||
LARGE_ASSIGNMENTS,
|
||||
lint_root,
|
||||
span,
|
||||
LargeAssignmentsLint { span, size: too_large_size.bytes(), limit: limit as u64 },
|
||||
);
|
||||
self.move_size_spans.push(span);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
|
||||
|
@ -813,11 +839,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
|
|||
};
|
||||
|
||||
match terminator.kind {
|
||||
mir::TerminatorKind::Call { ref func, ref args, .. } => {
|
||||
mir::TerminatorKind::Call { ref func, ref args, ref fn_span, .. } => {
|
||||
let callee_ty = func.ty(self.body, tcx);
|
||||
let callee_ty = self.monomorphize(callee_ty);
|
||||
self.check_fn_args_move_size(callee_ty, args, location);
|
||||
visit_fn_use(self.tcx, callee_ty, true, source, self.output)
|
||||
self.check_fn_args_move_size(callee_ty, args, *fn_span, location);
|
||||
visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output)
|
||||
}
|
||||
mir::TerminatorKind::Drop { ref place, .. } => {
|
||||
let ty = place.ty(self.body, self.tcx).ty;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue