diff options
Diffstat (limited to 'crates/ra_ide')
-rw-r--r-- | crates/ra_ide/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_ide/src/call_info.rs | 467 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_context.rs | 5 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 35 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_definition.rs | 18 |
5 files changed, 298 insertions, 228 deletions
diff --git a/crates/ra_ide/Cargo.toml b/crates/ra_ide/Cargo.toml index df2fad520..6f8107491 100644 --- a/crates/ra_ide/Cargo.toml +++ b/crates/ra_ide/Cargo.toml | |||
@@ -3,6 +3,7 @@ edition = "2018" | |||
3 | name = "ra_ide" | 3 | name = "ra_ide" |
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | license = "MIT OR Apache-2.0" | ||
6 | 7 | ||
7 | [lib] | 8 | [lib] |
8 | doctest = false | 9 | doctest = false |
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs index a6bdf1c9d..e1d6efb2a 100644 --- a/crates/ra_ide/src/call_info.rs +++ b/crates/ra_ide/src/call_info.rs | |||
@@ -93,7 +93,7 @@ fn call_info_for_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Op | |||
93 | arg_list | 93 | arg_list |
94 | .args() | 94 | .args() |
95 | .take_while(|arg| { | 95 | .take_while(|arg| { |
96 | arg.syntax().text_range().end() < token.text_range().start() | 96 | arg.syntax().text_range().end() <= token.text_range().start() |
97 | }) | 97 | }) |
98 | .count(), | 98 | .count(), |
99 | ); | 99 | ); |
@@ -213,169 +213,187 @@ impl CallInfo { | |||
213 | 213 | ||
214 | #[cfg(test)] | 214 | #[cfg(test)] |
215 | mod tests { | 215 | mod tests { |
216 | use expect::{expect, Expect}; | ||
216 | use test_utils::mark; | 217 | use test_utils::mark; |
217 | 218 | ||
218 | use crate::mock_analysis::analysis_and_position; | 219 | use crate::mock_analysis::analysis_and_position; |
219 | 220 | ||
220 | use super::*; | 221 | fn check(ra_fixture: &str, expect: Expect) { |
221 | 222 | let (analysis, position) = analysis_and_position(ra_fixture); | |
222 | // These are only used when testing | 223 | let call_info = analysis.call_info(position).unwrap(); |
223 | impl CallInfo { | 224 | let actual = match call_info { |
224 | fn doc(&self) -> Option<hir::Documentation> { | 225 | Some(call_info) => { |
225 | self.signature.doc.clone() | 226 | let docs = match &call_info.signature.doc { |
226 | } | 227 | None => "".to_string(), |
227 | 228 | Some(docs) => format!("{}\n------\n", docs.as_str()), | |
228 | fn label(&self) -> String { | 229 | }; |
229 | self.signature.to_string() | 230 | let params = call_info |
230 | } | 231 | .parameters() |
231 | } | 232 | .iter() |
232 | 233 | .enumerate() | |
233 | fn call_info_helper(text: &str) -> Option<CallInfo> { | 234 | .map(|(i, param)| { |
234 | let (analysis, position) = analysis_and_position(text); | 235 | if Some(i) == call_info.active_parameter { |
235 | analysis.call_info(position).unwrap() | 236 | format!("<{}>", param) |
236 | } | 237 | } else { |
237 | 238 | param.clone() | |
238 | fn call_info(text: &str) -> CallInfo { | 239 | } |
239 | let info = call_info_helper(text); | 240 | }) |
240 | assert!(info.is_some()); | 241 | .collect::<Vec<_>>() |
241 | info.unwrap() | 242 | .join(", "); |
242 | } | 243 | format!("{}{}\n({})\n", docs, call_info.signature, params) |
243 | 244 | } | |
244 | fn no_call_info(text: &str) { | 245 | None => String::new(), |
245 | let info = call_info_helper(text); | 246 | }; |
246 | assert!(info.is_none()); | 247 | expect.assert_eq(&actual); |
247 | } | 248 | } |
248 | 249 | ||
249 | #[test] | 250 | #[test] |
250 | fn test_fn_signature_two_args_firstx() { | 251 | fn test_fn_signature_two_args() { |
251 | let info = call_info( | 252 | check( |
252 | r#"fn foo(x: u32, y: u32) -> u32 {x + y} | 253 | r#" |
253 | fn bar() { foo(<|>3, ); }"#, | 254 | fn foo(x: u32, y: u32) -> u32 {x + y} |
255 | fn bar() { foo(<|>3, ); } | ||
256 | "#, | ||
257 | expect![[r#" | ||
258 | fn foo(x: u32, y: u32) -> u32 | ||
259 | (<x: u32>, y: u32) | ||
260 | "#]], | ||
254 | ); | 261 | ); |
255 | 262 | check( | |
256 | assert_eq!(info.parameters(), ["x: u32", "y: u32"]); | 263 | r#" |
257 | assert_eq!(info.active_parameter, Some(0)); | 264 | fn foo(x: u32, y: u32) -> u32 {x + y} |
258 | } | 265 | fn bar() { foo(3<|>, ); } |
259 | 266 | "#, | |
260 | #[test] | 267 | expect![[r#" |
261 | fn test_fn_signature_two_args_second() { | 268 | fn foo(x: u32, y: u32) -> u32 |
262 | let info = call_info( | 269 | (<x: u32>, y: u32) |
263 | r#"fn foo(x: u32, y: u32) -> u32 {x + y} | 270 | "#]], |
264 | fn bar() { foo(3, <|>); }"#, | 271 | ); |
272 | check( | ||
273 | r#" | ||
274 | fn foo(x: u32, y: u32) -> u32 {x + y} | ||
275 | fn bar() { foo(3,<|> ); } | ||
276 | "#, | ||
277 | expect![[r#" | ||
278 | fn foo(x: u32, y: u32) -> u32 | ||
279 | (x: u32, <y: u32>) | ||
280 | "#]], | ||
281 | ); | ||
282 | check( | ||
283 | r#" | ||
284 | fn foo(x: u32, y: u32) -> u32 {x + y} | ||
285 | fn bar() { foo(3, <|>); } | ||
286 | "#, | ||
287 | expect![[r#" | ||
288 | fn foo(x: u32, y: u32) -> u32 | ||
289 | (x: u32, <y: u32>) | ||
290 | "#]], | ||
265 | ); | 291 | ); |
266 | |||
267 | assert_eq!(info.parameters(), ["x: u32", "y: u32"]); | ||
268 | assert_eq!(info.active_parameter, Some(1)); | ||
269 | } | 292 | } |
270 | 293 | ||
271 | #[test] | 294 | #[test] |
272 | fn test_fn_signature_two_args_empty() { | 295 | fn test_fn_signature_two_args_empty() { |
273 | let info = call_info( | 296 | check( |
274 | r#"fn foo(x: u32, y: u32) -> u32 {x + y} | 297 | r#" |
275 | fn bar() { foo(<|>); }"#, | 298 | fn foo(x: u32, y: u32) -> u32 {x + y} |
299 | fn bar() { foo(<|>); } | ||
300 | "#, | ||
301 | expect![[r#" | ||
302 | fn foo(x: u32, y: u32) -> u32 | ||
303 | (<x: u32>, y: u32) | ||
304 | "#]], | ||
276 | ); | 305 | ); |
277 | |||
278 | assert_eq!(info.parameters(), ["x: u32", "y: u32"]); | ||
279 | assert_eq!(info.active_parameter, Some(0)); | ||
280 | } | 306 | } |
281 | 307 | ||
282 | #[test] | 308 | #[test] |
283 | fn test_fn_signature_two_args_first_generics() { | 309 | fn test_fn_signature_two_args_first_generics() { |
284 | let info = call_info( | 310 | check( |
285 | r#"fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 where T: Copy + Display, U: Debug {x + y} | ||
286 | fn bar() { foo(<|>3, ); }"#, | ||
287 | ); | ||
288 | |||
289 | assert_eq!(info.parameters(), ["x: T", "y: U"]); | ||
290 | assert_eq!( | ||
291 | info.label(), | ||
292 | r#" | 311 | r#" |
293 | fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 | 312 | fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 |
294 | where T: Copy + Display, | 313 | where T: Copy + Display, U: Debug |
295 | U: Debug | 314 | { x + y } |
296 | "# | 315 | |
297 | .trim() | 316 | fn bar() { foo(<|>3, ); } |
317 | "#, | ||
318 | expect![[r#" | ||
319 | fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 | ||
320 | where T: Copy + Display, | ||
321 | U: Debug | ||
322 | (<x: T>, y: U) | ||
323 | "#]], | ||
298 | ); | 324 | ); |
299 | assert_eq!(info.active_parameter, Some(0)); | ||
300 | } | 325 | } |
301 | 326 | ||
302 | #[test] | 327 | #[test] |
303 | fn test_fn_signature_no_params() { | 328 | fn test_fn_signature_no_params() { |
304 | let info = call_info( | 329 | check( |
305 | r#"fn foo<T>() -> T where T: Copy + Display {} | ||
306 | fn bar() { foo(<|>); }"#, | ||
307 | ); | ||
308 | |||
309 | assert!(info.parameters().is_empty()); | ||
310 | assert_eq!( | ||
311 | info.label(), | ||
312 | r#" | 330 | r#" |
313 | fn foo<T>() -> T | 331 | fn foo<T>() -> T where T: Copy + Display {} |
314 | where T: Copy + Display | 332 | fn bar() { foo(<|>); } |
315 | "# | 333 | "#, |
316 | .trim() | 334 | expect![[r#" |
335 | fn foo<T>() -> T | ||
336 | where T: Copy + Display | ||
337 | () | ||
338 | "#]], | ||
317 | ); | 339 | ); |
318 | assert!(info.active_parameter.is_none()); | ||
319 | } | 340 | } |
320 | 341 | ||
321 | #[test] | 342 | #[test] |
322 | fn test_fn_signature_for_impl() { | 343 | fn test_fn_signature_for_impl() { |
323 | let info = call_info( | 344 | check( |
324 | r#"struct F; impl F { pub fn new() { F{}} } | 345 | r#" |
325 | fn bar() {let _ : F = F::new(<|>);}"#, | 346 | struct F; impl F { pub fn new() { F{}} } |
347 | fn bar() {let _ : F = F::new(<|>);} | ||
348 | "#, | ||
349 | expect![[r#" | ||
350 | pub fn new() | ||
351 | () | ||
352 | "#]], | ||
326 | ); | 353 | ); |
327 | |||
328 | assert!(info.parameters().is_empty()); | ||
329 | assert_eq!(info.active_parameter, None); | ||
330 | } | 354 | } |
331 | 355 | ||
332 | #[test] | 356 | #[test] |
333 | fn test_fn_signature_for_method_self() { | 357 | fn test_fn_signature_for_method_self() { |
334 | let info = call_info( | 358 | check( |
335 | r#"struct F; | 359 | r#" |
336 | impl F { | 360 | struct S; |
337 | pub fn new() -> F{ | 361 | impl S { pub fn do_it(&self) {} } |
338 | F{} | ||
339 | } | ||
340 | |||
341 | pub fn do_it(&self) {} | ||
342 | } | ||
343 | 362 | ||
344 | fn bar() { | 363 | fn bar() { |
345 | let f : F = F::new(); | 364 | let s: S = S; |
346 | f.do_it(<|>); | 365 | s.do_it(<|>); |
347 | }"#, | 366 | } |
367 | "#, | ||
368 | expect![[r#" | ||
369 | pub fn do_it(&self) | ||
370 | (&self) | ||
371 | "#]], | ||
348 | ); | 372 | ); |
349 | |||
350 | assert_eq!(info.parameters(), ["&self"]); | ||
351 | assert_eq!(info.active_parameter, None); | ||
352 | } | 373 | } |
353 | 374 | ||
354 | #[test] | 375 | #[test] |
355 | fn test_fn_signature_for_method_with_arg() { | 376 | fn test_fn_signature_for_method_with_arg() { |
356 | let info = call_info( | 377 | check( |
357 | r#"struct F; | 378 | r#" |
358 | impl F { | 379 | struct S; |
359 | pub fn new() -> F{ | 380 | impl S { pub fn do_it(&self, x: i32) {} } |
360 | F{} | ||
361 | } | ||
362 | |||
363 | pub fn do_it(&self, x: i32) {} | ||
364 | } | ||
365 | 381 | ||
366 | fn bar() { | 382 | fn bar() { |
367 | let f : F = F::new(); | 383 | let s: S = S; |
368 | f.do_it(<|>); | 384 | s.do_it(<|>); |
369 | }"#, | 385 | } |
386 | "#, | ||
387 | expect![[r#" | ||
388 | pub fn do_it(&self, x: i32) | ||
389 | (&self, <x: i32>) | ||
390 | "#]], | ||
370 | ); | 391 | ); |
371 | |||
372 | assert_eq!(info.parameters(), ["&self", "x: i32"]); | ||
373 | assert_eq!(info.active_parameter, Some(1)); | ||
374 | } | 392 | } |
375 | 393 | ||
376 | #[test] | 394 | #[test] |
377 | fn test_fn_signature_with_docs_simple() { | 395 | fn test_fn_signature_with_docs_simple() { |
378 | let info = call_info( | 396 | check( |
379 | r#" | 397 | r#" |
380 | /// test | 398 | /// test |
381 | // non-doc-comment | 399 | // non-doc-comment |
@@ -387,17 +405,18 @@ fn bar() { | |||
387 | let _ = foo(<|>); | 405 | let _ = foo(<|>); |
388 | } | 406 | } |
389 | "#, | 407 | "#, |
408 | expect![[r#" | ||
409 | test | ||
410 | ------ | ||
411 | fn foo(j: u32) -> u32 | ||
412 | (<j: u32>) | ||
413 | "#]], | ||
390 | ); | 414 | ); |
391 | |||
392 | assert_eq!(info.parameters(), ["j: u32"]); | ||
393 | assert_eq!(info.active_parameter, Some(0)); | ||
394 | assert_eq!(info.label(), "fn foo(j: u32) -> u32"); | ||
395 | assert_eq!(info.doc().map(|it| it.into()), Some("test".to_string())); | ||
396 | } | 415 | } |
397 | 416 | ||
398 | #[test] | 417 | #[test] |
399 | fn test_fn_signature_with_docs() { | 418 | fn test_fn_signature_with_docs() { |
400 | let info = call_info( | 419 | check( |
401 | r#" | 420 | r#" |
402 | /// Adds one to the number given. | 421 | /// Adds one to the number given. |
403 | /// | 422 | /// |
@@ -415,31 +434,26 @@ pub fn add_one(x: i32) -> i32 { | |||
415 | pub fn do() { | 434 | pub fn do() { |
416 | add_one(<|> | 435 | add_one(<|> |
417 | }"#, | 436 | }"#, |
418 | ); | 437 | expect![[r##" |
419 | 438 | Adds one to the number given. | |
420 | assert_eq!(info.parameters(), ["x: i32"]); | ||
421 | assert_eq!(info.active_parameter, Some(0)); | ||
422 | assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32"); | ||
423 | assert_eq!( | ||
424 | info.doc().map(|it| it.into()), | ||
425 | Some( | ||
426 | r#"Adds one to the number given. | ||
427 | 439 | ||
428 | # Examples | 440 | # Examples |
429 | 441 | ||
430 | ``` | 442 | ``` |
431 | let five = 5; | 443 | let five = 5; |
432 | 444 | ||
433 | assert_eq!(6, my_crate::add_one(5)); | 445 | assert_eq!(6, my_crate::add_one(5)); |
434 | ```"# | 446 | ``` |
435 | .to_string() | 447 | ------ |
436 | ) | 448 | pub fn add_one(x: i32) -> i32 |
449 | (<x: i32>) | ||
450 | "##]], | ||
437 | ); | 451 | ); |
438 | } | 452 | } |
439 | 453 | ||
440 | #[test] | 454 | #[test] |
441 | fn test_fn_signature_with_docs_impl() { | 455 | fn test_fn_signature_with_docs_impl() { |
442 | let info = call_info( | 456 | check( |
443 | r#" | 457 | r#" |
444 | struct addr; | 458 | struct addr; |
445 | impl addr { | 459 | impl addr { |
@@ -460,32 +474,28 @@ impl addr { | |||
460 | pub fn do_it() { | 474 | pub fn do_it() { |
461 | addr {}; | 475 | addr {}; |
462 | addr::add_one(<|>); | 476 | addr::add_one(<|>); |
463 | }"#, | 477 | } |
464 | ); | 478 | "#, |
465 | 479 | expect![[r##" | |
466 | assert_eq!(info.parameters(), ["x: i32"]); | 480 | Adds one to the number given. |
467 | assert_eq!(info.active_parameter, Some(0)); | ||
468 | assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32"); | ||
469 | assert_eq!( | ||
470 | info.doc().map(|it| it.into()), | ||
471 | Some( | ||
472 | r#"Adds one to the number given. | ||
473 | 481 | ||
474 | # Examples | 482 | # Examples |
475 | 483 | ||
476 | ``` | 484 | ``` |
477 | let five = 5; | 485 | let five = 5; |
478 | 486 | ||
479 | assert_eq!(6, my_crate::add_one(5)); | 487 | assert_eq!(6, my_crate::add_one(5)); |
480 | ```"# | 488 | ``` |
481 | .to_string() | 489 | ------ |
482 | ) | 490 | pub fn add_one(x: i32) -> i32 |
491 | (<x: i32>) | ||
492 | "##]], | ||
483 | ); | 493 | ); |
484 | } | 494 | } |
485 | 495 | ||
486 | #[test] | 496 | #[test] |
487 | fn test_fn_signature_with_docs_from_actix() { | 497 | fn test_fn_signature_with_docs_from_actix() { |
488 | let info = call_info( | 498 | check( |
489 | r#" | 499 | r#" |
490 | struct WriteHandler<E>; | 500 | struct WriteHandler<E>; |
491 | 501 | ||
@@ -509,101 +519,102 @@ impl<E> WriteHandler<E> { | |||
509 | pub fn foo(mut r: WriteHandler<()>) { | 519 | pub fn foo(mut r: WriteHandler<()>) { |
510 | r.finished(<|>); | 520 | r.finished(<|>); |
511 | } | 521 | } |
512 | |||
513 | "#, | 522 | "#, |
514 | ); | 523 | expect![[r#" |
515 | 524 | Method is called when writer finishes. | |
516 | assert_eq!(info.label(), "fn finished(&mut self, ctx: &mut Self::Context)".to_string()); | 525 | |
517 | assert_eq!(info.parameters(), ["&mut self", "ctx: &mut Self::Context"]); | 526 | By default this method stops actor's `Context`. |
518 | assert_eq!(info.active_parameter, Some(1)); | 527 | ------ |
519 | assert_eq!( | 528 | fn finished(&mut self, ctx: &mut Self::Context) |
520 | info.doc().map(|it| it.into()), | 529 | (&mut self, <ctx: &mut Self::Context>) |
521 | Some( | 530 | "#]], |
522 | r#"Method is called when writer finishes. | ||
523 | |||
524 | By default this method stops actor's `Context`."# | ||
525 | .to_string() | ||
526 | ) | ||
527 | ); | 531 | ); |
528 | } | 532 | } |
529 | 533 | ||
530 | #[test] | 534 | #[test] |
531 | fn call_info_bad_offset() { | 535 | fn call_info_bad_offset() { |
532 | mark::check!(call_info_bad_offset); | 536 | mark::check!(call_info_bad_offset); |
533 | let (analysis, position) = analysis_and_position( | 537 | check( |
534 | r#"fn foo(x: u32, y: u32) -> u32 {x + y} | 538 | r#" |
535 | fn bar() { foo <|> (3, ); }"#, | 539 | fn foo(x: u32, y: u32) -> u32 {x + y} |
540 | fn bar() { foo <|> (3, ); } | ||
541 | "#, | ||
542 | expect![[""]], | ||
536 | ); | 543 | ); |
537 | let call_info = analysis.call_info(position).unwrap(); | ||
538 | assert!(call_info.is_none()); | ||
539 | } | 544 | } |
540 | 545 | ||
541 | #[test] | 546 | #[test] |
542 | fn test_nested_method_in_lamba() { | 547 | fn test_nested_method_in_lambda() { |
543 | let info = call_info( | 548 | check( |
544 | r#"struct Foo; | 549 | r#" |
545 | 550 | struct Foo; | |
546 | impl Foo { | 551 | impl Foo { fn bar(&self, _: u32) { } } |
547 | fn bar(&self, _: u32) { } | ||
548 | } | ||
549 | 552 | ||
550 | fn bar(_: u32) { } | 553 | fn bar(_: u32) { } |
551 | 554 | ||
552 | fn main() { | 555 | fn main() { |
553 | let foo = Foo; | 556 | let foo = Foo; |
554 | std::thread::spawn(move || foo.bar(<|>)); | 557 | std::thread::spawn(move || foo.bar(<|>)); |
555 | }"#, | 558 | } |
559 | "#, | ||
560 | expect![[r#" | ||
561 | fn bar(&self, _: u32) | ||
562 | (&self, <_: u32>) | ||
563 | "#]], | ||
556 | ); | 564 | ); |
557 | |||
558 | assert_eq!(info.parameters(), ["&self", "_: u32"]); | ||
559 | assert_eq!(info.active_parameter, Some(1)); | ||
560 | assert_eq!(info.label(), "fn bar(&self, _: u32)"); | ||
561 | } | 565 | } |
562 | 566 | ||
563 | #[test] | 567 | #[test] |
564 | fn works_for_tuple_structs() { | 568 | fn works_for_tuple_structs() { |
565 | let info = call_info( | 569 | check( |
566 | r#" | 570 | r#" |
567 | /// A cool tuple struct | 571 | /// A cool tuple struct |
568 | struct TS(u32, i32); | 572 | struct TS(u32, i32); |
569 | fn main() { | 573 | fn main() { |
570 | let s = TS(0, <|>); | 574 | let s = TS(0, <|>); |
571 | }"#, | 575 | } |
576 | "#, | ||
577 | expect![[r#" | ||
578 | A cool tuple struct | ||
579 | ------ | ||
580 | struct TS(u32, i32) -> TS | ||
581 | (u32, <i32>) | ||
582 | "#]], | ||
572 | ); | 583 | ); |
573 | |||
574 | assert_eq!(info.label(), "struct TS(u32, i32) -> TS"); | ||
575 | assert_eq!(info.doc().map(|it| it.into()), Some("A cool tuple struct".to_string())); | ||
576 | assert_eq!(info.active_parameter, Some(1)); | ||
577 | } | 584 | } |
578 | 585 | ||
579 | #[test] | 586 | #[test] |
580 | fn generic_struct() { | 587 | fn generic_struct() { |
581 | let info = call_info( | 588 | check( |
582 | r#" | 589 | r#" |
583 | struct TS<T>(T); | 590 | struct TS<T>(T); |
584 | fn main() { | 591 | fn main() { |
585 | let s = TS(<|>); | 592 | let s = TS(<|>); |
586 | }"#, | 593 | } |
594 | "#, | ||
595 | expect![[r#" | ||
596 | struct TS<T>(T) -> TS | ||
597 | (<T>) | ||
598 | "#]], | ||
587 | ); | 599 | ); |
588 | |||
589 | assert_eq!(info.label(), "struct TS<T>(T) -> TS"); | ||
590 | assert_eq!(info.active_parameter, Some(0)); | ||
591 | } | 600 | } |
592 | 601 | ||
593 | #[test] | 602 | #[test] |
594 | fn cant_call_named_structs() { | 603 | fn cant_call_named_structs() { |
595 | no_call_info( | 604 | check( |
596 | r#" | 605 | r#" |
597 | struct TS { x: u32, y: i32 } | 606 | struct TS { x: u32, y: i32 } |
598 | fn main() { | 607 | fn main() { |
599 | let s = TS(<|>); | 608 | let s = TS(<|>); |
600 | }"#, | 609 | } |
610 | "#, | ||
611 | expect![[""]], | ||
601 | ); | 612 | ); |
602 | } | 613 | } |
603 | 614 | ||
604 | #[test] | 615 | #[test] |
605 | fn works_for_enum_variants() { | 616 | fn works_for_enum_variants() { |
606 | let info = call_info( | 617 | check( |
607 | r#" | 618 | r#" |
608 | enum E { | 619 | enum E { |
609 | /// A Variant | 620 | /// A Variant |
@@ -617,17 +628,19 @@ enum E { | |||
617 | fn main() { | 628 | fn main() { |
618 | let a = E::A(<|>); | 629 | let a = E::A(<|>); |
619 | } | 630 | } |
620 | "#, | 631 | "#, |
632 | expect![[r#" | ||
633 | A Variant | ||
634 | ------ | ||
635 | E::A(0: i32) | ||
636 | (<0: i32>) | ||
637 | "#]], | ||
621 | ); | 638 | ); |
622 | |||
623 | assert_eq!(info.label(), "E::A(0: i32)"); | ||
624 | assert_eq!(info.doc().map(|it| it.into()), Some("A Variant".to_string())); | ||
625 | assert_eq!(info.active_parameter, Some(0)); | ||
626 | } | 639 | } |
627 | 640 | ||
628 | #[test] | 641 | #[test] |
629 | fn cant_call_enum_records() { | 642 | fn cant_call_enum_records() { |
630 | no_call_info( | 643 | check( |
631 | r#" | 644 | r#" |
632 | enum E { | 645 | enum E { |
633 | /// A Variant | 646 | /// A Variant |
@@ -641,13 +654,14 @@ enum E { | |||
641 | fn main() { | 654 | fn main() { |
642 | let a = E::C(<|>); | 655 | let a = E::C(<|>); |
643 | } | 656 | } |
644 | "#, | 657 | "#, |
658 | expect![[""]], | ||
645 | ); | 659 | ); |
646 | } | 660 | } |
647 | 661 | ||
648 | #[test] | 662 | #[test] |
649 | fn fn_signature_for_macro() { | 663 | fn fn_signature_for_macro() { |
650 | let info = call_info( | 664 | check( |
651 | r#" | 665 | r#" |
652 | /// empty macro | 666 | /// empty macro |
653 | macro_rules! foo { | 667 | macro_rules! foo { |
@@ -657,31 +671,30 @@ macro_rules! foo { | |||
657 | fn f() { | 671 | fn f() { |
658 | foo!(<|>); | 672 | foo!(<|>); |
659 | } | 673 | } |
660 | "#, | 674 | "#, |
675 | expect![[r#" | ||
676 | empty macro | ||
677 | ------ | ||
678 | foo!() | ||
679 | () | ||
680 | "#]], | ||
661 | ); | 681 | ); |
662 | |||
663 | assert_eq!(info.label(), "foo!()"); | ||
664 | assert_eq!(info.doc().map(|it| it.into()), Some("empty macro".to_string())); | ||
665 | } | 682 | } |
666 | 683 | ||
667 | #[test] | 684 | #[test] |
668 | fn fn_signature_for_call_in_macro() { | 685 | fn fn_signature_for_call_in_macro() { |
669 | let info = call_info( | 686 | check( |
670 | r#" | 687 | r#" |
671 | macro_rules! id { | 688 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } |
672 | ($($tt:tt)*) => { $($tt)* } | 689 | fn foo() { } |
673 | } | 690 | id! { |
674 | fn foo() { | 691 | fn bar() { foo(<|>); } |
675 | 692 | } | |
676 | } | 693 | "#, |
677 | id! { | 694 | expect![[r#" |
678 | fn bar() { | 695 | fn foo() |
679 | foo(<|>); | 696 | () |
680 | } | 697 | "#]], |
681 | } | ||
682 | "#, | ||
683 | ); | 698 | ); |
684 | |||
685 | assert_eq!(info.label(), "fn foo()"); | ||
686 | } | 699 | } |
687 | } | 700 | } |
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index 3d93f7067..9e82d6854 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs | |||
@@ -63,6 +63,8 @@ pub(crate) struct CompletionContext<'a> { | |||
63 | pub(super) dot_receiver_is_ambiguous_float_literal: bool, | 63 | pub(super) dot_receiver_is_ambiguous_float_literal: bool, |
64 | /// If this is a call (method or function) in particular, i.e. the () are already there. | 64 | /// If this is a call (method or function) in particular, i.e. the () are already there. |
65 | pub(super) is_call: bool, | 65 | pub(super) is_call: bool, |
66 | /// Like `is_call`, but for tuple patterns. | ||
67 | pub(super) is_pattern_call: bool, | ||
66 | /// If this is a macro call, i.e. the () are already there. | 68 | /// If this is a macro call, i.e. the () are already there. |
67 | pub(super) is_macro_call: bool, | 69 | pub(super) is_macro_call: bool, |
68 | pub(super) is_path_type: bool, | 70 | pub(super) is_path_type: bool, |
@@ -136,6 +138,7 @@ impl<'a> CompletionContext<'a> { | |||
136 | is_new_item: false, | 138 | is_new_item: false, |
137 | dot_receiver: None, | 139 | dot_receiver: None, |
138 | is_call: false, | 140 | is_call: false, |
141 | is_pattern_call: false, | ||
139 | is_macro_call: false, | 142 | is_macro_call: false, |
140 | is_path_type: false, | 143 | is_path_type: false, |
141 | has_type_args: false, | 144 | has_type_args: false, |
@@ -370,6 +373,8 @@ impl<'a> CompletionContext<'a> { | |||
370 | .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast)) | 373 | .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast)) |
371 | .is_some(); | 374 | .is_some(); |
372 | self.is_macro_call = path.syntax().parent().and_then(ast::MacroCall::cast).is_some(); | 375 | self.is_macro_call = path.syntax().parent().and_then(ast::MacroCall::cast).is_some(); |
376 | self.is_pattern_call = | ||
377 | path.syntax().parent().and_then(ast::TupleStructPat::cast).is_some(); | ||
373 | 378 | ||
374 | self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); | 379 | self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); |
375 | self.has_type_args = segment.type_arg_list().is_some(); | 380 | self.has_type_args = segment.type_arg_list().is_some(); |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 48afee5fb..64349dcb8 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -315,6 +315,7 @@ impl Completions { | |||
315 | } | 315 | } |
316 | 316 | ||
317 | if variant_kind == StructKind::Tuple { | 317 | if variant_kind == StructKind::Tuple { |
318 | mark::hit!(inserts_parens_for_tuple_enums); | ||
318 | let params = Params::Anonymous(variant.fields(ctx.db).len()); | 319 | let params = Params::Anonymous(variant.fields(ctx.db).len()); |
319 | res = res.add_call_parens(ctx, qualified_name, params) | 320 | res = res.add_call_parens(ctx, qualified_name, params) |
320 | } | 321 | } |
@@ -383,10 +384,17 @@ impl Builder { | |||
383 | if !ctx.config.add_call_parenthesis { | 384 | if !ctx.config.add_call_parenthesis { |
384 | return self; | 385 | return self; |
385 | } | 386 | } |
386 | if ctx.use_item_syntax.is_some() || ctx.is_call { | 387 | if ctx.use_item_syntax.is_some() { |
387 | mark::hit!(no_parens_in_use_item); | 388 | mark::hit!(no_parens_in_use_item); |
388 | return self; | 389 | return self; |
389 | } | 390 | } |
391 | if ctx.is_pattern_call { | ||
392 | mark::hit!(dont_duplicate_pattern_parens); | ||
393 | return self; | ||
394 | } | ||
395 | if ctx.is_call { | ||
396 | return self; | ||
397 | } | ||
390 | 398 | ||
391 | // Don't add parentheses if the expected type is some function reference. | 399 | // Don't add parentheses if the expected type is some function reference. |
392 | if let Some(ty) = &ctx.expected_type { | 400 | if let Some(ty) = &ctx.expected_type { |
@@ -865,6 +873,7 @@ fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 } | |||
865 | 873 | ||
866 | #[test] | 874 | #[test] |
867 | fn inserts_parens_for_tuple_enums() { | 875 | fn inserts_parens_for_tuple_enums() { |
876 | mark::check!(inserts_parens_for_tuple_enums); | ||
868 | check_edit( | 877 | check_edit( |
869 | "Some", | 878 | "Some", |
870 | r#" | 879 | r#" |
@@ -906,6 +915,30 @@ fn main(value: Option<i32>) { | |||
906 | } | 915 | } |
907 | 916 | ||
908 | #[test] | 917 | #[test] |
918 | fn dont_duplicate_pattern_parens() { | ||
919 | mark::check!(dont_duplicate_pattern_parens); | ||
920 | check_edit( | ||
921 | "Var", | ||
922 | r#" | ||
923 | enum E { Var(i32) } | ||
924 | fn main() { | ||
925 | match E::Var(92) { | ||
926 | E::<|>(92) => (), | ||
927 | } | ||
928 | } | ||
929 | "#, | ||
930 | r#" | ||
931 | enum E { Var(i32) } | ||
932 | fn main() { | ||
933 | match E::Var(92) { | ||
934 | E::Var(92) => (), | ||
935 | } | ||
936 | } | ||
937 | "#, | ||
938 | ); | ||
939 | } | ||
940 | |||
941 | #[test] | ||
909 | fn no_call_parens_if_fn_ptr_needed() { | 942 | fn no_call_parens_if_fn_ptr_needed() { |
910 | mark::check!(no_call_parens_if_fn_ptr_needed); | 943 | mark::check!(no_call_parens_if_fn_ptr_needed); |
911 | check_edit( | 944 | check_edit( |
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index f575d738f..c30b20611 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -866,4 +866,22 @@ type Alias<T> = T<|>; | |||
866 | "#, | 866 | "#, |
867 | ) | 867 | ) |
868 | } | 868 | } |
869 | |||
870 | #[test] | ||
871 | fn goto_def_for_macro_container() { | ||
872 | check( | ||
873 | r#" | ||
874 | //- /lib.rs | ||
875 | foo::module<|>::mac!(); | ||
876 | |||
877 | //- /foo/lib.rs | ||
878 | pub mod module { | ||
879 | //^^^^^^ | ||
880 | #[macro_export] | ||
881 | macro_rules! _mac { () => { () } } | ||
882 | pub use crate::_mac as mac; | ||
883 | } | ||
884 | "#, | ||
885 | ); | ||
886 | } | ||
869 | } | 887 | } |