Auto merge of #4570 - lzutao:call_site_toplevel_ref_arg, r=phansch

Fix macro expansion in toplevel_ref_arg lint

changelog: Fix macro expansion in toplevel_ref_arg lint
This commit is contained in:
bors 2019-09-26 06:02:21 +00:00
commit bc1b04ba85
4 changed files with 53 additions and 40 deletions

View file

@ -261,40 +261,45 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MiscLints {
} }
} }
fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx Stmt) { fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
if_chain! { if_chain! {
if let StmtKind::Local(ref l) = s.node; if let StmtKind::Local(ref local) = stmt.node;
if let PatKind::Binding(an, .., i, None) = l.pat.node; if let PatKind::Binding(an, .., name, None) = local.pat.node;
if let Some(ref init) = l.init; if let Some(ref init) = local.init;
then { then {
if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut { if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut {
let sugg_init = Sugg::hir(cx, init, ".."); let sugg_init = if init.span.from_expansion() {
let (mutopt,initref) = if an == BindingAnnotation::RefMut { Sugg::hir_with_macro_callsite(cx, init, "..")
} else {
Sugg::hir(cx, init, "..")
};
let (mutopt, initref) = if an == BindingAnnotation::RefMut {
("mut ", sugg_init.mut_addr()) ("mut ", sugg_init.mut_addr())
} else { } else {
("", sugg_init.addr()) ("", sugg_init.addr())
}; };
let tyopt = if let Some(ref ty) = l.ty { let tyopt = if let Some(ref ty) = local.ty {
format!(": &{mutopt}{ty}", mutopt=mutopt, ty=snippet(cx, ty.span, "_")) format!(": &{mutopt}{ty}", mutopt=mutopt, ty=snippet(cx, ty.span, "_"))
} else { } else {
String::new() String::new()
}; };
span_lint_hir_and_then(cx, span_lint_hir_and_then(
cx,
TOPLEVEL_REF_ARG, TOPLEVEL_REF_ARG,
init.hir_id, init.hir_id,
l.pat.span, local.pat.span,
"`ref` on an entire `let` pattern is discouraged, take a reference with `&` instead", "`ref` on an entire `let` pattern is discouraged, take a reference with `&` instead",
|db| { |db| {
db.span_suggestion( db.span_suggestion(
s.span, stmt.span,
"try", "try",
format!( format!(
"let {name}{tyopt} = {initref};", "let {name}{tyopt} = {initref};",
name=snippet(cx, i.span, "_"), name=snippet(cx, name.span, "_"),
tyopt=tyopt, tyopt=tyopt,
initref=initref, initref=initref,
), ),
Applicability::MachineApplicable, // snippet Applicability::MachineApplicable,
); );
} }
); );
@ -302,19 +307,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MiscLints {
} }
}; };
if_chain! { if_chain! {
if let StmtKind::Semi(ref expr) = s.node; if let StmtKind::Semi(ref expr) = stmt.node;
if let ExprKind::Binary(ref binop, ref a, ref b) = expr.node; if let ExprKind::Binary(ref binop, ref a, ref b) = expr.node;
if binop.node == BinOpKind::And || binop.node == BinOpKind::Or; if binop.node == BinOpKind::And || binop.node == BinOpKind::Or;
if let Some(sugg) = Sugg::hir_opt(cx, a); if let Some(sugg) = Sugg::hir_opt(cx, a);
then { then {
span_lint_and_then(cx, span_lint_and_then(cx,
SHORT_CIRCUIT_STATEMENT, SHORT_CIRCUIT_STATEMENT,
s.span, stmt.span,
"boolean short circuit operator in statement may be clearer using an explicit test", "boolean short circuit operator in statement may be clearer using an explicit test",
|db| { |db| {
let sugg = if binop.node == BinOpKind::Or { !sugg } else { sugg }; let sugg = if binop.node == BinOpKind::Or { !sugg } else { sugg };
db.span_suggestion( db.span_suggestion(
s.span, stmt.span,
"replace it with", "replace it with",
format!( format!(
"if {} {{ {}; }}", "if {} {{ {}; }}",

View file

@ -1,25 +1,26 @@
// run-rustfix // run-rustfix
#![warn(clippy::toplevel_ref_arg)] #![warn(clippy::toplevel_ref_arg)]
#![allow(unused)]
fn main() { fn main() {
// Closures should not warn // Closures should not warn
let y = |ref x| println!("{:?}", x); let y = |ref x| println!("{:?}", x);
y(1u8); y(1u8);
let x = &1; let _x = &1;
let y: &(&_, u8) = &(&1, 2); let _y: &(&_, u8) = &(&1, 2);
let z = &(1 + 2); let _z = &(1 + 2);
let z = &mut (1 + 2); let _z = &mut (1 + 2);
let (ref x, _) = (1, 2); // ok, not top level let (ref x, _) = (1, 2); // ok, not top level
println!("The answer is {}.", x); println!("The answer is {}.", x);
let _x = &vec![1, 2, 3];
// Make sure that allowing the lint works // Make sure that allowing the lint works
#[allow(clippy::toplevel_ref_arg)] #[allow(clippy::toplevel_ref_arg)]
let ref mut x = 1_234_543; let ref mut _x = 1_234_543;
} }

View file

@ -1,25 +1,26 @@
// run-rustfix // run-rustfix
#![warn(clippy::toplevel_ref_arg)] #![warn(clippy::toplevel_ref_arg)]
#![allow(unused)]
fn main() { fn main() {
// Closures should not warn // Closures should not warn
let y = |ref x| println!("{:?}", x); let y = |ref x| println!("{:?}", x);
y(1u8); y(1u8);
let ref x = 1; let ref _x = 1;
let ref y: (&_, u8) = (&1, 2); let ref _y: (&_, u8) = (&1, 2);
let ref z = 1 + 2; let ref _z = 1 + 2;
let ref mut z = 1 + 2; let ref mut _z = 1 + 2;
let (ref x, _) = (1, 2); // ok, not top level let (ref x, _) = (1, 2); // ok, not top level
println!("The answer is {}.", x); println!("The answer is {}.", x);
let ref _x = vec![1, 2, 3];
// Make sure that allowing the lint works // Make sure that allowing the lint works
#[allow(clippy::toplevel_ref_arg)] #[allow(clippy::toplevel_ref_arg)]
let ref mut x = 1_234_543; let ref mut _x = 1_234_543;
} }

View file

@ -1,28 +1,34 @@
error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
--> $DIR/toplevel_ref_arg.rs:11:9 --> $DIR/toplevel_ref_arg.rs:10:9
| |
LL | let ref x = 1; LL | let ref _x = 1;
| ----^^^^^----- help: try: `let x = &1;` | ----^^^^^^----- help: try: `let _x = &1;`
| |
= note: `-D clippy::toplevel-ref-arg` implied by `-D warnings` = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings`
error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
--> $DIR/toplevel_ref_arg.rs:13:9 --> $DIR/toplevel_ref_arg.rs:12:9
| |
LL | let ref y: (&_, u8) = (&1, 2); LL | let ref _y: (&_, u8) = (&1, 2);
| ----^^^^^--------------------- help: try: `let y: &(&_, u8) = &(&1, 2);` | ----^^^^^^--------------------- help: try: `let _y: &(&_, u8) = &(&1, 2);`
error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
--> $DIR/toplevel_ref_arg.rs:15:9 --> $DIR/toplevel_ref_arg.rs:14:9
| |
LL | let ref z = 1 + 2; LL | let ref _z = 1 + 2;
| ----^^^^^--------- help: try: `let z = &(1 + 2);` | ----^^^^^^--------- help: try: `let _z = &(1 + 2);`
error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
--> $DIR/toplevel_ref_arg.rs:17:9 --> $DIR/toplevel_ref_arg.rs:16:9
| |
LL | let ref mut z = 1 + 2; LL | let ref mut _z = 1 + 2;
| ----^^^^^^^^^--------- help: try: `let z = &mut (1 + 2);` | ----^^^^^^^^^^--------- help: try: `let _z = &mut (1 + 2);`
error: aborting due to 4 previous errors error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
--> $DIR/toplevel_ref_arg.rs:21:9
|
LL | let ref _x = vec![1, 2, 3];
| ----^^^^^^----------------- help: try: `let _x = &vec![1, 2, 3];`
error: aborting due to 5 previous errors