#![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()) } } 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) } } // 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) } } impl std::fmt::Debug for H { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", &self) } } // 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) } } // 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) } } impl std::fmt::Debug for J { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{:?}", &*self) } } 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) } } 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) } } 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) } } // 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(); }