aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/find_path.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src/find_path.rs')
-rw-r--r--crates/hir_def/src/find_path.rs249
1 files changed, 140 insertions, 109 deletions
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs
index baf374144..02613c4c4 100644
--- a/crates/hir_def/src/find_path.rs
+++ b/crates/hir_def/src/find_path.rs
@@ -19,12 +19,17 @@ use crate::{
19/// *from where* you're referring to the item, hence the `from` parameter. 19/// *from where* you're referring to the item, hence the `from` parameter.
20pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { 20pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
21 let _p = profile::span("find_path"); 21 let _p = profile::span("find_path");
22 find_path_inner(db, item, from, MAX_PATH_LEN, Prefixed::Not) 22 find_path_inner(db, item, from, MAX_PATH_LEN, None)
23} 23}
24 24
25pub fn find_path_prefixed(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { 25pub fn find_path_prefixed(
26 let _p = profile::span("find_path_absolute"); 26 db: &dyn DefDatabase,
27 find_path_inner(db, item, from, MAX_PATH_LEN, Prefixed::Plain) 27 item: ItemInNs,
28 from: ModuleId,
29 prefix_kind: PrefixKind,
30) -> Option<ModPath> {
31 let _p = profile::span("find_path_prefixed");
32 find_path_inner(db, item, from, MAX_PATH_LEN, Some(prefix_kind))
28} 33}
29 34
30const MAX_PATH_LEN: usize = 15; 35const MAX_PATH_LEN: usize = 15;
@@ -42,58 +47,52 @@ impl ModPath {
42 } 47 }
43} 48}
44 49
45fn check_crate_self_super( 50fn check_self_super(def_map: &CrateDefMap, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
46 def_map: &CrateDefMap, 51 if item == ItemInNs::Types(from.into()) {
47 item: ItemInNs,
48 from: ModuleId,
49) -> Option<ModPath> {
50 // - if the item is the crate root, return `crate`
51 if item
52 == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId {
53 krate: from.krate,
54 local_id: def_map.root,
55 }))
56 {
57 Some(ModPath::from_segments(PathKind::Crate, Vec::new()))
58 } else if item == ItemInNs::Types(from.into()) {
59 // - if the item is the module we're in, use `self` 52 // - if the item is the module we're in, use `self`
60 Some(ModPath::from_segments(PathKind::Super(0), Vec::new())) 53 Some(ModPath::from_segments(PathKind::Super(0), Vec::new()))
61 } else { 54 } else if let Some(parent_id) = def_map.modules[from.local_id].parent {
62 if let Some(parent_id) = def_map.modules[from.local_id].parent { 55 // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
63 // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly) 56 if item
64 if item 57 == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId {
65 == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId { 58 krate: from.krate,
66 krate: from.krate, 59 local_id: parent_id,
67 local_id: parent_id, 60 }))
68 })) 61 {
69 { 62 Some(ModPath::from_segments(PathKind::Super(1), Vec::new()))
70 return Some(ModPath::from_segments(PathKind::Super(1), Vec::new())); 63 } else {
71 } 64 None
72 } 65 }
66 } else {
73 None 67 None
74 } 68 }
75} 69}
76 70
77#[derive(Copy, Clone, PartialEq, Eq)] 71#[derive(Copy, Clone, Debug, PartialEq, Eq)]
78pub enum Prefixed { 72pub enum PrefixKind {
79 Not, 73 /// Causes paths to always start with either `self`, `super`, `crate` or a crate-name.
74 /// This is the same as plain, just that paths will start with `self` iprepended f the path
75 /// starts with an identifier that is not a crate.
80 BySelf, 76 BySelf,
77 /// Causes paths to ignore imports in the local module.
81 Plain, 78 Plain,
79 /// Causes paths to start with `crate` where applicable, effectively forcing paths to be absolute.
80 ByCrate,
82} 81}
83 82
84impl Prefixed { 83impl PrefixKind {
85 #[inline] 84 #[inline]
86 fn prefix(self) -> Option<PathKind> { 85 fn prefix(self) -> PathKind {
87 match self { 86 match self {
88 Prefixed::Not => None, 87 PrefixKind::BySelf => PathKind::Super(0),
89 Prefixed::BySelf => Some(PathKind::Super(0)), 88 PrefixKind::Plain => PathKind::Plain,
90 Prefixed::Plain => Some(PathKind::Plain), 89 PrefixKind::ByCrate => PathKind::Crate,
91 } 90 }
92 } 91 }
93 92
94 #[inline] 93 #[inline]
95 fn prefixed(self) -> bool { 94 fn is_absolute(&self) -> bool {
96 self != Prefixed::Not 95 self == &PrefixKind::ByCrate
97 } 96 }
98} 97}
99 98
@@ -102,7 +101,7 @@ fn find_path_inner(
102 item: ItemInNs, 101 item: ItemInNs,
103 from: ModuleId, 102 from: ModuleId,
104 max_len: usize, 103 max_len: usize,
105 prefixed: Prefixed, 104 prefixed: Option<PrefixKind>,
106) -> Option<ModPath> { 105) -> Option<ModPath> {
107 if max_len == 0 { 106 if max_len == 0 {
108 return None; 107 return None;
@@ -115,13 +114,25 @@ fn find_path_inner(
115 let from_scope: &crate::item_scope::ItemScope = &def_map.modules[from.local_id].scope; 114 let from_scope: &crate::item_scope::ItemScope = &def_map.modules[from.local_id].scope;
116 let scope_name = 115 let scope_name =
117 if let Some((name, _)) = from_scope.name_of(item) { Some(name.clone()) } else { None }; 116 if let Some((name, _)) = from_scope.name_of(item) { Some(name.clone()) } else { None };
118 if !prefixed.prefixed() && scope_name.is_some() { 117 if prefixed.is_none() && scope_name.is_some() {
119 return scope_name 118 return scope_name
120 .map(|scope_name| ModPath::from_segments(PathKind::Plain, vec![scope_name])); 119 .map(|scope_name| ModPath::from_segments(PathKind::Plain, vec![scope_name]));
121 } 120 }
122 121
123 if let modpath @ Some(_) = check_crate_self_super(&def_map, item, from) { 122 // - if the item is the crate root, return `crate`
124 return modpath; 123 if item
124 == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId {
125 krate: from.krate,
126 local_id: def_map.root,
127 }))
128 {
129 return Some(ModPath::from_segments(PathKind::Crate, Vec::new()));
130 }
131
132 if prefixed.filter(PrefixKind::is_absolute).is_none() {
133 if let modpath @ Some(_) = check_self_super(&def_map, item, from) {
134 return modpath;
135 }
125 } 136 }
126 137
127 // - if the item is the crate root of a dependency crate, return the name from the extern prelude 138 // - if the item is the crate root of a dependency crate, return the name from the extern prelude
@@ -211,6 +222,7 @@ fn find_path_inner(
211 best_path_len - 1, 222 best_path_len - 1,
212 prefixed, 223 prefixed,
213 )?; 224 )?;
225 mark::hit!(partially_imported);
214 path.segments.push(info.path.segments.last().unwrap().clone()); 226 path.segments.push(info.path.segments.last().unwrap().clone());
215 Some(path) 227 Some(path)
216 }) 228 })
@@ -226,7 +238,7 @@ fn find_path_inner(
226 } 238 }
227 } 239 }
228 240
229 if let Some(prefix) = prefixed.prefix() { 241 if let Some(prefix) = prefixed.map(PrefixKind::prefix) {
230 best_path.or_else(|| { 242 best_path.or_else(|| {
231 scope_name.map(|scope_name| ModPath::from_segments(prefix, vec![scope_name])) 243 scope_name.map(|scope_name| ModPath::from_segments(prefix, vec![scope_name]))
232 }) 244 })
@@ -355,7 +367,7 @@ mod tests {
355 /// `code` needs to contain a cursor marker; checks that `find_path` for the 367 /// `code` needs to contain a cursor marker; checks that `find_path` for the
356 /// item the `path` refers to returns that same path when called from the 368 /// item the `path` refers to returns that same path when called from the
357 /// module the cursor is in. 369 /// module the cursor is in.
358 fn check_found_path_(ra_fixture: &str, path: &str, absolute: bool) { 370 fn check_found_path_(ra_fixture: &str, path: &str, prefix_kind: Option<PrefixKind>) {
359 let (db, pos) = TestDB::with_position(ra_fixture); 371 let (db, pos) = TestDB::with_position(ra_fixture);
360 let module = db.module_for_file(pos.file_id); 372 let module = db.module_for_file(pos.file_id);
361 let parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path)); 373 let parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path));
@@ -375,20 +387,22 @@ mod tests {
375 .take_types() 387 .take_types()
376 .unwrap(); 388 .unwrap();
377 389
378 let found_path = if absolute { find_path_prefixed } else { find_path }( 390 let found_path =
379 &db, 391 find_path_inner(&db, ItemInNs::Types(resolved), module, MAX_PATH_LEN, prefix_kind);
380 ItemInNs::Types(resolved), 392 assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind);
381 module,
382 );
383 assert_eq!(found_path, Some(mod_path), "absolute {}", absolute);
384 } 393 }
385 394
386 fn check_found_path(ra_fixture: &str, path: &str) { 395 fn check_found_path(
387 check_found_path_(ra_fixture, path, false); 396 ra_fixture: &str,
388 } 397 unprefixed: &str,
389 398 prefixed: &str,
390 fn check_found_path_abs(ra_fixture: &str, path: &str) { 399 absolute: &str,
391 check_found_path_(ra_fixture, path, true); 400 self_prefixed: &str,
401 ) {
402 check_found_path_(ra_fixture, unprefixed, None);
403 check_found_path_(ra_fixture, prefixed, Some(PrefixKind::Plain));
404 check_found_path_(ra_fixture, absolute, Some(PrefixKind::ByCrate));
405 check_found_path_(ra_fixture, self_prefixed, Some(PrefixKind::BySelf));
392 } 406 }
393 407
394 #[test] 408 #[test]
@@ -398,8 +412,7 @@ mod tests {
398 struct S; 412 struct S;
399 <|> 413 <|>
400 "#; 414 "#;
401 check_found_path(code, "S"); 415 check_found_path(code, "S", "S", "crate::S", "self::S");
402 check_found_path_abs(code, "S");
403 } 416 }
404 417
405 #[test] 418 #[test]
@@ -409,8 +422,7 @@ mod tests {
409 enum E { A } 422 enum E { A }
410 <|> 423 <|>
411 "#; 424 "#;
412 check_found_path(code, "E::A"); 425 check_found_path(code, "E::A", "E::A", "E::A", "E::A");
413 check_found_path_abs(code, "E::A");
414 } 426 }
415 427
416 #[test] 428 #[test]
@@ -422,8 +434,7 @@ mod tests {
422 } 434 }
423 <|> 435 <|>
424 "#; 436 "#;
425 check_found_path(code, "foo::S"); 437 check_found_path(code, "foo::S", "foo::S", "crate::foo::S", "self::foo::S");
426 check_found_path_abs(code, "foo::S");
427 } 438 }
428 439
429 #[test] 440 #[test]
@@ -437,8 +448,7 @@ mod tests {
437 //- /foo/bar.rs 448 //- /foo/bar.rs
438 <|> 449 <|>
439 "#; 450 "#;
440 check_found_path(code, "super::S"); 451 check_found_path(code, "super::S", "super::S", "crate::foo::S", "super::S");
441 check_found_path_abs(code, "super::S");
442 } 452 }
443 453
444 #[test] 454 #[test]
@@ -449,8 +459,7 @@ mod tests {
449 //- /foo.rs 459 //- /foo.rs
450 <|> 460 <|>
451 "#; 461 "#;
452 check_found_path(code, "self"); 462 check_found_path(code, "self", "self", "crate::foo", "self");
453 check_found_path_abs(code, "self");
454 } 463 }
455 464
456 #[test] 465 #[test]
@@ -461,8 +470,7 @@ mod tests {
461 //- /foo.rs 470 //- /foo.rs
462 <|> 471 <|>
463 "#; 472 "#;
464 check_found_path(code, "crate"); 473 check_found_path(code, "crate", "crate", "crate", "crate");
465 check_found_path_abs(code, "crate");
466 } 474 }
467 475
468 #[test] 476 #[test]
@@ -474,8 +482,7 @@ mod tests {
474 //- /foo.rs 482 //- /foo.rs
475 <|> 483 <|>
476 "#; 484 "#;
477 check_found_path(code, "crate::S"); 485 check_found_path(code, "crate::S", "crate::S", "crate::S", "crate::S");
478 check_found_path_abs(code, "crate::S");
479 } 486 }
480 487
481 #[test] 488 #[test]
@@ -486,8 +493,7 @@ mod tests {
486 //- /std.rs crate:std 493 //- /std.rs crate:std
487 pub struct S; 494 pub struct S;
488 "#; 495 "#;
489 check_found_path(code, "std::S"); 496 check_found_path(code, "std::S", "std::S", "std::S", "std::S");
490 check_found_path_abs(code, "std::S");
491 } 497 }
492 498
493 #[test] 499 #[test]
@@ -499,12 +505,18 @@ mod tests {
499 //- /std.rs crate:std 505 //- /std.rs crate:std
500 pub struct S; 506 pub struct S;
501 "#; 507 "#;
502 check_found_path(code, "std_renamed::S"); 508 check_found_path(
503 check_found_path_abs(code, "std_renamed::S"); 509 code,
510 "std_renamed::S",
511 "std_renamed::S",
512 "std_renamed::S",
513 "std_renamed::S",
514 );
504 } 515 }
505 516
506 #[test] 517 #[test]
507 fn partially_imported() { 518 fn partially_imported() {
519 mark::check!(partially_imported);
508 // Tests that short paths are used even for external items, when parts of the path are 520 // Tests that short paths are used even for external items, when parts of the path are
509 // already in scope. 521 // already in scope.
510 let code = r#" 522 let code = r#"
@@ -520,8 +532,13 @@ mod tests {
520 } 532 }
521 } 533 }
522 "#; 534 "#;
523 check_found_path(code, "ast::ModuleItem"); 535 check_found_path(
524 check_found_path_abs(code, "syntax::ast::ModuleItem"); 536 code,
537 "ast::ModuleItem",
538 "syntax::ast::ModuleItem",
539 "syntax::ast::ModuleItem",
540 "syntax::ast::ModuleItem",
541 );
525 542
526 let code = r#" 543 let code = r#"
527 //- /main.rs crate:main deps:syntax 544 //- /main.rs crate:main deps:syntax
@@ -535,8 +552,13 @@ mod tests {
535 } 552 }
536 } 553 }
537 "#; 554 "#;
538 check_found_path(code, "syntax::ast::ModuleItem"); 555 check_found_path(
539 check_found_path_abs(code, "syntax::ast::ModuleItem"); 556 code,
557 "syntax::ast::ModuleItem",
558 "syntax::ast::ModuleItem",
559 "syntax::ast::ModuleItem",
560 "syntax::ast::ModuleItem",
561 );
540 } 562 }
541 563
542 #[test] 564 #[test]
@@ -549,8 +571,7 @@ mod tests {
549 } 571 }
550 <|> 572 <|>
551 "#; 573 "#;
552 check_found_path(code, "bar::S"); 574 check_found_path(code, "bar::S", "bar::S", "crate::bar::S", "self::bar::S");
553 check_found_path_abs(code, "bar::S");
554 } 575 }
555 576
556 #[test] 577 #[test]
@@ -563,8 +584,7 @@ mod tests {
563 } 584 }
564 <|> 585 <|>
565 "#; 586 "#;
566 check_found_path(code, "bar::U"); 587 check_found_path(code, "bar::U", "bar::U", "crate::bar::U", "self::bar::U");
567 check_found_path_abs(code, "bar::U");
568 } 588 }
569 589
570 #[test] 590 #[test]
@@ -577,8 +597,7 @@ mod tests {
577 //- /core.rs crate:core 597 //- /core.rs crate:core
578 pub struct S; 598 pub struct S;
579 "#; 599 "#;
580 check_found_path(code, "std::S"); 600 check_found_path(code, "std::S", "std::S", "std::S", "std::S");
581 check_found_path_abs(code, "std::S");
582 } 601 }
583 602
584 #[test] 603 #[test]
@@ -591,8 +610,7 @@ mod tests {
591 #[prelude_import] 610 #[prelude_import]
592 pub use prelude::*; 611 pub use prelude::*;
593 "#; 612 "#;
594 check_found_path(code, "S"); 613 check_found_path(code, "S", "S", "S", "S");
595 check_found_path_abs(code, "S");
596 } 614 }
597 615
598 #[test] 616 #[test]
@@ -608,10 +626,8 @@ mod tests {
608 #[prelude_import] 626 #[prelude_import]
609 pub use prelude::*; 627 pub use prelude::*;
610 "#; 628 "#;
611 check_found_path(code, "None"); 629 check_found_path(code, "None", "None", "None", "None");
612 check_found_path(code, "Some"); 630 check_found_path(code, "Some", "Some", "Some", "Some");
613 check_found_path_abs(code, "None");
614 check_found_path_abs(code, "Some");
615 } 631 }
616 632
617 #[test] 633 #[test]
@@ -627,8 +643,7 @@ mod tests {
627 //- /baz.rs 643 //- /baz.rs
628 pub use crate::foo::bar::S; 644 pub use crate::foo::bar::S;
629 "#; 645 "#;
630 check_found_path(code, "baz::S"); 646 check_found_path(code, "baz::S", "baz::S", "crate::baz::S", "self::baz::S");
631 check_found_path_abs(code, "baz::S");
632 } 647 }
633 648
634 #[test] 649 #[test]
@@ -642,8 +657,7 @@ mod tests {
642 <|> 657 <|>
643 "#; 658 "#;
644 // crate::S would be shorter, but using private imports seems wrong 659 // crate::S would be shorter, but using private imports seems wrong
645 check_found_path(code, "crate::bar::S"); 660 check_found_path(code, "crate::bar::S", "crate::bar::S", "crate::bar::S", "crate::bar::S");
646 check_found_path_abs(code, "crate::bar::S");
647 } 661 }
648 662
649 #[test] 663 #[test]
@@ -661,8 +675,7 @@ mod tests {
661 //- /baz.rs 675 //- /baz.rs
662 pub use super::foo; 676 pub use super::foo;
663 "#; 677 "#;
664 check_found_path(code, "crate::foo::S"); 678 check_found_path(code, "crate::foo::S", "crate::foo::S", "crate::foo::S", "crate::foo::S");
665 check_found_path_abs(code, "crate::foo::S");
666 } 679 }
667 680
668 #[test] 681 #[test]
@@ -682,8 +695,13 @@ mod tests {
682 pub struct Arc; 695 pub struct Arc;
683 } 696 }
684 "#; 697 "#;
685 check_found_path(code, "std::sync::Arc"); 698 check_found_path(
686 check_found_path_abs(code, "std::sync::Arc"); 699 code,
700 "std::sync::Arc",
701 "std::sync::Arc",
702 "std::sync::Arc",
703 "std::sync::Arc",
704 );
687 } 705 }
688 706
689 #[test] 707 #[test]
@@ -707,8 +725,13 @@ mod tests {
707 pub struct Error; 725 pub struct Error;
708 } 726 }
709 "#; 727 "#;
710 check_found_path(code, "core::fmt::Error"); 728 check_found_path(
711 check_found_path_abs(code, "core::fmt::Error"); 729 code,
730 "core::fmt::Error",
731 "core::fmt::Error",
732 "core::fmt::Error",
733 "core::fmt::Error",
734 );
712 } 735 }
713 736
714 #[test] 737 #[test]
@@ -731,8 +754,13 @@ mod tests {
731 pub struct Arc; 754 pub struct Arc;
732 } 755 }
733 "#; 756 "#;
734 check_found_path(code, "alloc::sync::Arc"); 757 check_found_path(
735 check_found_path_abs(code, "alloc::sync::Arc"); 758 code,
759 "alloc::sync::Arc",
760 "alloc::sync::Arc",
761 "alloc::sync::Arc",
762 "alloc::sync::Arc",
763 );
736 } 764 }
737 765
738 #[test] 766 #[test]
@@ -749,8 +777,13 @@ mod tests {
749 //- /zzz.rs crate:megaalloc 777 //- /zzz.rs crate:megaalloc
750 pub struct Arc; 778 pub struct Arc;
751 "#; 779 "#;
752 check_found_path(code, "megaalloc::Arc"); 780 check_found_path(
753 check_found_path_abs(code, "megaalloc::Arc"); 781 code,
782 "megaalloc::Arc",
783 "megaalloc::Arc",
784 "megaalloc::Arc",
785 "megaalloc::Arc",
786 );
754 } 787 }
755 788
756 #[test] 789 #[test]
@@ -763,9 +796,7 @@ mod tests {
763 pub use u8; 796 pub use u8;
764 } 797 }
765 "#; 798 "#;
766 check_found_path(code, "u8"); 799 check_found_path(code, "u8", "u8", "u8", "u8");
767 check_found_path(code, "u16"); 800 check_found_path(code, "u16", "u16", "u16", "u16");
768 check_found_path_abs(code, "u8");
769 check_found_path_abs(code, "u16");
770 } 801 }
771} 802}