@@ -2,6 +2,7 @@ use rustc_errors::Applicability;
22use rustc_hir:: { BinOpKind , BorrowKind , Expr , ExprKind , LangItem , QPath } ;
33use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
44use rustc_middle:: lint:: in_external_macro;
5+ use rustc_middle:: ty;
56use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
67use rustc_span:: source_map:: Spanned ;
78use rustc_span:: sym;
@@ -11,7 +12,7 @@ use if_chain::if_chain;
1112use crate :: utils:: SpanlessEq ;
1213use crate :: utils:: {
1314 get_parent_expr, is_allowed, is_type_diagnostic_item, match_function_call, method_calls, paths, span_lint,
14- span_lint_and_sugg,
15+ span_lint_and_help , span_lint_and_sugg,
1516} ;
1617
1718declare_clippy_lint ! {
@@ -289,3 +290,100 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
289290 }
290291 }
291292}
293+
294+ declare_clippy_lint ! {
295+ /// **What it does:** This lint checks for `.to_string()` method calls on values of type `&str`.
296+ ///
297+ /// **Why is this bad?** The `to_string` method is also used on other types to convert them to a string.
298+ /// When called on a `&str` it turns the `&str` into the owned variant `String`, which can be better
299+ /// expressed with `.to_owned()`.
300+ ///
301+ /// **Known problems:** None.
302+ ///
303+ /// **Example:**
304+ ///
305+ /// ```rust
306+ /// // example code where clippy issues a warning
307+ /// let _ = "str".to_string();
308+ /// ```
309+ /// Use instead:
310+ /// ```rust
311+ /// // example code which does not raise clippy warning
312+ /// let _ = "str".to_owned();
313+ /// ```
314+ pub STR_TO_STRING ,
315+ restriction,
316+ "using `to_string()` on a `&str`, which should be `to_owned()`"
317+ }
318+
319+ declare_lint_pass ! ( StrToString => [ STR_TO_STRING ] ) ;
320+
321+ impl LateLintPass < ' _ > for StrToString {
322+ fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & Expr < ' _ > ) {
323+ if_chain ! {
324+ if let ExprKind :: MethodCall ( path, _, args, _) = & expr. kind;
325+ if path. ident. name == sym!( to_string) ;
326+ let ty = cx. typeck_results( ) . expr_ty( & args[ 0 ] ) ;
327+ if let ty:: Ref ( _, ty, ..) = ty. kind( ) ;
328+ if * ty. kind( ) == ty:: Str ;
329+ then {
330+ span_lint_and_help(
331+ cx,
332+ STR_TO_STRING ,
333+ expr. span,
334+ "`to_string()` called on a `&str`" ,
335+ None ,
336+ "consider using `.to_owned()`" ,
337+ ) ;
338+ }
339+ }
340+ }
341+ }
342+
343+ declare_clippy_lint ! {
344+ /// **What it does:** This lint checks for `.to_string()` method calls on values of type `String`.
345+ ///
346+ /// **Why is this bad?** The `to_string` method is also used on other types to convert them to a string.
347+ /// When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`.
348+ /// **Known problems:** None.
349+ ///
350+ /// **Example:**
351+ ///
352+ /// ```rust
353+ /// // example code where clippy issues a warning
354+ /// let msg = String::from("Hello World");
355+ /// let _ = msg.to_string();
356+ /// ```
357+ /// Use instead:
358+ /// ```rust
359+ /// // example code which does not raise clippy warning
360+ /// let msg = String::from("Hello World");
361+ /// let _ = msg.clone();
362+ /// ```
363+ pub STRING_TO_STRING ,
364+ restriction,
365+ "using `to_string()` on a `String`, which should be `clone()`"
366+ }
367+
368+ declare_lint_pass ! ( StringToString => [ STRING_TO_STRING ] ) ;
369+
370+ impl LateLintPass < ' _ > for StringToString {
371+ fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & Expr < ' _ > ) {
372+ if_chain ! {
373+ if let ExprKind :: MethodCall ( path, _, args, _) = & expr. kind;
374+ if path. ident. name == sym!( to_string) ;
375+ let ty = cx. typeck_results( ) . expr_ty( & args[ 0 ] ) ;
376+ if is_type_diagnostic_item( cx, ty, sym!( string_type) ) ;
377+ then {
378+ span_lint_and_help(
379+ cx,
380+ STRING_TO_STRING ,
381+ expr. span,
382+ "`to_string()` called on a `String`" ,
383+ None ,
384+ "consider using `.clone()`" ,
385+ ) ;
386+ }
387+ }
388+ }
389+ }
0 commit comments