Skip to content

Commit b02b0c7

Browse files
committed
Auto merge of rust-lang#6367 - justjosias:6348-print-stderr, r=ebroto
Add lint print_stderr Resolves rust-lang#6348 Almost identical to print_stdout, this lint applies to the `eprintln!` and `eprint!` macros rather than `println!` and `print!`. changelog: Add new lint [`print_stderr`]. [`println_empty_string`] and [`print_with_newline`] now apply to `eprint!()` and `eprintln!()` respectively.
2 parents f9fccbe + 3187cad commit b02b0c7

10 files changed

+294
-38
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2006,6 +2006,7 @@ Released 2018-09-13
20062006
[`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
20072007
[`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
20082008
[`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal
2009+
[`print_stderr`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr
20092010
[`print_stdout`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout
20102011
[`print_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_with_newline
20112012
[`println_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#println_empty_string

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
936936
&wildcard_imports::WILDCARD_IMPORTS,
937937
&write::PRINTLN_EMPTY_STRING,
938938
&write::PRINT_LITERAL,
939+
&write::PRINT_STDERR,
939940
&write::PRINT_STDOUT,
940941
&write::PRINT_WITH_NEWLINE,
941942
&write::USE_DEBUG,
@@ -1250,6 +1251,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
12501251
LintId::of(&types::RC_BUFFER),
12511252
LintId::of(&unwrap_in_result::UNWRAP_IN_RESULT),
12521253
LintId::of(&verbose_file_reads::VERBOSE_FILE_READS),
1254+
LintId::of(&write::PRINT_STDERR),
12531255
LintId::of(&write::PRINT_STDOUT),
12541256
LintId::of(&write::USE_DEBUG),
12551257
]);

clippy_lints/src/write.rs

Lines changed: 70 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,24 @@ declare_clippy_lint! {
7575
"printing on stdout"
7676
}
7777

78+
declare_clippy_lint! {
79+
/// **What it does:** Checks for printing on *stderr*. The purpose of this lint
80+
/// is to catch debugging remnants.
81+
///
82+
/// **Why is this bad?** People often print on *stderr* while debugging an
83+
/// application and might forget to remove those prints afterward.
84+
///
85+
/// **Known problems:** Only catches `eprint!` and `eprintln!` calls.
86+
///
87+
/// **Example:**
88+
/// ```rust
89+
/// eprintln!("Hello world!");
90+
/// ```
91+
pub PRINT_STDERR,
92+
restriction,
93+
"printing on stderr"
94+
}
95+
7896
declare_clippy_lint! {
7997
/// **What it does:** Checks for use of `Debug` formatting. The purpose of this
8098
/// lint is to catch debugging remnants.
@@ -201,6 +219,7 @@ impl_lint_pass!(Write => [
201219
PRINT_WITH_NEWLINE,
202220
PRINTLN_EMPTY_STRING,
203221
PRINT_STDOUT,
222+
PRINT_STDERR,
204223
USE_DEBUG,
205224
PRINT_LITERAL,
206225
WRITE_WITH_NEWLINE,
@@ -243,47 +262,22 @@ impl EarlyLintPass for Write {
243262
.map_or(false, |crate_name| crate_name == "build_script_build")
244263
}
245264

246-
if mac.path == sym!(println) {
247-
if !is_build_script(cx) {
248-
span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`");
249-
}
250-
if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
251-
if fmt_str.symbol == Symbol::intern("") {
252-
span_lint_and_sugg(
253-
cx,
254-
PRINTLN_EMPTY_STRING,
255-
mac.span(),
256-
"using `println!(\"\")`",
257-
"replace it with",
258-
"println!()".to_string(),
259-
Applicability::MachineApplicable,
260-
);
261-
}
262-
}
263-
} else if mac.path == sym!(print) {
265+
if mac.path == sym!(print) {
264266
if !is_build_script(cx) {
265267
span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`");
266268
}
267-
if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
268-
if check_newlines(&fmt_str) {
269-
span_lint_and_then(
270-
cx,
271-
PRINT_WITH_NEWLINE,
272-
mac.span(),
273-
"using `print!()` with a format string that ends in a single newline",
274-
|err| {
275-
err.multipart_suggestion(
276-
"use `println!` instead",
277-
vec![
278-
(mac.path.span, String::from("println")),
279-
(newline_span(&fmt_str), String::new()),
280-
],
281-
Applicability::MachineApplicable,
282-
);
283-
},
284-
);
285-
}
269+
self.lint_print_with_newline(cx, mac);
270+
} else if mac.path == sym!(println) {
271+
if !is_build_script(cx) {
272+
span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`");
286273
}
274+
self.lint_println_empty_string(cx, mac);
275+
} else if mac.path == sym!(eprint) {
276+
span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprint!`");
277+
self.lint_print_with_newline(cx, mac);
278+
} else if mac.path == sym!(eprintln) {
279+
span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprintln!`");
280+
self.lint_println_empty_string(cx, mac);
287281
} else if mac.path == sym!(write) {
288282
if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), true) {
289283
if check_newlines(&fmt_str) {
@@ -487,6 +481,45 @@ impl Write {
487481
}
488482
}
489483
}
484+
485+
fn lint_println_empty_string(&self, cx: &EarlyContext<'_>, mac: &MacCall) {
486+
if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
487+
if fmt_str.symbol == Symbol::intern("") {
488+
let name = mac.path.segments[0].ident.name;
489+
span_lint_and_sugg(
490+
cx,
491+
PRINTLN_EMPTY_STRING,
492+
mac.span(),
493+
&format!("using `{}!(\"\")`", name),
494+
"replace it with",
495+
format!("{}!()", name),
496+
Applicability::MachineApplicable,
497+
);
498+
}
499+
}
500+
}
501+
502+
fn lint_print_with_newline(&self, cx: &EarlyContext<'_>, mac: &MacCall) {
503+
if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
504+
if check_newlines(&fmt_str) {
505+
let name = mac.path.segments[0].ident.name;
506+
let suggested = format!("{}ln", name);
507+
span_lint_and_then(
508+
cx,
509+
PRINT_WITH_NEWLINE,
510+
mac.span(),
511+
&format!("using `{}!()` with a format string that ends in a single newline", name),
512+
|err| {
513+
err.multipart_suggestion(
514+
&format!("use `{}!` instead", suggested),
515+
vec![(mac.path.span, suggested), (newline_span(&fmt_str), String::new())],
516+
Applicability::MachineApplicable,
517+
);
518+
},
519+
);
520+
}
521+
}
522+
}
490523
}
491524

492525
/// Checks if the format string contains a single newline that terminates it.

tests/ui/eprint_with_newline.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#![allow(clippy::print_literal)]
2+
#![warn(clippy::print_with_newline)]
3+
4+
fn main() {
5+
eprint!("Hello\n");
6+
eprint!("Hello {}\n", "world");
7+
eprint!("Hello {} {}\n", "world", "#2");
8+
eprint!("{}\n", 1265);
9+
eprint!("\n");
10+
11+
// these are all fine
12+
eprint!("");
13+
eprint!("Hello");
14+
eprintln!("Hello");
15+
eprintln!("Hello\n");
16+
eprintln!("Hello {}\n", "world");
17+
eprint!("Issue\n{}", 1265);
18+
eprint!("{}", 1265);
19+
eprint!("\n{}", 1275);
20+
eprint!("\n\n");
21+
eprint!("like eof\n\n");
22+
eprint!("Hello {} {}\n\n", "world", "#2");
23+
eprintln!("\ndon't\nwarn\nfor\nmultiple\nnewlines\n"); // #3126
24+
eprintln!("\nbla\n\n"); // #3126
25+
26+
// Escaping
27+
eprint!("\\n"); // #3514
28+
eprint!("\\\n"); // should fail
29+
eprint!("\\\\n");
30+
31+
// Raw strings
32+
eprint!(r"\n"); // #3778
33+
34+
// Literal newlines should also fail
35+
eprint!(
36+
"
37+
"
38+
);
39+
eprint!(
40+
r"
41+
"
42+
);
43+
44+
// Don't warn on CRLF (#4208)
45+
eprint!("\r\n");
46+
eprint!("foo\r\n");
47+
eprint!("\\r\n"); //~ ERROR
48+
eprint!("foo\rbar\n") // ~ ERROR
49+
}

tests/ui/eprint_with_newline.stderr

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
error: using `eprint!()` with a format string that ends in a single newline
2+
--> $DIR/eprint_with_newline.rs:5:5
3+
|
4+
LL | eprint!("Hello/n");
5+
| ^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::print-with-newline` implied by `-D warnings`
8+
help: use `eprintln!` instead
9+
|
10+
LL | eprintln!("Hello");
11+
| ^^^^^^^^ --
12+
13+
error: using `eprint!()` with a format string that ends in a single newline
14+
--> $DIR/eprint_with_newline.rs:6:5
15+
|
16+
LL | eprint!("Hello {}/n", "world");
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18+
|
19+
help: use `eprintln!` instead
20+
|
21+
LL | eprintln!("Hello {}", "world");
22+
| ^^^^^^^^ --
23+
24+
error: using `eprint!()` with a format string that ends in a single newline
25+
--> $DIR/eprint_with_newline.rs:7:5
26+
|
27+
LL | eprint!("Hello {} {}/n", "world", "#2");
28+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29+
|
30+
help: use `eprintln!` instead
31+
|
32+
LL | eprintln!("Hello {} {}", "world", "#2");
33+
| ^^^^^^^^ --
34+
35+
error: using `eprint!()` with a format string that ends in a single newline
36+
--> $DIR/eprint_with_newline.rs:8:5
37+
|
38+
LL | eprint!("{}/n", 1265);
39+
| ^^^^^^^^^^^^^^^^^^^^^
40+
|
41+
help: use `eprintln!` instead
42+
|
43+
LL | eprintln!("{}", 1265);
44+
| ^^^^^^^^ --
45+
46+
error: using `eprint!()` with a format string that ends in a single newline
47+
--> $DIR/eprint_with_newline.rs:9:5
48+
|
49+
LL | eprint!("/n");
50+
| ^^^^^^^^^^^^^
51+
|
52+
help: use `eprintln!` instead
53+
|
54+
LL | eprintln!();
55+
| ^^^^^^^^ --
56+
57+
error: using `eprint!()` with a format string that ends in a single newline
58+
--> $DIR/eprint_with_newline.rs:28:5
59+
|
60+
LL | eprint!("//n"); // should fail
61+
| ^^^^^^^^^^^^^^^
62+
|
63+
help: use `eprintln!` instead
64+
|
65+
LL | eprintln!("/"); // should fail
66+
| ^^^^^^^^ --
67+
68+
error: using `eprint!()` with a format string that ends in a single newline
69+
--> $DIR/eprint_with_newline.rs:35:5
70+
|
71+
LL | / eprint!(
72+
LL | | "
73+
LL | | "
74+
LL | | );
75+
| |_____^
76+
|
77+
help: use `eprintln!` instead
78+
|
79+
LL | eprintln!(
80+
LL | ""
81+
|
82+
83+
error: using `eprint!()` with a format string that ends in a single newline
84+
--> $DIR/eprint_with_newline.rs:39:5
85+
|
86+
LL | / eprint!(
87+
LL | | r"
88+
LL | | "
89+
LL | | );
90+
| |_____^
91+
|
92+
help: use `eprintln!` instead
93+
|
94+
LL | eprintln!(
95+
LL | r""
96+
|
97+
98+
error: using `eprint!()` with a format string that ends in a single newline
99+
--> $DIR/eprint_with_newline.rs:47:5
100+
|
101+
LL | eprint!("/r/n"); //~ ERROR
102+
| ^^^^^^^^^^^^^^^^
103+
|
104+
help: use `eprintln!` instead
105+
|
106+
LL | eprintln!("/r"); //~ ERROR
107+
| ^^^^^^^^ --
108+
109+
error: using `eprint!()` with a format string that ends in a single newline
110+
--> $DIR/eprint_with_newline.rs:48:5
111+
|
112+
LL | eprint!("foo/rbar/n") // ~ ERROR
113+
| ^^^^^^^^^^^^^^^^^^^^^
114+
|
115+
help: use `eprintln!` instead
116+
|
117+
LL | eprintln!("foo/rbar") // ~ ERROR
118+
| ^^^^^^^^ --
119+
120+
error: aborting due to 10 previous errors
121+

tests/ui/print_stderr.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![warn(clippy::print_stderr)]
2+
3+
fn main() {
4+
eprintln!("Hello");
5+
println!("This should not do anything");
6+
eprint!("World");
7+
print!("Nor should this");
8+
}

tests/ui/print_stderr.stderr

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: use of `eprintln!`
2+
--> $DIR/print_stderr.rs:4:5
3+
|
4+
LL | eprintln!("Hello");
5+
| ^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::print-stderr` implied by `-D warnings`
8+
9+
error: use of `eprint!`
10+
--> $DIR/print_stderr.rs:6:5
11+
|
12+
LL | eprint!("World");
13+
| ^^^^^^^^^^^^^^^^
14+
15+
error: aborting due to 2 previous errors
16+

tests/ui/println_empty_string.fixed

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,11 @@ fn main() {
88
match "a" {
99
_ => println!(),
1010
}
11+
12+
eprintln!();
13+
eprintln!();
14+
15+
match "a" {
16+
_ => eprintln!(),
17+
}
1118
}

tests/ui/println_empty_string.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,11 @@ fn main() {
88
match "a" {
99
_ => println!(""),
1010
}
11+
12+
eprintln!();
13+
eprintln!("");
14+
15+
match "a" {
16+
_ => eprintln!(""),
17+
}
1118
}

0 commit comments

Comments
 (0)