]> git.proxmox.com Git - rustc.git/blob - src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_string_with_char.rs
New upstream version 1.64.0+dfsg1
[rustc.git] / src / tools / rust-analyzer / crates / ide-assists / src / handlers / replace_string_with_char.rs
1 use syntax::{
2 ast,
3 ast::IsString,
4 AstToken,
5 SyntaxKind::{CHAR, STRING},
6 TextRange, TextSize,
7 };
8
9 use crate::{AssistContext, AssistId, AssistKind, Assists};
10
11 // Assist: replace_string_with_char
12 //
13 // Replace string literal with char literal.
14 //
15 // ```
16 // fn main() {
17 // find("{$0");
18 // }
19 // ```
20 // ->
21 // ```
22 // fn main() {
23 // find('{');
24 // }
25 // ```
26 pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
27 let token = ctx.find_token_syntax_at_offset(STRING).and_then(ast::String::cast)?;
28 let value = token.value()?;
29 let target = token.syntax().text_range();
30
31 if value.chars().take(2).count() != 1 {
32 return None;
33 }
34 let quote_offets = token.quote_offsets()?;
35
36 acc.add(
37 AssistId("replace_string_with_char", AssistKind::RefactorRewrite),
38 "Replace string with char",
39 target,
40 |edit| {
41 let (left, right) = quote_offets.quotes;
42 edit.replace(left, '\'');
43 edit.replace(right, '\'');
44 if value == "'" {
45 edit.insert(left.end(), '\\');
46 }
47 },
48 )
49 }
50
51 // Assist: replace_char_with_string
52 //
53 // Replace a char literal with a string literal.
54 //
55 // ```
56 // fn main() {
57 // find('{$0');
58 // }
59 // ```
60 // ->
61 // ```
62 // fn main() {
63 // find("{");
64 // }
65 // ```
66 pub(crate) fn replace_char_with_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
67 let token = ctx.find_token_syntax_at_offset(CHAR)?;
68 let target = token.text_range();
69
70 acc.add(
71 AssistId("replace_char_with_string", AssistKind::RefactorRewrite),
72 "Replace char with string",
73 target,
74 |edit| {
75 if token.text() == "'\"'" {
76 edit.replace(token.text_range(), r#""\"""#);
77 } else {
78 let len = TextSize::of('\'');
79 edit.replace(TextRange::at(target.start(), len), '"');
80 edit.replace(TextRange::at(target.end() - len, len), '"');
81 }
82 },
83 )
84 }
85
86 #[cfg(test)]
87 mod tests {
88 use crate::tests::{check_assist, check_assist_not_applicable};
89
90 use super::*;
91
92 #[test]
93 fn replace_string_with_char_assist() {
94 check_assist(
95 replace_string_with_char,
96 r#"
97 fn f() {
98 let s = "$0c";
99 }
100 "#,
101 r##"
102 fn f() {
103 let s = 'c';
104 }
105 "##,
106 )
107 }
108
109 #[test]
110 fn replace_string_with_char_assist_with_multi_byte_char() {
111 check_assist(
112 replace_string_with_char,
113 r#"
114 fn f() {
115 let s = "$0😀";
116 }
117 "#,
118 r##"
119 fn f() {
120 let s = '😀';
121 }
122 "##,
123 )
124 }
125
126 #[test]
127 fn replace_string_with_char_multiple_chars() {
128 check_assist_not_applicable(
129 replace_string_with_char,
130 r#"
131 fn f() {
132 let s = "$0test";
133 }
134 "#,
135 )
136 }
137
138 #[test]
139 fn replace_string_with_char_works_inside_macros() {
140 check_assist(
141 replace_string_with_char,
142 r#"
143 fn f() {
144 format!($0"x", 92)
145 }
146 "#,
147 r##"
148 fn f() {
149 format!('x', 92)
150 }
151 "##,
152 )
153 }
154
155 #[test]
156 fn replace_string_with_char_newline() {
157 check_assist(
158 replace_string_with_char,
159 r#"
160 fn f() {
161 find($0"\n");
162 }
163 "#,
164 r##"
165 fn f() {
166 find('\n');
167 }
168 "##,
169 )
170 }
171
172 #[test]
173 fn replace_string_with_char_unicode_escape() {
174 check_assist(
175 replace_string_with_char,
176 r#"
177 fn f() {
178 find($0"\u{7FFF}");
179 }
180 "#,
181 r##"
182 fn f() {
183 find('\u{7FFF}');
184 }
185 "##,
186 )
187 }
188
189 #[test]
190 fn replace_raw_string_with_char() {
191 check_assist(
192 replace_string_with_char,
193 r##"
194 fn f() {
195 $0r#"X"#
196 }
197 "##,
198 r##"
199 fn f() {
200 'X'
201 }
202 "##,
203 )
204 }
205
206 #[test]
207 fn replace_char_with_string_assist() {
208 check_assist(
209 replace_char_with_string,
210 r"
211 fn f() {
212 let s = '$0c';
213 }
214 ",
215 r#"
216 fn f() {
217 let s = "c";
218 }
219 "#,
220 )
221 }
222
223 #[test]
224 fn replace_char_with_string_assist_with_multi_byte_char() {
225 check_assist(
226 replace_char_with_string,
227 r"
228 fn f() {
229 let s = '$0😀';
230 }
231 ",
232 r#"
233 fn f() {
234 let s = "😀";
235 }
236 "#,
237 )
238 }
239
240 #[test]
241 fn replace_char_with_string_newline() {
242 check_assist(
243 replace_char_with_string,
244 r"
245 fn f() {
246 find($0'\n');
247 }
248 ",
249 r#"
250 fn f() {
251 find("\n");
252 }
253 "#,
254 )
255 }
256
257 #[test]
258 fn replace_char_with_string_unicode_escape() {
259 check_assist(
260 replace_char_with_string,
261 r"
262 fn f() {
263 find($0'\u{7FFF}');
264 }
265 ",
266 r#"
267 fn f() {
268 find("\u{7FFF}");
269 }
270 "#,
271 )
272 }
273
274 #[test]
275 fn replace_char_with_string_quote() {
276 check_assist(
277 replace_char_with_string,
278 r#"
279 fn f() {
280 find($0'"');
281 }
282 "#,
283 r#"
284 fn f() {
285 find("\"");
286 }
287 "#,
288 )
289 }
290
291 #[test]
292 fn replace_string_with_char_quote() {
293 check_assist(
294 replace_string_with_char,
295 r#"
296 fn f() {
297 find($0"'");
298 }
299 "#,
300 r#"
301 fn f() {
302 find('\'');
303 }
304 "#,
305 )
306 }
307 }