Skip to content

Commit e415911

Browse files
authored
fix(use_debug): don't get confused by nested Debug impls (rust-lang#15946)
Fixes rust-lang/rust-clippy#15942 changelog: [`use_debug`]: don't get confused by nested `Debug` impls
2 parents bcc40ce + d349b20 commit e415911

File tree

7 files changed

+147
-109
lines changed

7 files changed

+147
-109
lines changed

clippy_lints/src/write.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_ast::{
99
FormatPlaceholder, FormatTrait,
1010
};
1111
use rustc_errors::Applicability;
12-
use rustc_hir::{Expr, Impl, Item, ItemKind};
12+
use rustc_hir::{Expr, Impl, Item, ItemKind, OwnerId};
1313
use rustc_lint::{LateContext, LateLintPass, LintContext};
1414
use rustc_session::impl_lint_pass;
1515
use rustc_span::{BytePos, Span};
@@ -240,18 +240,23 @@ declare_clippy_lint! {
240240

241241
pub struct Write {
242242
format_args: FormatArgsStorage,
243-
in_debug_impl: bool,
243+
// The outermost `impl Debug` we're currently in. While we're in one, `USE_DEBUG` is deactivated
244+
outermost_debug_impl: Option<OwnerId>,
244245
allow_print_in_tests: bool,
245246
}
246247

247248
impl Write {
248249
pub fn new(conf: &'static Conf, format_args: FormatArgsStorage) -> Self {
249250
Self {
250251
format_args,
251-
in_debug_impl: false,
252+
outermost_debug_impl: None,
252253
allow_print_in_tests: conf.allow_print_in_tests,
253254
}
254255
}
256+
257+
fn in_debug_impl(&self) -> bool {
258+
self.outermost_debug_impl.is_some()
259+
}
255260
}
256261

257262
impl_lint_pass!(Write => [
@@ -268,14 +273,16 @@ impl_lint_pass!(Write => [
268273

269274
impl<'tcx> LateLintPass<'tcx> for Write {
270275
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
271-
if is_debug_impl(cx, item) {
272-
self.in_debug_impl = true;
276+
// Only check for `impl Debug`s if we're not already in one
277+
if self.outermost_debug_impl.is_none() && is_debug_impl(cx, item) {
278+
self.outermost_debug_impl = Some(item.owner_id);
273279
}
274280
}
275281

276-
fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
277-
if is_debug_impl(cx, item) {
278-
self.in_debug_impl = false;
282+
fn check_item_post(&mut self, _cx: &LateContext<'_>, item: &Item<'_>) {
283+
// Only clear `self.outermost_debug_impl` if we're escaping the _outermost_ debug impl
284+
if self.outermost_debug_impl == Some(item.owner_id) {
285+
self.outermost_debug_impl = None;
279286
}
280287
}
281288

@@ -329,7 +336,7 @@ impl<'tcx> LateLintPass<'tcx> for Write {
329336

330337
check_literal(cx, format_args, name);
331338

332-
if !self.in_debug_impl {
339+
if !self.in_debug_impl() {
333340
for piece in &format_args.template {
334341
if let &FormatArgsPiece::Placeholder(FormatPlaceholder {
335342
span: Some(span),

tests/ui/print.rs

Lines changed: 0 additions & 44 deletions
This file was deleted.

tests/ui/print.stderr

Lines changed: 0 additions & 56 deletions
This file was deleted.

tests/ui/print_stdout.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#![expect(clippy::print_literal)]
2+
#![warn(clippy::print_stdout)]
3+
4+
fn main() {
5+
println!("Hello");
6+
//~^ print_stdout
7+
8+
print!("Hello");
9+
//~^ print_stdout
10+
11+
print!("Hello {}", "World");
12+
//~^ print_stdout
13+
14+
print!("Hello {:?}", "World");
15+
//~^ print_stdout
16+
17+
print!("Hello {:#?}", "#orld");
18+
//~^ print_stdout
19+
20+
assert_eq!(42, 1337);
21+
22+
vec![1, 2];
23+
}

tests/ui/print_stdout.stderr

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
error: use of `println!`
2+
--> tests/ui/print_stdout.rs:5:5
3+
|
4+
LL | println!("Hello");
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::print-stdout` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::print_stdout)]`
9+
10+
error: use of `print!`
11+
--> tests/ui/print_stdout.rs:8:5
12+
|
13+
LL | print!("Hello");
14+
| ^^^^^^^^^^^^^^^
15+
16+
error: use of `print!`
17+
--> tests/ui/print_stdout.rs:11:5
18+
|
19+
LL | print!("Hello {}", "World");
20+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
21+
22+
error: use of `print!`
23+
--> tests/ui/print_stdout.rs:14:5
24+
|
25+
LL | print!("Hello {:?}", "World");
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
27+
28+
error: use of `print!`
29+
--> tests/ui/print_stdout.rs:17:5
30+
|
31+
LL | print!("Hello {:#?}", "#orld");
32+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
33+
34+
error: aborting due to 5 previous errors
35+

tests/ui/use_debug.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#![warn(clippy::use_debug)]
2+
3+
use std::fmt::{Debug, Display, Formatter, Result};
4+
5+
struct Foo;
6+
7+
impl Display for Foo {
8+
fn fmt(&self, f: &mut Formatter) -> Result {
9+
write!(f, "{:?}", 43.1415)
10+
//~^ use_debug
11+
}
12+
}
13+
14+
impl Debug for Foo {
15+
fn fmt(&self, f: &mut Formatter) -> Result {
16+
// ok, we can use `Debug` formatting in `Debug` implementations
17+
write!(f, "{:?}", 42.718)
18+
}
19+
}
20+
21+
fn main() {
22+
print!("Hello {:?}", "World");
23+
//~^ use_debug
24+
25+
print!("Hello {:#?}", "#orld");
26+
//~^ use_debug
27+
28+
assert_eq!(42, 1337);
29+
30+
vec![1, 2];
31+
}
32+
33+
// don't get confused by nested impls
34+
fn issue15942() {
35+
struct Bar;
36+
impl Debug for Bar {
37+
fn fmt(&self, f: &mut Formatter) -> Result {
38+
struct Baz;
39+
impl Debug for Baz {
40+
fn fmt(&self, f: &mut Formatter) -> Result {
41+
// ok, we can use `Debug` formatting in `Debug` implementations
42+
write!(f, "{:?}", 42.718)
43+
}
44+
}
45+
46+
// ok, we can use `Debug` formatting in `Debug` implementations
47+
write!(f, "{:?}", 42.718)
48+
}
49+
}
50+
}

tests/ui/use_debug.stderr

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error: use of `Debug`-based formatting
2+
--> tests/ui/use_debug.rs:9:20
3+
|
4+
LL | write!(f, "{:?}", 43.1415)
5+
| ^^^^
6+
|
7+
= note: `-D clippy::use-debug` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::use_debug)]`
9+
10+
error: use of `Debug`-based formatting
11+
--> tests/ui/use_debug.rs:22:19
12+
|
13+
LL | print!("Hello {:?}", "World");
14+
| ^^^^
15+
16+
error: use of `Debug`-based formatting
17+
--> tests/ui/use_debug.rs:25:19
18+
|
19+
LL | print!("Hello {:#?}", "#orld");
20+
| ^^^^^
21+
22+
error: aborting due to 3 previous errors
23+

0 commit comments

Comments
 (0)