aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-07-15 09:17:13 +0100
committerGitHub <[email protected]>2020-07-15 09:17:13 +0100
commit77425c21c797bab5ae66c418751d689691229651 (patch)
tree1f6ac29ef9654f781355931556a36aad8674fafa
parentfc2f761d654aa17f4af7d3c40cb9b31ea7d91ad0 (diff)
parentfac1b0def12855fade4b29c180d5233a9b33646a (diff)
Merge #5385
5385: Off by one error when determining the active param r=matklad a=matklad closes #3615 bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r--crates/ra_ide/src/call_info.rs467
1 files changed, 240 insertions, 227 deletions
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)]
215mod tests { 215mod 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#"
253fn bar() { foo(<|>3, ); }"#, 254fn foo(x: u32, y: u32) -> u32 {x + y}
255fn 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)); 264fn foo(x: u32, y: u32) -> u32 {x + y}
258 } 265fn 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 "#]],
264fn bar() { foo(3, <|>); }"#, 271 );
272 check(
273 r#"
274fn foo(x: u32, y: u32) -> u32 {x + y}
275fn 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#"
284fn foo(x: u32, y: u32) -> u32 {x + y}
285fn 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#"
275fn bar() { foo(<|>); }"#, 298fn foo(x: u32, y: u32) -> u32 {x + y}
299fn 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}
286fn bar() { foo(<|>3, ); }"#,
287 );
288
289 assert_eq!(info.parameters(), ["x: T", "y: U"]);
290 assert_eq!(
291 info.label(),
292 r#" 311 r#"
293fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 312fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
294where T: Copy + Display, 313 where T: Copy + Display, U: Debug
295 U: Debug 314{ x + y }
296 "# 315
297 .trim() 316fn 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 {}
306fn bar() { foo(<|>); }"#,
307 );
308
309 assert!(info.parameters().is_empty());
310 assert_eq!(
311 info.label(),
312 r#" 330 r#"
313fn foo<T>() -> T 331fn foo<T>() -> T where T: Copy + Display {}
314where T: Copy + Display 332fn 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#"
325fn bar() {let _ : F = F::new(<|>);}"#, 346struct F; impl F { pub fn new() { F{}} }
347fn 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#"
336impl F { 360struct S;
337 pub fn new() -> F{ 361impl S { pub fn do_it(&self) {} }
338 F{}
339 }
340
341 pub fn do_it(&self) {}
342}
343 362
344fn bar() { 363fn 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#"
358impl F { 379struct S;
359 pub fn new() -> F{ 380impl S { pub fn do_it(&self, x: i32) {} }
360 F{}
361 }
362
363 pub fn do_it(&self, x: i32) {}
364}
365 381
366fn bar() { 382fn 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 {
415pub fn do() { 434pub 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 ```
431let five = 5; 443 let five = 5;
432 444
433assert_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#"
444struct addr; 458struct addr;
445impl addr { 459impl addr {
@@ -460,32 +474,28 @@ impl addr {
460pub fn do_it() { 474pub 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 ```
477let five = 5; 485 let five = 5;
478 486
479assert_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#"
490struct WriteHandler<E>; 500struct WriteHandler<E>;
491 501
@@ -509,101 +519,102 @@ impl<E> WriteHandler<E> {
509pub fn foo(mut r: WriteHandler<()>) { 519pub 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
524By 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, ); }"#, 539fn foo(x: u32, y: u32) -> u32 {x + y}
540fn 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 550struct Foo;
546impl Foo { 551impl Foo { fn bar(&self, _: u32) { } }
547 fn bar(&self, _: u32) { }
548}
549 552
550fn bar(_: u32) { } 553fn bar(_: u32) { }
551 554
552fn main() { 555fn 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
568struct TS(u32, i32); 572struct TS(u32, i32);
569fn main() { 573fn 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#"
583struct TS<T>(T); 590struct TS<T>(T);
584fn main() { 591fn 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#"
597struct TS { x: u32, y: i32 } 606struct TS { x: u32, y: i32 }
598fn main() { 607fn 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#"
608enum E { 619enum E {
609 /// A Variant 620 /// A Variant
@@ -617,17 +628,19 @@ enum E {
617fn main() { 628fn 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#"
632enum E { 645enum E {
633 /// A Variant 646 /// A Variant
@@ -641,13 +654,14 @@ enum E {
641fn main() { 654fn 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
653macro_rules! foo { 667macro_rules! foo {
@@ -657,31 +671,30 @@ macro_rules! foo {
657fn f() { 671fn 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 { 688macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
672 ($($tt:tt)*) => { $($tt)* } 689fn foo() { }
673 } 690id! {
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}