2021-03-25 13:29:11 -05:00
use clippy_utils ::diagnostics ::span_lint_and_help ;
2022-07-05 11:56:16 -05:00
use clippy_utils ::ty ::{ implements_trait , is_type_lang_item } ;
2022-10-06 02:44:38 -05:00
use clippy_utils ::{ return_ty , trait_ref_of_method } ;
2024-05-17 12:17:48 -05:00
use rustc_hir ::{ GenericParamKind , ImplItem , ImplItemKind , LangItem , Safety } ;
2020-01-12 00:08:41 -06:00
use rustc_lint ::{ LateContext , LateLintPass } ;
2023-12-01 11:21:58 -06:00
use rustc_session ::declare_lint_pass ;
2020-11-05 07:29:48 -06:00
use rustc_span ::sym ;
2023-07-31 16:53:53 -05:00
use rustc_target ::spec ::abi ::Abi ;
2019-07-06 13:13:38 -05:00
declare_clippy_lint! {
2021-07-29 05:16:06 -05:00
/// ### What it does
/// Checks for the definition of inherent methods with a signature of `to_string(&self) -> String`.
2019-07-06 13:13:38 -05:00
///
2021-07-29 05:16:06 -05:00
/// ### Why is this bad?
/// This method is also implicitly defined if a type implements the `Display` trait. As the functionality of `Display` is much more versatile, it should be preferred.
2019-07-06 13:13:38 -05:00
///
2021-07-29 05:16:06 -05:00
/// ### Example
2023-11-02 11:35:56 -05:00
/// ```no_run
2019-07-06 13:13:38 -05:00
/// pub struct A;
///
/// impl A {
/// pub fn to_string(&self) -> String {
/// "I am A".to_string()
/// }
/// }
2019-07-15 11:43:47 -05:00
/// ```
///
2022-06-16 10:39:06 -05:00
/// Use instead:
2023-11-02 11:35:56 -05:00
/// ```no_run
2019-07-06 13:13:38 -05:00
/// use std::fmt;
///
/// pub struct A;
///
/// impl fmt::Display for A {
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
/// write!(f, "I am A")
/// }
/// }
/// ```
2021-12-06 05:33:31 -06:00
#[ clippy::version = " 1.38.0 " ]
2019-07-06 13:13:38 -05:00
pub INHERENT_TO_STRING ,
style ,
2019-07-15 11:43:47 -05:00
" type implements inherent method `to_string()`, but should instead implement the `Display` trait "
2019-07-06 13:13:38 -05:00
}
declare_clippy_lint! {
2021-07-29 05:16:06 -05:00
/// ### What it does
/// Checks for the definition of inherent methods with a signature of `to_string(&self) -> String` and if the type implementing this method also implements the `Display` trait.
2019-07-06 13:13:38 -05:00
///
2021-07-29 05:16:06 -05:00
/// ### Why is this bad?
/// This method is also implicitly defined if a type implements the `Display` trait. The less versatile inherent method will then shadow the implementation introduced by `Display`.
2019-07-06 13:13:38 -05:00
///
2021-07-29 05:16:06 -05:00
/// ### Example
2023-11-02 11:35:56 -05:00
/// ```no_run
2019-07-06 13:13:38 -05:00
/// use std::fmt;
///
/// pub struct A;
///
/// impl A {
/// pub fn to_string(&self) -> String {
/// "I am A".to_string()
/// }
/// }
///
/// impl fmt::Display for A {
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
/// write!(f, "I am A, too")
/// }
/// }
2019-07-15 11:43:47 -05:00
/// ```
///
2022-06-16 10:39:06 -05:00
/// Use instead:
2023-11-02 11:35:56 -05:00
/// ```no_run
2019-07-06 13:13:38 -05:00
/// use std::fmt;
///
/// pub struct A;
///
/// impl fmt::Display for A {
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
/// write!(f, "I am A")
/// }
/// }
/// ```
2021-12-06 05:33:31 -06:00
#[ clippy::version = " 1.38.0 " ]
2019-07-06 13:13:38 -05:00
pub INHERENT_TO_STRING_SHADOW_DISPLAY ,
correctness ,
2020-01-06 00:30:43 -06:00
" type implements inherent method `to_string()`, which gets shadowed by the implementation of the `Display` trait "
2019-07-06 13:13:38 -05:00
}
declare_lint_pass! ( InherentToString = > [ INHERENT_TO_STRING , INHERENT_TO_STRING_SHADOW_DISPLAY ] ) ;
2020-06-25 15:41:36 -05:00
impl < ' tcx > LateLintPass < ' tcx > for InherentToString {
fn check_impl_item ( & mut self , cx : & LateContext < ' tcx > , impl_item : & ' tcx ImplItem < '_ > ) {
2023-07-31 16:53:53 -05:00
// Check if item is a method called `to_string` and has a parameter 'self'
if let ImplItemKind ::Fn ( ref signature , _ ) = impl_item . kind
// #11201
& & let header = signature . header
2024-05-17 12:17:48 -05:00
& & header . safety = = Safety ::Safe
2023-07-31 16:53:53 -05:00
& & header . abi = = Abi ::Rust
& & impl_item . ident . name = = sym ::to_string
& & let decl = signature . decl
& & decl . implicit_self . has_implicit_self ( )
& & decl . inputs . len ( ) = = 1
& & impl_item . generics . params . iter ( ) . all ( | p | matches! ( p . kind , GenericParamKind ::Lifetime { .. } ) )
2024-07-11 08:44:03 -05:00
& & ! impl_item . span . from_expansion ( )
2019-07-06 13:13:38 -05:00
// Check if return type is String
2023-07-31 16:53:53 -05:00
& & is_type_lang_item ( cx , return_ty ( cx , impl_item . owner_id ) , LangItem ::String )
2019-07-06 13:13:38 -05:00
// Filters instances of to_string which are required by a trait
2023-07-31 16:53:53 -05:00
& & trait_ref_of_method ( cx , impl_item . owner_id . def_id ) . is_none ( )
{
show_lint ( cx , impl_item ) ;
2019-07-06 13:13:38 -05:00
}
}
}
2020-06-25 15:41:36 -05:00
fn show_lint ( cx : & LateContext < '_ > , item : & ImplItem < '_ > ) {
2022-10-06 02:44:38 -05:00
let display_trait_id = cx
. tcx
. get_diagnostic_item ( sym ::Display )
. expect ( " Failed to get trait ID of `Display`! " ) ;
2019-07-06 13:13:38 -05:00
// Get the real type of 'self'
2023-01-18 17:52:47 -06:00
let self_type = cx . tcx . fn_sig ( item . owner_id ) . skip_binder ( ) . input ( 0 ) ;
2020-09-24 07:49:22 -05:00
let self_type = self_type . skip_binder ( ) . peel_refs ( ) ;
2019-07-06 13:13:38 -05:00
// Emit either a warning or an error
if implements_trait ( cx , self_type , display_trait_id , & [ ] ) {
2020-01-26 19:56:22 -06:00
span_lint_and_help (
2019-07-06 13:13:38 -05:00
cx ,
INHERENT_TO_STRING_SHADOW_DISPLAY ,
item . span ,
2024-04-04 12:52:55 -05:00
format! (
2022-10-06 02:44:38 -05:00
" type `{self_type}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display` "
2019-07-06 13:13:38 -05:00
) ,
2020-04-18 05:28:29 -05:00
None ,
2024-04-04 12:52:55 -05:00
format! ( " remove the inherent method from type ` {self_type} ` " ) ,
2019-07-06 13:13:38 -05:00
) ;
} else {
2020-01-26 19:56:22 -06:00
span_lint_and_help (
2019-07-06 13:13:38 -05:00
cx ,
INHERENT_TO_STRING ,
item . span ,
2024-04-04 12:52:55 -05:00
format! ( " implementation of inherent method `to_string(&self) -> String` for type ` {self_type} ` " ) ,
2020-04-18 05:28:29 -05:00
None ,
2024-04-04 12:52:55 -05:00
format! ( " implement trait `Display` for type ` {self_type} ` instead " ) ,
2019-07-06 13:13:38 -05:00
) ;
}
}