@@ -2,6 +2,7 @@ use rustc_errors::Applicability;
2
2
use rustc_hir:: { BinOpKind , BorrowKind , Expr , ExprKind , LangItem , QPath } ;
3
3
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
4
4
use rustc_middle:: lint:: in_external_macro;
5
+ use rustc_middle:: ty;
5
6
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
6
7
use rustc_span:: source_map:: Spanned ;
7
8
use rustc_span:: sym;
@@ -11,7 +12,7 @@ use if_chain::if_chain;
11
12
use crate :: utils:: SpanlessEq ;
12
13
use crate :: utils:: {
13
14
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,
15
16
} ;
16
17
17
18
declare_clippy_lint ! {
@@ -289,3 +290,100 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
289
290
}
290
291
}
291
292
}
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