diff options
author | Florian Diebold <[email protected]> | 2019-09-22 19:01:12 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-09-22 19:02:32 +0100 |
commit | 18bf278c258f44ed68f67f84993f20f7c27c63d0 (patch) | |
tree | 3c07347cee581c61107950b1ed9daed191027f5b /crates/ra_assists/src | |
parent | 468e1d14c1a4b3d646207ae919082dc17753cd31 (diff) |
Handle associated type shorthand (`T::Item`)
This is only allowed for generic parameters (including `Self` in traits), and
special care needs to be taken to not run into cycles while resolving it,
because we use the where clauses of the generic parameter to find candidates for
the trait containing the associated type, but the where clauses may themselves
contain instances of short-hand associated types.
In some cases this is even fine, e.g. we might have `T: Trait<U::Item>, U:
Iterator`. If there is a cycle, we'll currently panic, which isn't great, but
better than overflowing the stack...
Diffstat (limited to 'crates/ra_assists/src')
-rw-r--r-- | crates/ra_assists/src/raw_string.rs | 740 |
1 files changed, 370 insertions, 370 deletions
diff --git a/crates/ra_assists/src/raw_string.rs b/crates/ra_assists/src/raw_string.rs index e00267060..965a64c98 100644 --- a/crates/ra_assists/src/raw_string.rs +++ b/crates/ra_assists/src/raw_string.rs | |||
@@ -1,370 +1,370 @@ | |||
1 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
2 | use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; | 2 | use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; |
3 | 3 | ||
4 | use crate::{Assist, AssistCtx, AssistId}; | 4 | use crate::{Assist, AssistCtx, AssistId}; |
5 | 5 | ||
6 | pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 6 | pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
7 | let literal = ctx.node_at_offset::<Literal>()?; | 7 | let literal = ctx.node_at_offset::<Literal>()?; |
8 | if literal.token().kind() != ra_syntax::SyntaxKind::STRING { | 8 | if literal.token().kind() != ra_syntax::SyntaxKind::STRING { |
9 | return None; | 9 | return None; |
10 | } | 10 | } |
11 | ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| { | 11 | ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| { |
12 | edit.target(literal.syntax().text_range()); | 12 | edit.target(literal.syntax().text_range()); |
13 | edit.insert(literal.syntax().text_range().start(), "r"); | 13 | edit.insert(literal.syntax().text_range().start(), "r"); |
14 | }); | 14 | }); |
15 | ctx.build() | 15 | ctx.build() |
16 | } | 16 | } |
17 | 17 | ||
18 | fn find_usual_string_range(s: &str) -> Option<TextRange> { | 18 | fn find_usual_string_range(s: &str) -> Option<TextRange> { |
19 | Some(TextRange::from_to( | 19 | Some(TextRange::from_to( |
20 | TextUnit::from(s.find('"')? as u32), | 20 | TextUnit::from(s.find('"')? as u32), |
21 | TextUnit::from(s.rfind('"')? as u32), | 21 | TextUnit::from(s.rfind('"')? as u32), |
22 | )) | 22 | )) |
23 | } | 23 | } |
24 | 24 | ||
25 | pub(crate) fn make_usual_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 25 | pub(crate) fn make_usual_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
26 | let literal = ctx.node_at_offset::<Literal>()?; | 26 | let literal = ctx.node_at_offset::<Literal>()?; |
27 | if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { | 27 | if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { |
28 | return None; | 28 | return None; |
29 | } | 29 | } |
30 | let token = literal.token(); | 30 | let token = literal.token(); |
31 | let text = token.text().as_str(); | 31 | let text = token.text().as_str(); |
32 | let usual_string_range = find_usual_string_range(text)?; | 32 | let usual_string_range = find_usual_string_range(text)?; |
33 | ctx.add_action(AssistId("make_usual_string"), "make usual string", |edit| { | 33 | ctx.add_action(AssistId("make_usual_string"), "make usual string", |edit| { |
34 | edit.target(literal.syntax().text_range()); | 34 | edit.target(literal.syntax().text_range()); |
35 | // parse inside string to escape `"` | 35 | // parse inside string to escape `"` |
36 | let start_of_inside = usual_string_range.start().to_usize() + 1; | 36 | let start_of_inside = usual_string_range.start().to_usize() + 1; |
37 | let end_of_inside = usual_string_range.end().to_usize(); | 37 | let end_of_inside = usual_string_range.end().to_usize(); |
38 | let inside_str = &text[start_of_inside..end_of_inside]; | 38 | let inside_str = &text[start_of_inside..end_of_inside]; |
39 | let escaped = inside_str.escape_default().to_string(); | 39 | let escaped = inside_str.escape_default().to_string(); |
40 | edit.replace(literal.syntax().text_range(), format!("\"{}\"", escaped)); | 40 | edit.replace(literal.syntax().text_range(), format!("\"{}\"", escaped)); |
41 | }); | 41 | }); |
42 | ctx.build() | 42 | ctx.build() |
43 | } | 43 | } |
44 | 44 | ||
45 | pub(crate) fn add_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 45 | pub(crate) fn add_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
46 | let literal = ctx.node_at_offset::<Literal>()?; | 46 | let literal = ctx.node_at_offset::<Literal>()?; |
47 | if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { | 47 | if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { |
48 | return None; | 48 | return None; |
49 | } | 49 | } |
50 | ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| { | 50 | ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| { |
51 | edit.target(literal.syntax().text_range()); | 51 | edit.target(literal.syntax().text_range()); |
52 | edit.insert(literal.syntax().text_range().start() + TextUnit::of_char('r'), "#"); | 52 | edit.insert(literal.syntax().text_range().start() + TextUnit::of_char('r'), "#"); |
53 | edit.insert(literal.syntax().text_range().end(), "#"); | 53 | edit.insert(literal.syntax().text_range().end(), "#"); |
54 | }); | 54 | }); |
55 | ctx.build() | 55 | ctx.build() |
56 | } | 56 | } |
57 | 57 | ||
58 | pub(crate) fn remove_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 58 | pub(crate) fn remove_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
59 | let literal = ctx.node_at_offset::<Literal>()?; | 59 | let literal = ctx.node_at_offset::<Literal>()?; |
60 | if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { | 60 | if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { |
61 | return None; | 61 | return None; |
62 | } | 62 | } |
63 | let token = literal.token(); | 63 | let token = literal.token(); |
64 | let text = token.text().as_str(); | 64 | let text = token.text().as_str(); |
65 | if text.starts_with("r\"") { | 65 | if text.starts_with("r\"") { |
66 | // no hash to remove | 66 | // no hash to remove |
67 | return None; | 67 | return None; |
68 | } | 68 | } |
69 | ctx.add_action(AssistId("remove_hash"), "remove hash from raw string", |edit| { | 69 | ctx.add_action(AssistId("remove_hash"), "remove hash from raw string", |edit| { |
70 | edit.target(literal.syntax().text_range()); | 70 | edit.target(literal.syntax().text_range()); |
71 | let result = &text[2..text.len() - 1]; | 71 | let result = &text[2..text.len() - 1]; |
72 | let result = if result.starts_with("\"") { | 72 | let result = if result.starts_with("\"") { |
73 | // no more hash, escape | 73 | // no more hash, escape |
74 | let internal_str = &result[1..result.len() - 1]; | 74 | let internal_str = &result[1..result.len() - 1]; |
75 | format!("\"{}\"", internal_str.escape_default().to_string()) | 75 | format!("\"{}\"", internal_str.escape_default().to_string()) |
76 | } else { | 76 | } else { |
77 | result.to_owned() | 77 | result.to_owned() |
78 | }; | 78 | }; |
79 | edit.replace(literal.syntax().text_range(), format!("r{}", result)); | 79 | edit.replace(literal.syntax().text_range(), format!("r{}", result)); |
80 | }); | 80 | }); |
81 | ctx.build() | 81 | ctx.build() |
82 | } | 82 | } |
83 | 83 | ||
84 | #[cfg(test)] | 84 | #[cfg(test)] |
85 | mod test { | 85 | mod test { |
86 | use super::*; | 86 | use super::*; |
87 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 87 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; |
88 | 88 | ||
89 | #[test] | 89 | #[test] |
90 | fn make_raw_string_target() { | 90 | fn make_raw_string_target() { |
91 | check_assist_target( | 91 | check_assist_target( |
92 | make_raw_string, | 92 | make_raw_string, |
93 | r#" | 93 | r#" |
94 | fn f() { | 94 | fn f() { |
95 | let s = <|>"random string"; | 95 | let s = <|>"random string"; |
96 | } | 96 | } |
97 | "#, | 97 | "#, |
98 | r#""random string""#, | 98 | r#""random string""#, |
99 | ); | 99 | ); |
100 | } | 100 | } |
101 | 101 | ||
102 | #[test] | 102 | #[test] |
103 | fn make_raw_string_works() { | 103 | fn make_raw_string_works() { |
104 | check_assist( | 104 | check_assist( |
105 | make_raw_string, | 105 | make_raw_string, |
106 | r#" | 106 | r#" |
107 | fn f() { | 107 | fn f() { |
108 | let s = <|>"random string"; | 108 | let s = <|>"random string"; |
109 | } | 109 | } |
110 | "#, | 110 | "#, |
111 | r#" | 111 | r#" |
112 | fn f() { | 112 | fn f() { |
113 | let s = <|>r"random string"; | 113 | let s = <|>r"random string"; |
114 | } | 114 | } |
115 | "#, | 115 | "#, |
116 | ) | 116 | ) |
117 | } | 117 | } |
118 | 118 | ||
119 | #[test] | 119 | #[test] |
120 | fn make_raw_string_with_escaped_works() { | 120 | fn make_raw_string_with_escaped_works() { |
121 | check_assist( | 121 | check_assist( |
122 | make_raw_string, | 122 | make_raw_string, |
123 | r#" | 123 | r#" |
124 | fn f() { | 124 | fn f() { |
125 | let s = <|>"random\nstring"; | 125 | let s = <|>"random\nstring"; |
126 | } | 126 | } |
127 | "#, | 127 | "#, |
128 | r#" | 128 | r#" |
129 | fn f() { | 129 | fn f() { |
130 | let s = <|>r"random\nstring"; | 130 | let s = <|>r"random\nstring"; |
131 | } | 131 | } |
132 | "#, | 132 | "#, |
133 | ) | 133 | ) |
134 | } | 134 | } |
135 | 135 | ||
136 | #[test] | 136 | #[test] |
137 | fn make_raw_string_not_works() { | 137 | fn make_raw_string_not_works() { |
138 | check_assist_not_applicable( | 138 | check_assist_not_applicable( |
139 | make_raw_string, | 139 | make_raw_string, |
140 | r#" | 140 | r#" |
141 | fn f() { | 141 | fn f() { |
142 | let s = <|>r"random string"; | 142 | let s = <|>r"random string"; |
143 | } | 143 | } |
144 | "#, | 144 | "#, |
145 | ); | 145 | ); |
146 | } | 146 | } |
147 | 147 | ||
148 | #[test] | 148 | #[test] |
149 | fn add_hash_target() { | 149 | fn add_hash_target() { |
150 | check_assist_target( | 150 | check_assist_target( |
151 | add_hash, | 151 | add_hash, |
152 | r#" | 152 | r#" |
153 | fn f() { | 153 | fn f() { |
154 | let s = <|>r"random string"; | 154 | let s = <|>r"random string"; |
155 | } | 155 | } |
156 | "#, | 156 | "#, |
157 | r#"r"random string""#, | 157 | r#"r"random string""#, |
158 | ); | 158 | ); |
159 | } | 159 | } |
160 | 160 | ||
161 | #[test] | 161 | #[test] |
162 | fn add_hash_works() { | 162 | fn add_hash_works() { |
163 | check_assist( | 163 | check_assist( |
164 | add_hash, | 164 | add_hash, |
165 | r#" | 165 | r#" |
166 | fn f() { | 166 | fn f() { |
167 | let s = <|>r"random string"; | 167 | let s = <|>r"random string"; |
168 | } | 168 | } |
169 | "#, | 169 | "#, |
170 | r##" | 170 | r##" |
171 | fn f() { | 171 | fn f() { |
172 | let s = <|>r#"random string"#; | 172 | let s = <|>r#"random string"#; |
173 | } | 173 | } |
174 | "##, | 174 | "##, |
175 | ) | 175 | ) |
176 | } | 176 | } |
177 | 177 | ||
178 | #[test] | 178 | #[test] |
179 | fn add_more_hash_works() { | 179 | fn add_more_hash_works() { |
180 | check_assist( | 180 | check_assist( |
181 | add_hash, | 181 | add_hash, |
182 | r##" | 182 | r##" |
183 | fn f() { | 183 | fn f() { |
184 | let s = <|>r#"random"string"#; | 184 | let s = <|>r#"random"string"#; |
185 | } | 185 | } |
186 | "##, | 186 | "##, |
187 | r###" | 187 | r###" |
188 | fn f() { | 188 | fn f() { |
189 | let s = <|>r##"random"string"##; | 189 | let s = <|>r##"random"string"##; |
190 | } | 190 | } |
191 | "###, | 191 | "###, |
192 | ) | 192 | ) |
193 | } | 193 | } |
194 | 194 | ||
195 | #[test] | 195 | #[test] |
196 | fn add_hash_not_works() { | 196 | fn add_hash_not_works() { |
197 | check_assist_not_applicable( | 197 | check_assist_not_applicable( |
198 | add_hash, | 198 | add_hash, |
199 | r#" | 199 | r#" |
200 | fn f() { | 200 | fn f() { |
201 | let s = <|>"random string"; | 201 | let s = <|>"random string"; |
202 | } | 202 | } |
203 | "#, | 203 | "#, |
204 | ); | 204 | ); |
205 | } | 205 | } |
206 | 206 | ||
207 | #[test] | 207 | #[test] |
208 | fn remove_hash_target() { | 208 | fn remove_hash_target() { |
209 | check_assist_target( | 209 | check_assist_target( |
210 | remove_hash, | 210 | remove_hash, |
211 | r##" | 211 | r##" |
212 | fn f() { | 212 | fn f() { |
213 | let s = <|>r#"random string"#; | 213 | let s = <|>r#"random string"#; |
214 | } | 214 | } |
215 | "##, | 215 | "##, |
216 | r##"r#"random string"#"##, | 216 | r##"r#"random string"#"##, |
217 | ); | 217 | ); |
218 | } | 218 | } |
219 | 219 | ||
220 | #[test] | 220 | #[test] |
221 | fn remove_hash_works() { | 221 | fn remove_hash_works() { |
222 | check_assist( | 222 | check_assist( |
223 | remove_hash, | 223 | remove_hash, |
224 | r##" | 224 | r##" |
225 | fn f() { | 225 | fn f() { |
226 | let s = <|>r#"random string"#; | 226 | let s = <|>r#"random string"#; |
227 | } | 227 | } |
228 | "##, | 228 | "##, |
229 | r#" | 229 | r#" |
230 | fn f() { | 230 | fn f() { |
231 | let s = <|>r"random string"; | 231 | let s = <|>r"random string"; |
232 | } | 232 | } |
233 | "#, | 233 | "#, |
234 | ) | 234 | ) |
235 | } | 235 | } |
236 | 236 | ||
237 | #[test] | 237 | #[test] |
238 | fn remove_hash_with_quote_works() { | 238 | fn remove_hash_with_quote_works() { |
239 | check_assist( | 239 | check_assist( |
240 | remove_hash, | 240 | remove_hash, |
241 | r##" | 241 | r##" |
242 | fn f() { | 242 | fn f() { |
243 | let s = <|>r#"random"str"ing"#; | 243 | let s = <|>r#"random"str"ing"#; |
244 | } | 244 | } |
245 | "##, | 245 | "##, |
246 | r#" | 246 | r#" |
247 | fn f() { | 247 | fn f() { |
248 | let s = <|>r"random\"str\"ing"; | 248 | let s = <|>r"random\"str\"ing"; |
249 | } | 249 | } |
250 | "#, | 250 | "#, |
251 | ) | 251 | ) |
252 | } | 252 | } |
253 | 253 | ||
254 | #[test] | 254 | #[test] |
255 | fn remove_more_hash_works() { | 255 | fn remove_more_hash_works() { |
256 | check_assist( | 256 | check_assist( |
257 | remove_hash, | 257 | remove_hash, |
258 | r###" | 258 | r###" |
259 | fn f() { | 259 | fn f() { |
260 | let s = <|>r##"random string"##; | 260 | let s = <|>r##"random string"##; |
261 | } | 261 | } |
262 | "###, | 262 | "###, |
263 | r##" | 263 | r##" |
264 | fn f() { | 264 | fn f() { |
265 | let s = <|>r#"random string"#; | 265 | let s = <|>r#"random string"#; |
266 | } | 266 | } |
267 | "##, | 267 | "##, |
268 | ) | 268 | ) |
269 | } | 269 | } |
270 | 270 | ||
271 | #[test] | 271 | #[test] |
272 | fn remove_hash_not_works() { | 272 | fn remove_hash_not_works() { |
273 | check_assist_not_applicable( | 273 | check_assist_not_applicable( |
274 | remove_hash, | 274 | remove_hash, |
275 | r#" | 275 | r#" |
276 | fn f() { | 276 | fn f() { |
277 | let s = <|>"random string"; | 277 | let s = <|>"random string"; |
278 | } | 278 | } |
279 | "#, | 279 | "#, |
280 | ); | 280 | ); |
281 | } | 281 | } |
282 | 282 | ||
283 | #[test] | 283 | #[test] |
284 | fn remove_hash_no_hash_not_works() { | 284 | fn remove_hash_no_hash_not_works() { |
285 | check_assist_not_applicable( | 285 | check_assist_not_applicable( |
286 | remove_hash, | 286 | remove_hash, |
287 | r#" | 287 | r#" |
288 | fn f() { | 288 | fn f() { |
289 | let s = <|>r"random string"; | 289 | let s = <|>r"random string"; |
290 | } | 290 | } |
291 | "#, | 291 | "#, |
292 | ); | 292 | ); |
293 | } | 293 | } |
294 | 294 | ||
295 | #[test] | 295 | #[test] |
296 | fn make_usual_string_target() { | 296 | fn make_usual_string_target() { |
297 | check_assist_target( | 297 | check_assist_target( |
298 | make_usual_string, | 298 | make_usual_string, |
299 | r##" | 299 | r##" |
300 | fn f() { | 300 | fn f() { |
301 | let s = <|>r#"random string"#; | 301 | let s = <|>r#"random string"#; |
302 | } | 302 | } |
303 | "##, | 303 | "##, |
304 | r##"r#"random string"#"##, | 304 | r##"r#"random string"#"##, |
305 | ); | 305 | ); |
306 | } | 306 | } |
307 | 307 | ||
308 | #[test] | 308 | #[test] |
309 | fn make_usual_string_works() { | 309 | fn make_usual_string_works() { |
310 | check_assist( | 310 | check_assist( |
311 | make_usual_string, | 311 | make_usual_string, |
312 | r##" | 312 | r##" |
313 | fn f() { | 313 | fn f() { |
314 | let s = <|>r#"random string"#; | 314 | let s = <|>r#"random string"#; |
315 | } | 315 | } |
316 | "##, | 316 | "##, |
317 | r#" | 317 | r#" |
318 | fn f() { | 318 | fn f() { |
319 | let s = <|>"random string"; | 319 | let s = <|>"random string"; |
320 | } | 320 | } |
321 | "#, | 321 | "#, |
322 | ) | 322 | ) |
323 | } | 323 | } |
324 | 324 | ||
325 | #[test] | 325 | #[test] |
326 | fn make_usual_string_with_quote_works() { | 326 | fn make_usual_string_with_quote_works() { |
327 | check_assist( | 327 | check_assist( |
328 | make_usual_string, | 328 | make_usual_string, |
329 | r##" | 329 | r##" |
330 | fn f() { | 330 | fn f() { |
331 | let s = <|>r#"random"str"ing"#; | 331 | let s = <|>r#"random"str"ing"#; |
332 | } | 332 | } |
333 | "##, | 333 | "##, |
334 | r#" | 334 | r#" |
335 | fn f() { | 335 | fn f() { |
336 | let s = <|>"random\"str\"ing"; | 336 | let s = <|>"random\"str\"ing"; |
337 | } | 337 | } |
338 | "#, | 338 | "#, |
339 | ) | 339 | ) |
340 | } | 340 | } |
341 | 341 | ||
342 | #[test] | 342 | #[test] |
343 | fn make_usual_string_more_hash_works() { | 343 | fn make_usual_string_more_hash_works() { |
344 | check_assist( | 344 | check_assist( |
345 | make_usual_string, | 345 | make_usual_string, |
346 | r###" | 346 | r###" |
347 | fn f() { | 347 | fn f() { |
348 | let s = <|>r##"random string"##; | 348 | let s = <|>r##"random string"##; |
349 | } | 349 | } |
350 | "###, | 350 | "###, |
351 | r##" | 351 | r##" |
352 | fn f() { | 352 | fn f() { |
353 | let s = <|>"random string"; | 353 | let s = <|>"random string"; |
354 | } | 354 | } |
355 | "##, | 355 | "##, |
356 | ) | 356 | ) |
357 | } | 357 | } |
358 | 358 | ||
359 | #[test] | 359 | #[test] |
360 | fn make_usual_string_not_works() { | 360 | fn make_usual_string_not_works() { |
361 | check_assist_not_applicable( | 361 | check_assist_not_applicable( |
362 | make_usual_string, | 362 | make_usual_string, |
363 | r#" | 363 | r#" |
364 | fn f() { | 364 | fn f() { |
365 | let s = <|>"random string"; | 365 | let s = <|>"random string"; |
366 | } | 366 | } |
367 | "#, | 367 | "#, |
368 | ); | 368 | ); |
369 | } | 369 | } |
370 | } | 370 | } |