fix: prefer (*p).clone to p.clone if the p is a raw pointer

This commit is contained in:
Lin Yihai 2024-06-29 16:49:35 +08:00
parent d38cd229b7
commit 8dc36c1647
5 changed files with 50 additions and 33 deletions

View file

@ -1288,7 +1288,7 @@ fn suggest_cloning_inner(
return false;
}
// Try to find predicates on *generic params* that would allow copying `ty`
let suggestion =
let mut suggestion =
if let Some(symbol) = tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
format!(": {symbol}.clone()")
} else {
@ -1296,6 +1296,8 @@ fn suggest_cloning_inner(
};
let mut sugg = Vec::with_capacity(2);
let mut inner_expr = expr;
let mut is_raw_ptr = false;
let typeck_result = self.infcx.tcx.typeck(self.mir_def_id());
// Remove uses of `&` and `*` when suggesting `.clone()`.
while let hir::ExprKind::AddrOf(.., inner) | hir::ExprKind::Unary(hir::UnOp::Deref, inner) =
&inner_expr.kind
@ -1306,14 +1308,32 @@ fn suggest_cloning_inner(
return false;
}
inner_expr = inner;
if let Some(inner_type) = typeck_result.node_type_opt(inner.hir_id) {
if matches!(inner_type.kind(), ty::RawPtr(..)) {
is_raw_ptr = true;
break;
}
}
}
if inner_expr.span.lo() != expr.span.lo() {
// Cloning the raw pointer doesn't make sense in some cases and would cause a type mismatch error. (see #126863)
if inner_expr.span.lo() != expr.span.lo() && !is_raw_ptr {
// Remove "(*" or "(&"
sugg.push((expr.span.with_hi(inner_expr.span.lo()), String::new()));
}
// Check whether `expr` is surrounded by parentheses or not.
let span = if inner_expr.span.hi() != expr.span.hi() {
// Account for `(*x)` to suggest `x.clone()`.
expr.span.with_lo(inner_expr.span.hi())
if is_raw_ptr {
expr.span.shrink_to_hi()
} else {
// Remove the close parenthesis ")"
expr.span.with_lo(inner_expr.span.hi())
}
} else {
if is_raw_ptr {
sugg.push((expr.span.shrink_to_lo(), "(".to_string()));
suggestion = ").clone()".to_string();
}
expr.span.shrink_to_hi()
};
sugg.push((span, suggestion));

View file

@ -639,12 +639,27 @@ fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span
fn add_borrow_suggestions(&self, err: &mut Diag<'_>, span: Span) {
match self.infcx.tcx.sess.source_map().span_to_snippet(span) {
Ok(snippet) if snippet.starts_with('*') => {
err.span_suggestion_verbose(
span.with_hi(span.lo() + BytePos(1)),
"consider removing the dereference here",
String::new(),
Applicability::MaybeIncorrect,
);
let sp = span.with_lo(span.lo() + BytePos(1));
let inner = self.find_expr(sp);
let mut is_raw_ptr = false;
if let Some(inner) = inner {
let typck_result = self.infcx.tcx.typeck(self.mir_def_id());
if let Some(inner_type) = typck_result.node_type_opt(inner.hir_id) {
if matches!(inner_type.kind(), ty::RawPtr(..)) {
is_raw_ptr = true;
}
}
}
// If the `inner` is a raw pointer, do not suggest removing the "*", see #126863
// FIXME: need to check whether the assigned object can be a raw pointer, see `tests/ui/borrowck/issue-20801.rs`.
if !is_raw_ptr {
err.span_suggestion_verbose(
span.with_hi(span.lo() + BytePos(1)),
"consider removing the dereference here",
String::new(),
Applicability::MaybeIncorrect,
);
}
}
_ => {
err.span_suggestion_verbose(

View file

@ -4,16 +4,10 @@ error[E0507]: cannot move out of `*x` which is behind a raw pointer
LL | let y = *x;
| ^^ move occurs because `*x` has type `Box<isize>`, which does not implement the `Copy` trait
|
help: consider removing the dereference here
|
LL - let y = *x;
LL + let y = x;
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let y = *x;
LL + let y = x.clone();
|
LL | let y = (*x).clone();
| + +++++++++
error: aborting due to 1 previous error

View file

@ -67,11 +67,6 @@ LL | struct T(u8);
...
LL | let c = unsafe { *mut_ptr() };
| ---------- you could clone this value
help: consider removing the dereference here
|
LL - let c = unsafe { *mut_ptr() };
LL + let c = unsafe { mut_ptr() };
|
error[E0507]: cannot move out of a raw pointer
--> $DIR/issue-20801.rs:36:22
@ -87,11 +82,6 @@ LL | struct T(u8);
...
LL | let d = unsafe { *const_ptr() };
| ------------ you could clone this value
help: consider removing the dereference here
|
LL - let d = unsafe { *const_ptr() };
LL + let d = unsafe { const_ptr() };
|
error: aborting due to 4 previous errors; 1 warning emitted

View file

@ -30,9 +30,8 @@ LL | *u.c
|
help: consider cloning the value if the performance cost is acceptable
|
LL - *u.c
LL + u.c.clone()
|
LL | (*u.c).clone()
| + +++++++++
error[E0507]: cannot move out of `*u.d` which is behind a raw pointer
--> $DIR/move-from-union-field-issue-66500.rs:24:5
@ -42,9 +41,8 @@ LL | *u.d
|
help: consider cloning the value if the performance cost is acceptable
|
LL - *u.d
LL + u.d.clone()
|
LL | (*u.d).clone()
| + +++++++++
error: aborting due to 4 previous errors