aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-09-22 19:01:12 +0100
committerFlorian Diebold <[email protected]>2019-09-22 19:02:32 +0100
commit18bf278c258f44ed68f67f84993f20f7c27c63d0 (patch)
tree3c07347cee581c61107950b1ed9daed191027f5b /crates/ra_assists/src
parent468e1d14c1a4b3d646207ae919082dc17753cd31 (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.rs740
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 @@
1use hir::db::HirDatabase; 1use hir::db::HirDatabase;
2use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; 2use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit};
3 3
4use crate::{Assist, AssistCtx, AssistId}; 4use crate::{Assist, AssistCtx, AssistId};
5 5
6pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 6pub(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
18fn find_usual_string_range(s: &str) -> Option<TextRange> { 18fn 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
25pub(crate) fn make_usual_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 25pub(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
45pub(crate) fn add_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 45pub(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
58pub(crate) fn remove_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 58pub(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)]
85mod test { 85mod 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}