@@ -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" , "Add .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,24 @@ 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+ struct String;
534+
535+ fn test() -> String {
536+ "a"$0
537+ }
538+ "# ,
539+ r#"
540+ struct String;
541+
542+ fn test() -> String {
543+ "a".to_string()
544+ }
545+ "# ,
546+ ) ;
547+ }
501548}
0 commit comments