mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-12-24 03:53:20 +00:00
334 lines
7.2 KiB
Rust
334 lines
7.2 KiB
Rust
#![warn(clippy::recursive_format_impl)]
|
|
#![allow(
|
|
clippy::borrow_deref_ref,
|
|
clippy::deref_addrof,
|
|
clippy::inherent_to_string_shadow_display,
|
|
clippy::to_string_in_format_args,
|
|
clippy::uninlined_format_args
|
|
)]
|
|
|
|
use std::fmt;
|
|
|
|
struct A;
|
|
impl A {
|
|
fn fmt(&self) {
|
|
self.to_string();
|
|
}
|
|
}
|
|
|
|
trait B {
|
|
fn fmt(&self) {}
|
|
}
|
|
|
|
impl B for A {
|
|
fn fmt(&self) {
|
|
self.to_string();
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for A {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{}", self.to_string())
|
|
//~^ ERROR: using `self.to_string` in `fmt::Display` implementation will cause inf
|
|
//~| NOTE: `-D clippy::recursive-format-impl` implied by `-D warnings`
|
|
}
|
|
}
|
|
|
|
fn fmt(a: A) {
|
|
a.to_string();
|
|
}
|
|
|
|
struct C;
|
|
|
|
impl C {
|
|
// Doesn't trigger if to_string defined separately
|
|
// i.e. not using ToString trait (from Display)
|
|
fn to_string(&self) -> String {
|
|
String::from("I am C")
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for C {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{}", self.to_string())
|
|
}
|
|
}
|
|
|
|
enum D {
|
|
E(String),
|
|
F,
|
|
}
|
|
|
|
impl std::fmt::Display for D {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match &self {
|
|
Self::E(string) => write!(f, "E {}", string.to_string()),
|
|
Self::F => write!(f, "F"),
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check for use of self as Display, in Display impl
|
|
// Triggers on direct use of self
|
|
struct G;
|
|
|
|
impl std::fmt::Display for G {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", self)
|
|
//~^ ERROR: using `self` as `Display` in `impl Display` will cause infinite recurs
|
|
}
|
|
}
|
|
|
|
// Triggers on reference to self
|
|
struct H;
|
|
|
|
impl std::fmt::Display for H {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", &self)
|
|
//~^ ERROR: using `self` as `Display` in `impl Display` will cause infinite recurs
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Debug for H {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{:?}", &self)
|
|
//~^ ERROR: using `self` as `Debug` in `impl Debug` will cause infinite recursion
|
|
}
|
|
}
|
|
|
|
// Triggers on multiple reference to self
|
|
struct H2;
|
|
|
|
impl std::fmt::Display for H2 {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", &&&self)
|
|
//~^ ERROR: using `self` as `Display` in `impl Display` will cause infinite recurs
|
|
}
|
|
}
|
|
|
|
// Doesn't trigger on correct deref
|
|
struct I;
|
|
|
|
impl std::ops::Deref for I {
|
|
type Target = str;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
"test"
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for I {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(f, "{}", &**self)
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Debug for I {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(f, "{:?}", &**self)
|
|
}
|
|
}
|
|
|
|
// Doesn't trigger on multiple correct deref
|
|
struct I2;
|
|
|
|
impl std::ops::Deref for I2 {
|
|
type Target = str;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
"test"
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for I2 {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(f, "{}", **&&&**self)
|
|
}
|
|
}
|
|
|
|
// Doesn't trigger on multiple correct deref
|
|
struct I3;
|
|
|
|
impl std::ops::Deref for I3 {
|
|
type Target = str;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
"test"
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for I3 {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(f, "{}", &&**&&&**self)
|
|
}
|
|
}
|
|
|
|
// Does trigger when deref resolves to self
|
|
struct J;
|
|
|
|
impl std::ops::Deref for J {
|
|
type Target = str;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
"test"
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for J {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(f, "{}", &*self)
|
|
//~^ ERROR: using `self` as `Display` in `impl Display` will cause infinite recurs
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Debug for J {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(f, "{:?}", &*self)
|
|
//~^ ERROR: using `self` as `Debug` in `impl Debug` will cause infinite recursion
|
|
}
|
|
}
|
|
|
|
struct J2;
|
|
|
|
impl std::ops::Deref for J2 {
|
|
type Target = str;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
"test"
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for J2 {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(f, "{}", *self)
|
|
//~^ ERROR: using `self` as `Display` in `impl Display` will cause infinite recurs
|
|
}
|
|
}
|
|
|
|
struct J3;
|
|
|
|
impl std::ops::Deref for J3 {
|
|
type Target = str;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
"test"
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for J3 {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(f, "{}", **&&*self)
|
|
//~^ ERROR: using `self` as `Display` in `impl Display` will cause infinite recurs
|
|
}
|
|
}
|
|
|
|
struct J4;
|
|
|
|
impl std::ops::Deref for J4 {
|
|
type Target = str;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
"test"
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for J4 {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(f, "{}", &&**&&*self)
|
|
//~^ ERROR: using `self` as `Display` in `impl Display` will cause infinite recurs
|
|
}
|
|
}
|
|
|
|
// Doesn't trigger on Debug from Display
|
|
struct K;
|
|
|
|
impl std::fmt::Debug for K {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(f, "test")
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for K {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(f, "{:?}", self)
|
|
}
|
|
}
|
|
|
|
// Doesn't trigger on Display from Debug
|
|
struct K2;
|
|
|
|
impl std::fmt::Debug for K2 {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(f, "{}", self)
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for K2 {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(f, "test")
|
|
}
|
|
}
|
|
|
|
// Doesn't trigger on struct fields
|
|
struct L {
|
|
field1: u32,
|
|
field2: i32,
|
|
}
|
|
|
|
impl std::fmt::Display for L {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(f, "{},{}", self.field1, self.field2)
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Debug for L {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(f, "{:?},{:?}", self.field1, self.field2)
|
|
}
|
|
}
|
|
|
|
// Doesn't trigger on nested enum matching
|
|
enum Tree {
|
|
Leaf,
|
|
Node(Vec<Tree>),
|
|
}
|
|
|
|
impl std::fmt::Display for Tree {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
match self {
|
|
Tree::Leaf => write!(f, "*"),
|
|
Tree::Node(children) => {
|
|
write!(f, "(")?;
|
|
for child in children.iter() {
|
|
write!(f, "{},", child)?;
|
|
}
|
|
write!(f, ")")
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Debug for Tree {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
match self {
|
|
Tree::Leaf => write!(f, "*"),
|
|
Tree::Node(children) => {
|
|
write!(f, "(")?;
|
|
for child in children.iter() {
|
|
write!(f, "{:?},", child)?;
|
|
}
|
|
write!(f, ")")
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let a = A;
|
|
a.to_string();
|
|
a.fmt();
|
|
fmt(a);
|
|
|
|
let c = C;
|
|
c.to_string();
|
|
}
|