Skip to content

Commit 343bdb3

Browse files
committed
Give better suggestion by working on span on deref_addrof lint
1 parent 158bf9a commit 343bdb3

File tree

4 files changed

+66
-9
lines changed

4 files changed

+66
-9
lines changed

clippy_lints/src/reference.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
use crate::utils::{in_macro, snippet_with_applicability, span_lint_and_sugg};
1+
use crate::utils::{in_macro, snippet_opt, snippet_with_applicability, span_lint_and_sugg};
22
use if_chain::if_chain;
3-
use rustc_ast::ast::{Expr, ExprKind, UnOp};
3+
use rustc_ast::ast::{Expr, ExprKind, UnOp, Mutability};
44
use rustc_errors::Applicability;
55
use rustc_lint::{EarlyContext, EarlyLintPass};
66
use rustc_session::{declare_lint_pass, declare_tool_lint};
7+
use rustc_span::BytePos;
8+
// use rustc_span::source_map::{BytePos, Span};
79

810
declare_clippy_lint! {
911
/// **What it does:** Checks for usage of `*&` and `*&mut` in expressions.
@@ -42,13 +44,37 @@ impl EarlyLintPass for DerefAddrOf {
4244
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
4345
if_chain! {
4446
if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind;
45-
if let ExprKind::AddrOf(_, _, ref addrof_target) = without_parens(deref_target).kind;
47+
if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind;
4648
if !in_macro(addrof_target.span);
4749
then {
4850
let mut applicability = Applicability::MachineApplicable;
4951
let sugg = if e.span.from_expansion() {
50-
let snip = snippet_with_applicability(cx, e.span, "_", &mut applicability);
51-
snip.trim_start_matches(|c| c == '&' || c == '*').to_string()
52+
if let Ok(macro_source) = cx.sess.source_map().span_to_snippet(e.span) {
53+
// Remove leading whitespace from the given span
54+
// e.g: ` $visitor` turns into `$visitor`
55+
let trim_leading_whitespaces = |span| {
56+
if let Some(start_no_whitespace) = snippet_opt(cx, span).and_then(|snip| {
57+
snip.find(|c: char| !c.is_whitespace()).map(|pos| {
58+
span.lo() + BytePos(pos as u32)
59+
})
60+
}) {
61+
e.span.with_lo(start_no_whitespace)
62+
} else {
63+
span
64+
}
65+
};
66+
67+
let rpos = if *mutability == Mutability::Mut {
68+
macro_source.rfind("mut").expect("already checked this is a mutable reference") + "mut".len()
69+
} else {
70+
macro_source.rfind("&").expect("already checked this is a reference") + "&".len()
71+
};
72+
let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32));
73+
let span = trim_leading_whitespaces(span_after_ref);
74+
snippet_with_applicability(cx, span, "_", &mut applicability).to_string()
75+
} else {
76+
snippet_with_applicability(cx, e.span, "_", &mut applicability).to_string()
77+
}
5278
} else {
5379
snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability).to_string()
5480
};

tests/ui/deref_addrof.fixed

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,19 @@ macro_rules! m {
4444
};
4545
}
4646

47+
#[rustfmt::skip]
48+
macro_rules! m_mut {
49+
($visitor: expr) => {
50+
$visitor
51+
};
52+
}
53+
4754
pub struct S;
4855
impl S {
4956
pub fn f(&self) -> &Self {
5057
m!(self)
5158
}
59+
pub fn f_mut(&self) -> &Self {
60+
m_mut!(self)
61+
}
5262
}

tests/ui/deref_addrof.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,14 @@ fn main() {
4040

4141
macro_rules! m {
4242
($visitor: expr) => {
43-
*&$visitor
43+
*& $visitor
44+
};
45+
}
46+
47+
#[rustfmt::skip]
48+
macro_rules! m_mut {
49+
($visitor: expr) => {
50+
*& mut $visitor
4451
};
4552
}
4653

@@ -49,4 +56,7 @@ impl S {
4956
pub fn f(&self) -> &Self {
5057
m!(self)
5158
}
59+
pub fn f_mut(&self) -> &Self {
60+
m_mut!(self)
61+
}
5262
}

tests/ui/deref_addrof.stderr

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,24 @@ LL | let b = **&aref;
5151
error: immediately dereferencing a reference
5252
--> $DIR/deref_addrof.rs:43:9
5353
|
54-
LL | *&$visitor
55-
| ^^^^^^^^^^ help: try this: `$visitor`
54+
LL | *& $visitor
55+
| ^^^^^^^^^^^ help: try this: `$visitor`
5656
...
5757
LL | m!(self)
5858
| -------- in this macro invocation
5959
|
6060
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
6161

62-
error: aborting due to 9 previous errors
62+
error: immediately dereferencing a reference
63+
--> $DIR/deref_addrof.rs:50:9
64+
|
65+
LL | *& mut $visitor
66+
| ^^^^^^^^^^^^^^^ help: try this: `$visitor`
67+
...
68+
LL | m_mut!(self)
69+
| ------------ in this macro invocation
70+
|
71+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
72+
73+
error: aborting due to 10 previous errors
6374

0 commit comments

Comments
 (0)