@@ -35,6 +35,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option<Vec<Assi
3535 add_reference ( ctx, d, & mut fixes) ;
3636 add_missing_ok_or_some ( ctx, d, & mut fixes) ;
3737 remove_semicolon ( ctx, d, & mut fixes) ;
38+ str_ref_to_string ( ctx, d, & mut fixes) ;
3839
3940 if fixes. is_empty ( ) {
4041 None
@@ -134,6 +135,32 @@ fn remove_semicolon(
134135 Some ( ( ) )
135136}
136137
138+ fn str_ref_to_string (
139+ ctx : & DiagnosticsContext < ' _ > ,
140+ d : & hir:: TypeMismatch ,
141+ acc : & mut Vec < Assist > ,
142+ ) -> Option < ( ) > {
143+ let expected = d. expected . display ( ctx. sema . db ) ;
144+ let actual = d. actual . display ( ctx. sema . db ) ;
145+
146+ if expected. to_string ( ) != "String" || actual. to_string ( ) != "&str" {
147+ return None ;
148+ }
149+
150+ let root = ctx. sema . db . parse_or_expand ( d. expr . file_id ) ?;
151+ let expr = d. expr . value . to_node ( & root) ;
152+ let expr_range = expr. syntax ( ) . text_range ( ) ;
153+
154+ let to_string = format ! ( ".to_string()" ) ;
155+
156+ let edit = TextEdit :: insert ( expr. syntax ( ) . text_range ( ) . end ( ) , to_string) ;
157+ let source_change =
158+ SourceChange :: from_text_edit ( d. expr . file_id . original_file ( ctx. sema . db ) , edit) ;
159+ acc. push ( fix ( "str_ref_to_string" , "Use to_string() here" , source_change, expr_range) ) ;
160+
161+ Some ( ( ) )
162+ }
163+
137164#[ cfg( test) ]
138165mod tests {
139166 use crate :: tests:: { check_diagnostics, check_fix, check_no_fix} ;
@@ -498,4 +525,20 @@ fn foo() -> SomeOtherEnum { 0$0 }
498525 fn remove_semicolon ( ) {
499526 check_fix ( r#"fn f() -> i32 { 92$0; }"# , r#"fn f() -> i32 { 92 }"# ) ;
500527 }
528+
529+ #[ test]
530+ fn str_ref_to_string ( ) {
531+ check_fix (
532+ r#"
533+ fn test() -> String {
534+ "a"$0
535+ }
536+ "# ,
537+ r#"
538+ fn test() -> String {
539+ "a".to_string()
540+ }
541+ "# ,
542+ ) ;
543+ }
501544}
0 commit comments