Skip to content

Commit 8a27af3

Browse files
Prevent mem_replace_with_default lint within macros
Also added test cases for internal and external macros.
1 parent 4ad0e5b commit 8a27af3

File tree

5 files changed

+44
-9
lines changed

5 files changed

+44
-9
lines changed

clippy_lints/src/mem_replace.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use crate::utils::{
2-
match_def_path, match_qpath, paths, snippet_with_applicability, span_help_and_lint, span_lint_and_sugg,
2+
in_macro, match_def_path, match_qpath, paths, snippet_with_applicability, span_help_and_lint, span_lint_and_sugg,
33
};
44
use if_chain::if_chain;
55
use rustc::declare_lint_pass;
66
use rustc::hir::{BorrowKind, Expr, ExprKind, HirVec, Mutability, QPath};
7-
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
7+
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintPass};
88
use rustc_errors::Applicability;
99
use rustc_session::declare_tool_lint;
1010

@@ -163,9 +163,9 @@ fn check_replace_with_uninit(cx: &LateContext<'_, '_>, expr: &'_ Expr, args: &Hi
163163
}
164164

165165
fn check_replace_with_default(cx: &LateContext<'_, '_>, expr: &'_ Expr, args: &HirVec<Expr>) {
166-
if let ExprKind::Call(ref repl_func, ref repl_args) = args[1].kind {
166+
if let ExprKind::Call(ref repl_func, _) = args[1].kind {
167167
if_chain! {
168-
if repl_args.is_empty();
168+
if !in_macro(expr.span) && !in_external_macro(cx.tcx.sess, expr.span);
169169
if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
170170
if let Some(repl_def_id) = cx.tables.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
171171
if match_def_path(cx, repl_def_id, &paths::DEFAULT_TRAIT_METHOD);

tests/ui/auxiliary/macro_rules.rs

+7
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,10 @@ macro_rules! string_add {
3939
let z = y + "...";
4040
};
4141
}
42+
43+
#[macro_export]
44+
macro_rules! take_external {
45+
($s:expr) => {
46+
std::mem::replace($s, Default::default())
47+
};
48+
}

tests/ui/mem_replace.fixed

+14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// except according to those terms.
99

1010
// run-rustfix
11+
// aux-build:macro_rules.rs
1112
#![allow(unused_imports)]
1213
#![warn(
1314
clippy::all,
@@ -16,8 +17,17 @@
1617
clippy::mem_replace_with_default
1718
)]
1819

20+
#[macro_use]
21+
extern crate macro_rules;
22+
1923
use std::mem;
2024

25+
macro_rules! take {
26+
($s:expr) => {
27+
std::mem::replace($s, Default::default())
28+
};
29+
}
30+
2131
fn replace_option_with_none() {
2232
let mut an_option = Some(1);
2333
let _ = an_option.take();
@@ -31,6 +41,10 @@ fn replace_with_default() {
3141
let s = &mut String::from("foo");
3242
let _ = std::mem::take(s);
3343
let _ = std::mem::take(s);
44+
45+
// dont lint within macros
46+
take!(s);
47+
take_external!(s);
3448
}
3549

3650
fn main() {

tests/ui/mem_replace.rs

+14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// except according to those terms.
99

1010
// run-rustfix
11+
// aux-build:macro_rules.rs
1112
#![allow(unused_imports)]
1213
#![warn(
1314
clippy::all,
@@ -16,8 +17,17 @@
1617
clippy::mem_replace_with_default
1718
)]
1819

20+
#[macro_use]
21+
extern crate macro_rules;
22+
1923
use std::mem;
2024

25+
macro_rules! take {
26+
($s:expr) => {
27+
std::mem::replace($s, Default::default())
28+
};
29+
}
30+
2131
fn replace_option_with_none() {
2232
let mut an_option = Some(1);
2333
let _ = mem::replace(&mut an_option, None);
@@ -31,6 +41,10 @@ fn replace_with_default() {
3141
let s = &mut String::from("foo");
3242
let _ = std::mem::replace(s, String::default());
3343
let _ = std::mem::replace(s, Default::default());
44+
45+
// dont lint within macros
46+
take!(s);
47+
take_external!(s);
3448
}
3549

3650
fn main() {

tests/ui/mem_replace.stderr

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
11
error: replacing an `Option` with `None`
2-
--> $DIR/mem_replace.rs:23:13
2+
--> $DIR/mem_replace.rs:33:13
33
|
44
LL | let _ = mem::replace(&mut an_option, None);
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
66
|
77
= note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings`
88

99
error: replacing an `Option` with `None`
10-
--> $DIR/mem_replace.rs:25:13
10+
--> $DIR/mem_replace.rs:35:13
1111
|
1212
LL | let _ = mem::replace(an_option, None);
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
1414

1515
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
16-
--> $DIR/mem_replace.rs:30:13
16+
--> $DIR/mem_replace.rs:40:13
1717
|
1818
LL | let _ = std::mem::replace(&mut s, String::default());
1919
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)`
2020
|
2121
= note: `-D clippy::mem-replace-with-default` implied by `-D warnings`
2222

2323
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
24-
--> $DIR/mem_replace.rs:32:13
24+
--> $DIR/mem_replace.rs:42:13
2525
|
2626
LL | let _ = std::mem::replace(s, String::default());
2727
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)`
2828

2929
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
30-
--> $DIR/mem_replace.rs:33:13
30+
--> $DIR/mem_replace.rs:43:13
3131
|
3232
LL | let _ = std::mem::replace(s, Default::default());
3333
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)`

0 commit comments

Comments
 (0)