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