1use hir::{PathResolution, Semantics};
21use ide_db::{
22 FileId, MiniCore, RootDatabase,
23 defs::{Definition, NameClass, NameRefClass},
24 helpers::pick_best_token,
25 ra_fixture::UpmapFromRaFixture,
26 search::{ReferenceCategory, SearchScope, UsageSearchResult},
27};
28use itertools::Itertools;
29use macros::UpmapFromRaFixture;
30use nohash_hasher::IntMap;
31use syntax::AstToken;
32use syntax::{
33 AstNode,
34 SyntaxKind::*,
35 SyntaxNode, T, TextRange, TextSize,
36 ast::{self, HasName},
37 match_ast,
38};
39
40use crate::{
41 Analysis, FilePosition, HighlightedRange, NavigationTarget, TryToNav,
42 doc_links::token_as_doc_comment, highlight_related,
43};
44
45#[derive(Debug, Clone, UpmapFromRaFixture)]
47pub struct ReferenceSearchResult {
48 pub declaration: Option<Declaration>,
52 pub references: IntMap<FileId, Vec<(TextRange, ReferenceCategory)>>,
59}
60
61#[derive(Debug, Clone, UpmapFromRaFixture)]
63pub struct Declaration {
64 pub nav: NavigationTarget,
66 pub is_mut: bool,
68}
69
70#[derive(Debug)]
91pub struct FindAllRefsConfig<'a> {
92 pub search_scope: Option<SearchScope>,
93 pub minicore: MiniCore<'a>,
94}
95
96pub(crate) fn find_all_refs(
122 sema: &Semantics<'_, RootDatabase>,
123 position: FilePosition,
124 config: &FindAllRefsConfig<'_>,
125) -> Option<Vec<ReferenceSearchResult>> {
126 let _p = tracing::info_span!("find_all_refs").entered();
127 let syntax = sema.parse_guess_edition(position.file_id).syntax().clone();
128 let make_searcher = |literal_search: bool| {
129 move |def: Definition| {
130 let mut usages =
131 def.usages(sema).set_scope(config.search_scope.as_ref()).include_self_refs().all();
132 if literal_search {
133 retain_adt_literal_usages(&mut usages, def, sema);
134 }
135
136 let mut references: IntMap<FileId, Vec<(TextRange, ReferenceCategory)>> = usages
137 .into_iter()
138 .map(|(file_id, refs)| {
139 (
140 file_id.file_id(sema.db),
141 refs.into_iter()
142 .map(|file_ref| (file_ref.range, file_ref.category))
143 .unique()
144 .collect(),
145 )
146 })
147 .collect();
148 let declaration = match def {
149 Definition::Module(module) => {
150 Some(NavigationTarget::from_module_to_decl(sema.db, module))
151 }
152 def => def.try_to_nav(sema),
153 }
154 .map(|nav| {
155 let (nav, extra_ref) = match nav.def_site {
156 Some(call) => (call, Some(nav.call_site)),
157 None => (nav.call_site, None),
158 };
159 if let Some(extra_ref) = extra_ref {
160 references
161 .entry(extra_ref.file_id)
162 .or_default()
163 .push((extra_ref.focus_or_full_range(), ReferenceCategory::empty()));
164 }
165 Declaration {
166 is_mut: matches!(def, Definition::Local(l) if l.is_mut(sema.db)),
167 nav,
168 }
169 });
170 ReferenceSearchResult { declaration, references }
171 }
172 };
173
174 if let Some(res) = handle_control_flow_keywords(sema, position) {
176 return Some(vec![res]);
177 }
178
179 if let Some(token) = syntax.token_at_offset(position.offset).left_biased()
180 && let Some(token) = ast::String::cast(token.clone())
181 && let Some((analysis, fixture_analysis)) =
182 Analysis::from_ra_fixture(sema, token.clone(), &token, config.minicore)
183 && let Some((virtual_file_id, file_offset)) =
184 fixture_analysis.map_offset_down(position.offset)
185 {
186 return analysis
187 .find_all_refs(FilePosition { file_id: virtual_file_id, offset: file_offset }, config)
188 .ok()??
189 .upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, position.file_id)
190 .ok();
191 }
192
193 match name_for_constructor_search(&syntax, position) {
194 Some(name) => {
195 let def = match NameClass::classify(sema, &name)? {
196 NameClass::Definition(it) | NameClass::ConstReference(it) => it,
197 NameClass::PatFieldShorthand { local_def: _, field_ref, adt_subst: _ } => {
198 Definition::Field(field_ref)
199 }
200 };
201 Some(vec![make_searcher(true)(def)])
202 }
203 None => {
204 let search = make_searcher(false);
205 Some(find_defs(sema, &syntax, position.offset)?.into_iter().map(search).collect())
206 }
207 }
208}
209
210pub(crate) fn find_defs(
211 sema: &Semantics<'_, RootDatabase>,
212 syntax: &SyntaxNode,
213 offset: TextSize,
214) -> Option<Vec<Definition>> {
215 if let Some(token) = syntax.token_at_offset(offset).left_biased()
216 && let Some(doc_comment) = token_as_doc_comment(&token)
217 {
218 return doc_comment
219 .get_definition_with_descend_at(sema, offset, |def, _, _| Some(vec![def]));
220 }
221
222 let token = syntax.token_at_offset(offset).find(|t| {
223 matches!(
224 t.kind(),
225 IDENT
226 | INT_NUMBER
227 | LIFETIME_IDENT
228 | STRING
229 | T![self]
230 | T![super]
231 | T![crate]
232 | T![Self]
233 )
234 })?;
235
236 if let Some((.., resolution)) = sema.check_for_format_args_template(token.clone(), offset) {
237 return resolution.map(Definition::from).map(|it| vec![it]);
238 }
239
240 Some(
241 sema.descend_into_macros_exact(token)
242 .into_iter()
243 .filter_map(|it| ast::NameLike::cast(it.parent()?))
244 .filter_map(move |name_like| {
245 let def = match name_like {
246 ast::NameLike::NameRef(name_ref) => {
247 match NameRefClass::classify(sema, &name_ref)? {
248 NameRefClass::Definition(def, _) => def,
249 NameRefClass::FieldShorthand {
250 local_ref,
251 field_ref: _,
252 adt_subst: _,
253 } => Definition::Local(local_ref),
254 NameRefClass::ExternCrateShorthand { decl, .. } => {
255 Definition::ExternCrateDecl(decl)
256 }
257 }
258 }
259 ast::NameLike::Name(name) => match NameClass::classify(sema, &name)? {
260 NameClass::Definition(it) | NameClass::ConstReference(it) => it,
261 NameClass::PatFieldShorthand { local_def, field_ref: _, adt_subst: _ } => {
262 Definition::Local(local_def)
263 }
264 },
265 ast::NameLike::Lifetime(lifetime) => {
266 NameRefClass::classify_lifetime(sema, &lifetime)
267 .and_then(|class| match class {
268 NameRefClass::Definition(it, _) => Some(it),
269 _ => None,
270 })
271 .or_else(|| {
272 NameClass::classify_lifetime(sema, &lifetime)
273 .and_then(NameClass::defined)
274 })?
275 }
276 };
277 Some(def)
278 })
279 .collect(),
280 )
281}
282
283fn retain_adt_literal_usages(
285 usages: &mut UsageSearchResult,
286 def: Definition,
287 sema: &Semantics<'_, RootDatabase>,
288) {
289 let refs = usages.references.values_mut();
290 match def {
291 Definition::Adt(hir::Adt::Enum(enum_)) => {
292 refs.for_each(|it| {
293 it.retain(|reference| {
294 reference
295 .name
296 .as_name_ref()
297 .is_some_and(|name_ref| is_enum_lit_name_ref(sema, enum_, name_ref))
298 })
299 });
300 usages.references.retain(|_, it| !it.is_empty());
301 }
302 Definition::Adt(_) | Definition::Variant(_) => {
303 refs.for_each(|it| {
304 it.retain(|reference| reference.name.as_name_ref().is_some_and(is_lit_name_ref))
305 });
306 usages.references.retain(|_, it| !it.is_empty());
307 }
308 _ => {}
309 }
310}
311
312fn name_for_constructor_search(syntax: &SyntaxNode, position: FilePosition) -> Option<ast::Name> {
326 let token = syntax.token_at_offset(position.offset).right_biased()?;
327 let token_parent = token.parent()?;
328 let kind = token.kind();
329 if kind == T![;] {
330 ast::Struct::cast(token_parent)
331 .filter(|struct_| struct_.field_list().is_none())
332 .and_then(|struct_| struct_.name())
333 } else if kind == T!['{'] {
334 match_ast! {
335 match token_parent {
336 ast::RecordFieldList(rfl) => match_ast! {
337 match (rfl.syntax().parent()?) {
338 ast::Variant(it) => it.name(),
339 ast::Struct(it) => it.name(),
340 ast::Union(it) => it.name(),
341 _ => None,
342 }
343 },
344 ast::VariantList(vl) => ast::Enum::cast(vl.syntax().parent()?)?.name(),
345 _ => None,
346 }
347 }
348 } else if kind == T!['('] {
349 let tfl = ast::TupleFieldList::cast(token_parent)?;
350 match_ast! {
351 match (tfl.syntax().parent()?) {
352 ast::Variant(it) => it.name(),
353 ast::Struct(it) => it.name(),
354 _ => None,
355 }
356 }
357 } else {
358 None
359 }
360}
361
362fn is_enum_lit_name_ref(
373 sema: &Semantics<'_, RootDatabase>,
374 enum_: hir::Enum,
375 name_ref: &ast::NameRef,
376) -> bool {
377 let path_is_variant_of_enum = |path: ast::Path| {
378 matches!(
379 sema.resolve_path(&path),
380 Some(PathResolution::Def(hir::ModuleDef::Variant(variant)))
381 if variant.parent_enum(sema.db) == enum_
382 )
383 };
384 name_ref
385 .syntax()
386 .ancestors()
387 .find_map(|ancestor| {
388 match_ast! {
389 match ancestor {
390 ast::PathExpr(path_expr) => path_expr.path().map(path_is_variant_of_enum),
391 ast::RecordExpr(record_expr) => record_expr.path().map(path_is_variant_of_enum),
392 _ => None,
393 }
394 }
395 })
396 .unwrap_or(false)
397}
398
399fn path_ends_with(path: Option<ast::Path>, name_ref: &ast::NameRef) -> bool {
402 path.and_then(|path| path.segment())
403 .and_then(|segment| segment.name_ref())
404 .map_or(false, |segment| segment == *name_ref)
405}
406
407fn is_lit_name_ref(name_ref: &ast::NameRef) -> bool {
413 name_ref.syntax().ancestors().find_map(|ancestor| {
414 match_ast! {
415 match ancestor {
416 ast::PathExpr(path_expr) => Some(path_ends_with(path_expr.path(), name_ref)),
417 ast::RecordExpr(record_expr) => Some(path_ends_with(record_expr.path(), name_ref)),
418 _ => None,
419 }
420 }
421 }).unwrap_or(false)
422}
423
424fn handle_control_flow_keywords(
425 sema: &Semantics<'_, RootDatabase>,
426 FilePosition { file_id, offset }: FilePosition,
427) -> Option<ReferenceSearchResult> {
428 let file = sema.parse_guess_edition(file_id);
429 let edition = sema.attach_first_edition(file_id).edition(sema.db);
430 let token = pick_best_token(file.syntax().token_at_offset(offset), |kind| match kind {
431 _ if kind.is_keyword(edition) => 4,
432 T![=>] => 3,
433 _ => 1,
434 })?;
435
436 let references = match token.kind() {
437 T![fn] | T![return] | T![try] => highlight_related::highlight_exit_points(sema, token),
438 T![async] => highlight_related::highlight_yield_points(sema, token),
439 T![loop] | T![while] | T![break] | T![continue] => {
440 highlight_related::highlight_break_points(sema, token)
441 }
442 T![for] if token.parent().and_then(ast::ForExpr::cast).is_some() => {
443 highlight_related::highlight_break_points(sema, token)
444 }
445 T![if] | T![=>] | T![match] => highlight_related::highlight_branch_exit_points(sema, token),
446 _ => return None,
447 }
448 .into_iter()
449 .map(|(file_id, ranges)| {
450 let ranges = ranges
451 .into_iter()
452 .map(|HighlightedRange { range, category }| (range, category))
453 .collect();
454 (file_id.file_id(sema.db), ranges)
455 })
456 .collect();
457
458 Some(ReferenceSearchResult { declaration: None, references })
459}
460
461#[cfg(test)]
462mod tests {
463 use expect_test::{Expect, expect};
464 use hir::EditionedFileId;
465 use ide_db::{FileId, MiniCore, RootDatabase};
466 use stdx::format_to;
467
468 use crate::{SearchScope, fixture, references::FindAllRefsConfig};
469
470 #[test]
471 fn exclude_tests() {
472 check(
473 r#"
474fn test_func() {}
475
476fn func() {
477 test_func$0();
478}
479
480#[test]
481fn test() {
482 test_func();
483}
484"#,
485 expect![[r#"
486 test_func Function FileId(0) 0..17 3..12
487
488 FileId(0) 35..44
489 FileId(0) 75..84 test
490 "#]],
491 );
492
493 check(
494 r#"
495fn test_func() {}
496
497fn func() {
498 test_func$0();
499}
500
501#[::core::prelude::v1::test]
502fn test() {
503 test_func();
504}
505"#,
506 expect![[r#"
507 test_func Function FileId(0) 0..17 3..12
508
509 FileId(0) 35..44
510 FileId(0) 96..105 test
511 "#]],
512 );
513 }
514
515 #[test]
516 fn exclude_tests_macro_refs() {
517 check(
518 r#"
519macro_rules! my_macro {
520 ($e:expr) => { $e };
521}
522
523fn foo$0() -> i32 { 42 }
524
525fn bar() {
526 foo();
527}
528
529#[test]
530fn t2() {
531 my_macro!(foo());
532}
533"#,
534 expect![[r#"
535 foo Function FileId(0) 52..74 55..58
536
537 FileId(0) 91..94
538 FileId(0) 133..136 test
539 "#]],
540 );
541 }
542 #[test]
543 fn test_struct_literal_after_space() {
544 check(
545 r#"
546struct Foo $0{
547 a: i32,
548}
549impl Foo {
550 fn f() -> i32 { 42 }
551}
552fn main() {
553 let f: Foo;
554 f = Foo {a: Foo::f()};
555}
556"#,
557 expect![[r#"
558 Foo Struct FileId(0) 0..26 7..10
559
560 FileId(0) 101..104
561 "#]],
562 );
563 }
564
565 #[test]
566 fn test_struct_literal_before_space() {
567 check(
568 r#"
569struct Foo$0 {}
570 fn main() {
571 let f: Foo;
572 f = Foo {};
573}
574"#,
575 expect![[r#"
576 Foo Struct FileId(0) 0..13 7..10
577
578 FileId(0) 41..44
579 FileId(0) 54..57
580 "#]],
581 );
582 }
583
584 #[test]
585 fn test_struct_literal_with_generic_type() {
586 check(
587 r#"
588struct Foo<T> $0{}
589 fn main() {
590 let f: Foo::<i32>;
591 f = Foo {};
592}
593"#,
594 expect![[r#"
595 Foo Struct FileId(0) 0..16 7..10
596
597 FileId(0) 64..67
598 "#]],
599 );
600 }
601
602 #[test]
603 fn test_struct_literal_for_tuple() {
604 check(
605 r#"
606struct Foo$0(i32);
607
608fn main() {
609 let f: Foo;
610 f = Foo(1);
611}
612"#,
613 expect![[r#"
614 Foo Struct FileId(0) 0..16 7..10
615
616 FileId(0) 54..57
617 "#]],
618 );
619 }
620
621 #[test]
622 fn test_struct_literal_for_union() {
623 check(
624 r#"
625union Foo $0{
626 x: u32
627}
628
629fn main() {
630 let f: Foo;
631 f = Foo { x: 1 };
632}
633"#,
634 expect![[r#"
635 Foo Union FileId(0) 0..24 6..9
636
637 FileId(0) 62..65
638 "#]],
639 );
640 }
641
642 #[test]
643 fn test_enum_after_space() {
644 check(
645 r#"
646enum Foo $0{
647 A,
648 B(),
649 C{},
650}
651fn main() {
652 let f: Foo;
653 f = Foo::A;
654 f = Foo::B();
655 f = Foo::C{};
656}
657"#,
658 expect![[r#"
659 Foo Enum FileId(0) 0..37 5..8
660
661 FileId(0) 74..77
662 FileId(0) 90..93
663 FileId(0) 108..111
664 "#]],
665 );
666 }
667
668 #[test]
669 fn test_variant_record_after_space() {
670 check(
671 r#"
672enum Foo {
673 A $0{ n: i32 },
674 B,
675}
676fn main() {
677 let f: Foo;
678 f = Foo::B;
679 f = Foo::A { n: 92 };
680}
681"#,
682 expect![[r#"
683 A Variant FileId(0) 15..27 15..16
684
685 FileId(0) 95..96
686 "#]],
687 );
688 }
689
690 #[test]
691 fn test_variant_tuple_before_paren() {
692 check(
693 r#"
694enum Foo {
695 A$0(i32),
696 B,
697}
698fn main() {
699 let f: Foo;
700 f = Foo::B;
701 f = Foo::A(92);
702}
703"#,
704 expect![[r#"
705 A Variant FileId(0) 15..21 15..16
706
707 FileId(0) 89..90
708 "#]],
709 );
710 }
711
712 #[test]
713 fn test_enum_before_space() {
714 check(
715 r#"
716enum Foo$0 {
717 A,
718 B,
719}
720fn main() {
721 let f: Foo;
722 f = Foo::A;
723}
724"#,
725 expect![[r#"
726 Foo Enum FileId(0) 0..26 5..8
727
728 FileId(0) 50..53
729 FileId(0) 63..66
730 "#]],
731 );
732 }
733
734 #[test]
735 fn test_enum_with_generic_type() {
736 check(
737 r#"
738enum Foo<T> $0{
739 A(T),
740 B,
741}
742fn main() {
743 let f: Foo<i8>;
744 f = Foo::A(1);
745}
746"#,
747 expect![[r#"
748 Foo Enum FileId(0) 0..32 5..8
749
750 FileId(0) 73..76
751 "#]],
752 );
753 }
754
755 #[test]
756 fn test_enum_for_tuple() {
757 check(
758 r#"
759enum Foo$0{
760 A(i8),
761 B(i8),
762}
763fn main() {
764 let f: Foo;
765 f = Foo::A(1);
766}
767"#,
768 expect![[r#"
769 Foo Enum FileId(0) 0..33 5..8
770
771 FileId(0) 70..73
772 "#]],
773 );
774 }
775
776 #[test]
777 fn test_find_all_refs_for_local() {
778 check(
779 r#"
780fn main() {
781 let mut i = 1;
782 let j = 1;
783 i = i$0 + j;
784
785 {
786 i = 0;
787 }
788
789 i = 5;
790}"#,
791 expect![[r#"
792 i Local FileId(0) 20..25 24..25 write
793
794 FileId(0) 50..51 write
795 FileId(0) 54..55 read
796 FileId(0) 76..77 write
797 FileId(0) 94..95 write
798 "#]],
799 );
800 }
801
802 #[test]
803 fn test_find_all_refs_in_comments() {
804 check(
805 r#"
806struct Foo;
807
808/// $0[`Foo`] is just above
809struct Bar;
810"#,
811 expect![[r#"
812 Foo Struct FileId(0) 0..11 7..10
813
814 (no references)
815 "#]],
816 );
817 }
818
819 #[test]
820 fn search_filters_by_range() {
821 check(
822 r#"
823fn foo() {
824 let spam$0 = 92;
825 spam + spam
826}
827fn bar() {
828 let spam = 92;
829 spam + spam
830}
831"#,
832 expect![[r#"
833 spam Local FileId(0) 19..23 19..23
834
835 FileId(0) 34..38 read
836 FileId(0) 41..45 read
837 "#]],
838 );
839 }
840
841 #[test]
842 fn test_find_all_refs_for_param_inside() {
843 check(
844 r#"
845fn foo(i : u32) -> u32 { i$0 }
846"#,
847 expect![[r#"
848 i ValueParam FileId(0) 7..8 7..8
849
850 FileId(0) 25..26 read
851 "#]],
852 );
853 }
854
855 #[test]
856 fn test_find_all_refs_for_fn_param() {
857 check(
858 r#"
859fn foo(i$0 : u32) -> u32 { i }
860"#,
861 expect![[r#"
862 i ValueParam FileId(0) 7..8 7..8
863
864 FileId(0) 25..26 read
865 "#]],
866 );
867 }
868
869 #[test]
870 fn test_find_all_refs_field_name() {
871 check(
872 r#"
873//- /lib.rs
874struct Foo {
875 pub spam$0: u32,
876}
877
878fn main(s: Foo) {
879 let f = s.spam;
880}
881"#,
882 expect![[r#"
883 spam Field FileId(0) 17..30 21..25
884
885 FileId(0) 67..71 read
886 "#]],
887 );
888 }
889
890 #[test]
891 fn test_find_all_refs_impl_item_name() {
892 check(
893 r#"
894struct Foo;
895impl Foo {
896 fn f$0(&self) { }
897}
898"#,
899 expect![[r#"
900 f Function FileId(0) 27..43 30..31
901
902 (no references)
903 "#]],
904 );
905 }
906
907 #[test]
908 fn test_find_all_refs_enum_var_name() {
909 check(
910 r#"
911enum Foo {
912 A,
913 B$0,
914 C,
915}
916"#,
917 expect![[r#"
918 B Variant FileId(0) 22..23 22..23
919
920 (no references)
921 "#]],
922 );
923 }
924
925 #[test]
926 fn test_find_all_refs_enum_var_field() {
927 check(
928 r#"
929enum Foo {
930 A,
931 B { field$0: u8 },
932 C,
933}
934"#,
935 expect![[r#"
936 field Field FileId(0) 26..35 26..31
937
938 (no references)
939 "#]],
940 );
941 }
942
943 #[test]
944 fn test_self() {
945 check(
946 r#"
947struct S$0<T> {
948 t: PhantomData<T>,
949}
950
951impl<T> S<T> {
952 fn new() -> Self {
953 Self {
954 t: Default::default(),
955 }
956 }
957}
958"#,
959 expect![[r#"
960 S Struct FileId(0) 0..38 7..8
961
962 FileId(0) 48..49
963 FileId(0) 71..75
964 FileId(0) 86..90
965 "#]],
966 )
967 }
968
969 #[test]
970 fn test_self_inside_not_adt_impl() {
971 check(
972 r#"
973pub trait TestTrait {
974 type Assoc;
975 fn stuff() -> Self;
976}
977impl TestTrait for () {
978 type Assoc$0 = u8;
979 fn stuff() -> Self {
980 let me: Self = ();
981 me
982 }
983}
984"#,
985 expect![[r#"
986 Assoc TypeAlias FileId(0) 92..108 97..102
987
988 FileId(0) 31..36
989 "#]],
990 )
991 }
992
993 #[test]
994 fn test_find_all_refs_two_modules() {
995 check(
996 r#"
997//- /lib.rs
998pub mod foo;
999pub mod bar;
1000
1001fn f() {
1002 let i = foo::Foo { n: 5 };
1003}
1004
1005//- /foo.rs
1006use crate::bar;
1007
1008pub struct Foo {
1009 pub n: u32,
1010}
1011
1012fn f() {
1013 let i = bar::Bar { n: 5 };
1014}
1015
1016//- /bar.rs
1017use crate::foo;
1018
1019pub struct Bar {
1020 pub n: u32,
1021}
1022
1023fn f() {
1024 let i = foo::Foo$0 { n: 5 };
1025}
1026"#,
1027 expect![[r#"
1028 Foo Struct FileId(1) 17..51 28..31 foo
1029
1030 FileId(0) 53..56
1031 FileId(2) 79..82
1032 "#]],
1033 );
1034 }
1035
1036 #[test]
1037 fn test_find_all_refs_decl_module() {
1038 check(
1039 r#"
1040//- /lib.rs
1041mod foo$0;
1042
1043use foo::Foo;
1044
1045fn f() {
1046 let i = Foo { n: 5 };
1047}
1048
1049//- /foo.rs
1050pub struct Foo {
1051 pub n: u32,
1052}
1053"#,
1054 expect![[r#"
1055 foo Module FileId(0) 0..8 4..7
1056
1057 FileId(0) 14..17 import
1058 "#]],
1059 );
1060 }
1061
1062 #[test]
1063 fn test_find_all_refs_decl_module_on_self() {
1064 check(
1065 r#"
1066//- /lib.rs
1067mod foo;
1068
1069//- /foo.rs
1070use self$0;
1071"#,
1072 expect![[r#"
1073 foo Module FileId(0) 0..8 4..7
1074
1075 FileId(1) 4..8 import
1076 "#]],
1077 );
1078 }
1079
1080 #[test]
1081 fn test_find_all_refs_decl_module_on_self_crate_root() {
1082 check(
1083 r#"
1084//- /lib.rs
1085use self$0;
1086"#,
1087 expect![[r#"
1088 _ CrateRoot FileId(0) 0..10
1089
1090 FileId(0) 4..8 import
1091 "#]],
1092 );
1093 }
1094
1095 #[test]
1096 fn test_find_all_refs_super_mod_vis() {
1097 check(
1098 r#"
1099//- /lib.rs
1100mod foo;
1101
1102//- /foo.rs
1103mod some;
1104use some::Foo;
1105
1106fn f() {
1107 let i = Foo { n: 5 };
1108}
1109
1110//- /foo/some.rs
1111pub(super) struct Foo$0 {
1112 pub n: u32,
1113}
1114"#,
1115 expect![[r#"
1116 Foo Struct FileId(2) 0..41 18..21 some
1117
1118 FileId(1) 20..23 import
1119 FileId(1) 47..50
1120 "#]],
1121 );
1122 }
1123
1124 #[test]
1125 fn test_find_all_refs_with_scope() {
1126 let code = r#"
1127 //- /lib.rs
1128 mod foo;
1129 mod bar;
1130
1131 pub fn quux$0() {}
1132
1133 //- /foo.rs
1134 fn f() { super::quux(); }
1135
1136 //- /bar.rs
1137 fn f() { super::quux(); }
1138 "#;
1139
1140 check_with_scope(
1141 code,
1142 None,
1143 expect![[r#"
1144 quux Function FileId(0) 19..35 26..30
1145
1146 FileId(1) 16..20
1147 FileId(2) 16..20
1148 "#]],
1149 );
1150
1151 check_with_scope(
1152 code,
1153 Some(&mut |db| {
1154 SearchScope::single_file(EditionedFileId::current_edition(db, FileId::from_raw(2)))
1155 }),
1156 expect![[r#"
1157 quux Function FileId(0) 19..35 26..30
1158
1159 FileId(2) 16..20
1160 "#]],
1161 );
1162 }
1163
1164 #[test]
1165 fn test_find_all_refs_macro_def() {
1166 check(
1167 r#"
1168#[macro_export]
1169macro_rules! m1$0 { () => (()) }
1170
1171fn foo() {
1172 m1();
1173 m1();
1174}
1175"#,
1176 expect![[r#"
1177 m1 Macro FileId(0) 0..46 29..31
1178
1179 FileId(0) 63..65
1180 FileId(0) 73..75
1181 "#]],
1182 );
1183 }
1184
1185 #[test]
1186 fn test_basic_highlight_read_write() {
1187 check(
1188 r#"
1189fn foo() {
1190 let mut i$0 = 0;
1191 i = i + 1;
1192}
1193"#,
1194 expect![[r#"
1195 i Local FileId(0) 19..24 23..24 write
1196
1197 FileId(0) 34..35 write
1198 FileId(0) 38..39 read
1199 "#]],
1200 );
1201 }
1202
1203 #[test]
1204 fn test_basic_highlight_field_read_write() {
1205 check(
1206 r#"
1207struct S {
1208 f: u32,
1209}
1210
1211fn foo() {
1212 let mut s = S{f: 0};
1213 s.f$0 = 0;
1214}
1215"#,
1216 expect![[r#"
1217 f Field FileId(0) 15..21 15..16
1218
1219 FileId(0) 55..56 read
1220 FileId(0) 68..69 write
1221 "#]],
1222 );
1223 }
1224
1225 #[test]
1226 fn test_basic_highlight_decl_no_write() {
1227 check(
1228 r#"
1229fn foo() {
1230 let i$0;
1231 i = 1;
1232}
1233"#,
1234 expect![[r#"
1235 i Local FileId(0) 19..20 19..20
1236
1237 FileId(0) 26..27 write
1238 "#]],
1239 );
1240 }
1241
1242 #[test]
1243 fn test_find_struct_function_refs_outside_module() {
1244 check(
1245 r#"
1246mod foo {
1247 pub struct Foo;
1248
1249 impl Foo {
1250 pub fn new$0() -> Foo { Foo }
1251 }
1252}
1253
1254fn main() {
1255 let _f = foo::Foo::new();
1256}
1257"#,
1258 expect![[r#"
1259 new Function FileId(0) 54..81 61..64
1260
1261 FileId(0) 126..129
1262 "#]],
1263 );
1264 }
1265
1266 #[test]
1267 fn test_find_all_refs_nested_module() {
1268 check(
1269 r#"
1270//- /lib.rs
1271mod foo { mod bar; }
1272
1273fn f$0() {}
1274
1275//- /foo/bar.rs
1276use crate::f;
1277
1278fn g() { f(); }
1279"#,
1280 expect![[r#"
1281 f Function FileId(0) 22..31 25..26
1282
1283 FileId(1) 11..12 import
1284 FileId(1) 24..25
1285 "#]],
1286 );
1287 }
1288
1289 #[test]
1290 fn test_find_all_refs_struct_pat() {
1291 check(
1292 r#"
1293struct S {
1294 field$0: u8,
1295}
1296
1297fn f(s: S) {
1298 match s {
1299 S { field } => {}
1300 }
1301}
1302"#,
1303 expect![[r#"
1304 field Field FileId(0) 15..24 15..20
1305
1306 FileId(0) 68..73 read
1307 "#]],
1308 );
1309 }
1310
1311 #[test]
1312 fn test_find_all_refs_enum_var_pat() {
1313 check(
1314 r#"
1315enum En {
1316 Variant {
1317 field$0: u8,
1318 }
1319}
1320
1321fn f(e: En) {
1322 match e {
1323 En::Variant { field } => {}
1324 }
1325}
1326"#,
1327 expect![[r#"
1328 field Field FileId(0) 32..41 32..37
1329
1330 FileId(0) 102..107 read
1331 "#]],
1332 );
1333 }
1334
1335 #[test]
1336 fn test_find_all_refs_enum_var_privacy() {
1337 check(
1338 r#"
1339mod m {
1340 pub enum En {
1341 Variant {
1342 field$0: u8,
1343 }
1344 }
1345}
1346
1347fn f() -> m::En {
1348 m::En::Variant { field: 0 }
1349}
1350"#,
1351 expect![[r#"
1352 field Field FileId(0) 56..65 56..61
1353
1354 FileId(0) 125..130 read
1355 "#]],
1356 );
1357 }
1358
1359 #[test]
1360 fn test_find_self_refs() {
1361 check(
1362 r#"
1363struct Foo { bar: i32 }
1364
1365impl Foo {
1366 fn foo(self) {
1367 let x = self$0.bar;
1368 if true {
1369 let _ = match () {
1370 () => self,
1371 };
1372 }
1373 }
1374}
1375"#,
1376 expect![[r#"
1377 self SelfParam FileId(0) 47..51 47..51
1378
1379 FileId(0) 71..75 read
1380 FileId(0) 152..156 read
1381 "#]],
1382 );
1383 }
1384
1385 #[test]
1386 fn test_find_self_refs_decl() {
1387 check(
1388 r#"
1389struct Foo { bar: i32 }
1390
1391impl Foo {
1392 fn foo(self$0) {
1393 self;
1394 }
1395}
1396"#,
1397 expect![[r#"
1398 self SelfParam FileId(0) 47..51 47..51
1399
1400 FileId(0) 63..67 read
1401 "#]],
1402 );
1403 }
1404
1405 #[test]
1406 fn test_highlight_if_branches() {
1407 check(
1408 r#"
1409fn main() {
1410 let x = if$0 true {
1411 1
1412 } else if false {
1413 2
1414 } else {
1415 3
1416 };
1417
1418 println!("x: {}", x);
1419}
1420"#,
1421 expect![[r#"
1422 FileId(0) 24..26
1423 FileId(0) 42..43
1424 FileId(0) 55..57
1425 FileId(0) 74..75
1426 FileId(0) 97..98
1427 "#]],
1428 );
1429 }
1430
1431 #[test]
1432 fn test_highlight_match_branches() {
1433 check(
1434 r#"
1435fn main() {
1436 $0match Some(42) {
1437 Some(x) if x > 0 => println!("positive"),
1438 Some(0) => println!("zero"),
1439 Some(_) => println!("negative"),
1440 None => println!("none"),
1441 };
1442}
1443"#,
1444 expect![[r#"
1445 FileId(0) 16..21
1446 FileId(0) 61..81
1447 FileId(0) 102..118
1448 FileId(0) 139..159
1449 FileId(0) 177..193
1450 "#]],
1451 );
1452 }
1453
1454 #[test]
1455 fn test_highlight_match_arm_arrow() {
1456 check(
1457 r#"
1458fn main() {
1459 match Some(42) {
1460 Some(x) if x > 0 $0=> println!("positive"),
1461 Some(0) => println!("zero"),
1462 Some(_) => println!("negative"),
1463 None => println!("none"),
1464 }
1465}
1466"#,
1467 expect![[r#"
1468 FileId(0) 58..60
1469 FileId(0) 61..81
1470 "#]],
1471 );
1472 }
1473
1474 #[test]
1475 fn test_highlight_nested_branches() {
1476 check(
1477 r#"
1478fn main() {
1479 let x = $0if true {
1480 if false {
1481 1
1482 } else {
1483 match Some(42) {
1484 Some(_) => 2,
1485 None => 3,
1486 }
1487 }
1488 } else {
1489 4
1490 };
1491
1492 println!("x: {}", x);
1493}
1494"#,
1495 expect![[r#"
1496 FileId(0) 24..26
1497 FileId(0) 65..66
1498 FileId(0) 140..141
1499 FileId(0) 167..168
1500 FileId(0) 215..216
1501 "#]],
1502 );
1503 }
1504
1505 #[test]
1506 fn test_highlight_match_with_complex_guards() {
1507 check(
1508 r#"
1509fn main() {
1510 let x = $0match (x, y) {
1511 (a, b) if a > b && a % 2 == 0 => 1,
1512 (a, b) if a < b || b % 2 == 1 => 2,
1513 (a, _) if a > 40 => 3,
1514 _ => 4,
1515 };
1516
1517 println!("x: {}", x);
1518}
1519"#,
1520 expect![[r#"
1521 FileId(0) 24..29
1522 FileId(0) 80..81
1523 FileId(0) 124..125
1524 FileId(0) 155..156
1525 FileId(0) 171..172
1526 "#]],
1527 );
1528 }
1529
1530 #[test]
1531 fn test_highlight_mixed_if_match_expressions() {
1532 check(
1533 r#"
1534fn main() {
1535 let x = $0if let Some(x) = Some(42) {
1536 1
1537 } else if let None = None {
1538 2
1539 } else {
1540 match 42 {
1541 0 => 3,
1542 _ => 4,
1543 }
1544 };
1545}
1546"#,
1547 expect![[r#"
1548 FileId(0) 24..26
1549 FileId(0) 60..61
1550 FileId(0) 73..75
1551 FileId(0) 102..103
1552 FileId(0) 153..154
1553 FileId(0) 173..174
1554 "#]],
1555 );
1556 }
1557
1558 fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
1559 check_with_scope(ra_fixture, None, expect)
1560 }
1561
1562 fn check_with_scope(
1563 #[rust_analyzer::rust_fixture] ra_fixture: &str,
1564 search_scope: Option<&mut dyn FnMut(&RootDatabase) -> SearchScope>,
1565 expect: Expect,
1566 ) {
1567 let (analysis, pos) = fixture::position(ra_fixture);
1568 let config = FindAllRefsConfig {
1569 search_scope: search_scope.map(|it| it(&analysis.db)),
1570 minicore: MiniCore::default(),
1571 };
1572 let refs = analysis.find_all_refs(pos, &config).unwrap().unwrap();
1573
1574 let mut actual = String::new();
1575 for mut refs in refs {
1576 actual += "\n\n";
1577
1578 if let Some(decl) = refs.declaration {
1579 format_to!(actual, "{}", decl.nav.debug_render());
1580 if decl.is_mut {
1581 format_to!(actual, " write",)
1582 }
1583 actual += "\n\n";
1584 }
1585
1586 for (file_id, references) in &mut refs.references {
1587 references.sort_by_key(|(range, _)| range.start());
1588 for (range, category) in references {
1589 format_to!(actual, "{:?} {:?}", file_id, range);
1590 for (name, _flag) in category.iter_names() {
1591 format_to!(actual, " {}", name.to_lowercase());
1592 }
1593 actual += "\n";
1594 }
1595 }
1596
1597 if refs.references.is_empty() {
1598 actual += "(no references)\n";
1599 }
1600 }
1601 expect.assert_eq(actual.trim_start())
1602 }
1603
1604 #[test]
1605 fn test_find_lifetimes_function() {
1606 check(
1607 r#"
1608trait Foo<'a> {}
1609impl<'a> Foo<'a> for &'a () {}
1610fn foo<'a, 'b: 'a>(x: &'a$0 ()) -> &'a () where &'a (): Foo<'a> {
1611 fn bar<'a>(_: &'a ()) {}
1612 x
1613}
1614"#,
1615 expect![[r#"
1616 'a LifetimeParam FileId(0) 55..57
1617
1618 FileId(0) 63..65
1619 FileId(0) 71..73
1620 FileId(0) 82..84
1621 FileId(0) 95..97
1622 FileId(0) 106..108
1623 "#]],
1624 );
1625 }
1626
1627 #[test]
1628 fn test_find_lifetimes_type_alias() {
1629 check(
1630 r#"
1631type Foo<'a, T> where T: 'a$0 = &'a T;
1632"#,
1633 expect![[r#"
1634 'a LifetimeParam FileId(0) 9..11
1635
1636 FileId(0) 25..27
1637 FileId(0) 31..33
1638 "#]],
1639 );
1640 }
1641
1642 #[test]
1643 fn test_find_lifetimes_trait_impl() {
1644 check(
1645 r#"
1646trait Foo<'a> {
1647 fn foo() -> &'a ();
1648}
1649impl<'a> Foo<'a> for &'a () {
1650 fn foo() -> &'a$0 () {
1651 unimplemented!()
1652 }
1653}
1654"#,
1655 expect![[r#"
1656 'a LifetimeParam FileId(0) 47..49
1657
1658 FileId(0) 55..57
1659 FileId(0) 64..66
1660 FileId(0) 89..91
1661 "#]],
1662 );
1663 }
1664
1665 #[test]
1666 fn test_map_range_to_original() {
1667 check(
1668 r#"
1669macro_rules! foo {($i:ident) => {$i} }
1670fn main() {
1671 let a$0 = "test";
1672 foo!(a);
1673}
1674"#,
1675 expect![[r#"
1676 a Local FileId(0) 59..60 59..60
1677
1678 FileId(0) 80..81 read
1679 "#]],
1680 );
1681 }
1682
1683 #[test]
1684 fn test_map_range_to_original_ref() {
1685 check(
1686 r#"
1687macro_rules! foo {($i:ident) => {$i} }
1688fn main() {
1689 let a = "test";
1690 foo!(a$0);
1691}
1692"#,
1693 expect![[r#"
1694 a Local FileId(0) 59..60 59..60
1695
1696 FileId(0) 80..81 read
1697 "#]],
1698 );
1699 }
1700
1701 #[test]
1702 fn test_find_labels() {
1703 check(
1704 r#"
1705fn foo<'a>() -> &'a () {
1706 'a: loop {
1707 'b: loop {
1708 continue 'a$0;
1709 }
1710 break 'a;
1711 }
1712}
1713"#,
1714 expect![[r#"
1715 'a Label FileId(0) 29..32 29..31
1716
1717 FileId(0) 80..82
1718 FileId(0) 108..110
1719 "#]],
1720 );
1721 }
1722
1723 #[test]
1724 fn test_find_const_param() {
1725 check(
1726 r#"
1727fn foo<const FOO$0: usize>() -> usize {
1728 FOO
1729}
1730"#,
1731 expect![[r#"
1732 FOO ConstParam FileId(0) 7..23 13..16
1733
1734 FileId(0) 42..45
1735 "#]],
1736 );
1737 }
1738
1739 #[test]
1740 fn test_trait() {
1741 check(
1742 r#"
1743trait Foo$0 where Self: {}
1744
1745impl Foo for () {}
1746"#,
1747 expect![[r#"
1748 Foo Trait FileId(0) 0..24 6..9
1749
1750 FileId(0) 31..34
1751 "#]],
1752 );
1753 }
1754
1755 #[test]
1756 fn test_trait_self() {
1757 check(
1758 r#"
1759trait Foo where Self$0 {
1760 fn f() -> Self;
1761}
1762
1763impl Foo for () {}
1764"#,
1765 expect![[r#"
1766 Self TypeParam FileId(0) 0..44 6..9
1767
1768 FileId(0) 16..20
1769 FileId(0) 37..41
1770 "#]],
1771 );
1772 }
1773
1774 #[test]
1775 fn test_self_ty() {
1776 check(
1777 r#"
1778 struct $0Foo;
1779
1780 impl Foo where Self: {
1781 fn f() -> Self;
1782 }
1783 "#,
1784 expect![[r#"
1785 Foo Struct FileId(0) 0..11 7..10
1786
1787 FileId(0) 18..21
1788 FileId(0) 28..32
1789 FileId(0) 50..54
1790 "#]],
1791 );
1792 check(
1793 r#"
1794struct Foo;
1795
1796impl Foo where Self: {
1797 fn f() -> Self$0;
1798}
1799"#,
1800 expect![[r#"
1801 impl Impl FileId(0) 13..57 18..21
1802
1803 FileId(0) 18..21
1804 FileId(0) 28..32
1805 FileId(0) 50..54
1806 "#]],
1807 );
1808 }
1809 #[test]
1810 fn test_self_variant_with_payload() {
1811 check(
1812 r#"
1813enum Foo { Bar() }
1814
1815impl Foo {
1816 fn foo(self) {
1817 match self {
1818 Self::Bar$0() => (),
1819 }
1820 }
1821}
1822
1823"#,
1824 expect![[r#"
1825 Bar Variant FileId(0) 11..16 11..14
1826
1827 FileId(0) 89..92
1828 "#]],
1829 );
1830 }
1831
1832 #[test]
1833 fn test_trait_alias() {
1834 check(
1835 r#"
1836trait Foo {}
1837trait Bar$0 = Foo where Self: ;
1838fn foo<T: Bar>(_: impl Bar, _: &dyn Bar) {}
1839"#,
1840 expect![[r#"
1841 Bar Trait FileId(0) 13..42 19..22
1842
1843 FileId(0) 53..56
1844 FileId(0) 66..69
1845 FileId(0) 79..82
1846 "#]],
1847 );
1848 }
1849
1850 #[test]
1851 fn test_trait_alias_self() {
1852 check(
1853 r#"
1854trait Foo = where Self$0: ;
1855"#,
1856 expect![[r#"
1857 Self TypeParam FileId(0) 0..25 6..9
1858
1859 FileId(0) 18..22
1860 "#]],
1861 );
1862 }
1863
1864 #[test]
1865 fn test_attr_differs_from_fn_with_same_name() {
1866 check(
1867 r#"
1868#[test]
1869fn test$0() {
1870 test();
1871}
1872"#,
1873 expect![[r#"
1874 test Function FileId(0) 0..33 11..15
1875
1876 FileId(0) 24..28 test
1877 "#]],
1878 );
1879 }
1880
1881 #[test]
1882 fn test_const_in_pattern() {
1883 check(
1884 r#"
1885const A$0: i32 = 42;
1886
1887fn main() {
1888 match A {
1889 A => (),
1890 _ => (),
1891 }
1892 if let A = A {}
1893}
1894"#,
1895 expect![[r#"
1896 A Const FileId(0) 0..18 6..7
1897
1898 FileId(0) 42..43
1899 FileId(0) 54..55
1900 FileId(0) 97..98
1901 FileId(0) 101..102
1902 "#]],
1903 );
1904 }
1905
1906 #[test]
1907 fn test_primitives() {
1908 check(
1909 r#"
1910fn foo(_: bool) -> bo$0ol { true }
1911"#,
1912 expect![[r#"
1913 FileId(0) 10..14
1914 FileId(0) 19..23
1915 "#]],
1916 );
1917 }
1918
1919 #[test]
1920 fn test_transitive() {
1921 check(
1922 r#"
1923//- /level3.rs new_source_root:local crate:level3
1924pub struct Fo$0o;
1925//- /level2.rs new_source_root:local crate:level2 deps:level3
1926pub use level3::Foo;
1927//- /level1.rs new_source_root:local crate:level1 deps:level2
1928pub use level2::Foo;
1929//- /level0.rs new_source_root:local crate:level0 deps:level1
1930pub use level1::Foo;
1931"#,
1932 expect![[r#"
1933 Foo Struct FileId(0) 0..15 11..14
1934
1935 FileId(1) 16..19 import
1936 FileId(2) 16..19 import
1937 FileId(3) 16..19 import
1938 "#]],
1939 );
1940 }
1941
1942 #[test]
1943 fn test_decl_macro_references() {
1944 check(
1945 r#"
1946//- /lib.rs crate:lib
1947#[macro_use]
1948mod qux;
1949mod bar;
1950
1951pub use self::foo;
1952//- /qux.rs
1953#[macro_export]
1954macro_rules! foo$0 {
1955 () => {struct Foo;};
1956}
1957//- /bar.rs
1958foo!();
1959//- /other.rs crate:other deps:lib new_source_root:local
1960lib::foo!();
1961"#,
1962 expect![[r#"
1963 foo Macro FileId(1) 0..61 29..32
1964
1965 FileId(0) 46..49 import
1966 FileId(2) 0..3
1967 FileId(3) 5..8
1968 "#]],
1969 );
1970 }
1971
1972 #[test]
1973 fn macro_doesnt_reference_attribute_on_call() {
1974 check(
1975 r#"
1976macro_rules! m {
1977 () => {};
1978}
1979
1980#[proc_macro_test::attr_noop]
1981m$0!();
1982
1983"#,
1984 expect![[r#"
1985 m Macro FileId(0) 0..32 13..14
1986
1987 FileId(0) 64..65
1988 "#]],
1989 );
1990 }
1991
1992 #[test]
1993 fn multi_def() {
1994 check(
1995 r#"
1996macro_rules! m {
1997 ($name:ident) => {
1998 mod module {
1999 pub fn $name() {}
2000 }
2001
2002 pub fn $name() {}
2003 }
2004}
2005
2006m!(func$0);
2007
2008fn f() {
2009 func();
2010 module::func();
2011}
2012 "#,
2013 expect![[r#"
2014 func Function FileId(0) 137..146 140..144 module
2015
2016 FileId(0) 181..185
2017
2018
2019 func Function FileId(0) 137..146 140..144
2020
2021 FileId(0) 161..165
2022 "#]],
2023 )
2024 }
2025
2026 #[test]
2027 fn attr_expanded() {
2028 check(
2029 r#"
2030//- proc_macros: identity
2031#[proc_macros::identity]
2032fn func$0() {
2033 func();
2034}
2035"#,
2036 expect![[r#"
2037 func Function FileId(0) 25..50 28..32
2038
2039 FileId(0) 41..45
2040 "#]],
2041 )
2042 }
2043
2044 #[test]
2045 fn attr_assoc_item() {
2046 check(
2047 r#"
2048//- proc_macros: identity
2049
2050trait Trait {
2051 #[proc_macros::identity]
2052 fn func() {
2053 Self::func$0();
2054 }
2055}
2056"#,
2057 expect![[r#"
2058 func Function FileId(0) 48..87 51..55 Trait
2059
2060 FileId(0) 74..78
2061 "#]],
2062 )
2063 }
2064
2065 #[test]
2067 fn attr() {
2068 check(
2069 r#"
2070//- proc_macros: identity
2071use proc_macros::identity;
2072
2073#[proc_macros::$0identity]
2074fn func() {}
2075"#,
2076 expect![[r#"
2077 identity Attribute FileId(1) 1..107 32..40
2078
2079 FileId(0) 17..25 import
2080 FileId(0) 43..51
2081 "#]],
2082 );
2083 check(
2084 r#"
2085#![crate_type="proc-macro"]
2086#[proc_macro_attribute]
2087fn func$0() {}
2088"#,
2089 expect![[r#"
2090 func Attribute FileId(0) 28..64 55..59
2091
2092 (no references)
2093 "#]],
2094 );
2095 }
2096
2097 #[test]
2099 fn proc_macro() {
2100 check(
2101 r#"
2102//- proc_macros: mirror
2103use proc_macros::mirror;
2104
2105mirror$0! {}
2106"#,
2107 expect![[r#"
2108 mirror ProcMacro FileId(1) 1..77 22..28
2109
2110 FileId(0) 17..23 import
2111 FileId(0) 26..32
2112 "#]],
2113 )
2114 }
2115
2116 #[test]
2117 fn derive() {
2118 check(
2119 r#"
2120//- proc_macros: derive_identity
2121//- minicore: derive
2122use proc_macros::DeriveIdentity;
2123
2124#[derive(proc_macros::DeriveIdentity$0)]
2125struct Foo;
2126"#,
2127 expect![[r#"
2128 derive_identity Derive FileId(2) 1..107 45..60
2129
2130 FileId(0) 17..31 import
2131 FileId(0) 56..70
2132 "#]],
2133 );
2134 check(
2135 r#"
2136#![crate_type="proc-macro"]
2137#[proc_macro_derive(Derive, attributes(x))]
2138pub fn deri$0ve(_stream: TokenStream) -> TokenStream {}
2139"#,
2140 expect![[r#"
2141 derive Derive FileId(0) 28..125 79..85
2142
2143 (no references)
2144 "#]],
2145 );
2146 }
2147
2148 #[test]
2149 fn assoc_items_trait_def() {
2150 check(
2151 r#"
2152trait Trait {
2153 const CONST$0: usize;
2154}
2155
2156impl Trait for () {
2157 const CONST: usize = 0;
2158}
2159
2160impl Trait for ((),) {
2161 const CONST: usize = 0;
2162}
2163
2164fn f<T: Trait>() {
2165 let _ = <()>::CONST;
2166
2167 let _ = T::CONST;
2168}
2169"#,
2170 expect![[r#"
2171 CONST Const FileId(0) 18..37 24..29 Trait
2172
2173 FileId(0) 71..76
2174 FileId(0) 125..130
2175 FileId(0) 183..188
2176 FileId(0) 206..211
2177 "#]],
2178 );
2179 check(
2180 r#"
2181trait Trait {
2182 type TypeAlias$0;
2183}
2184
2185impl Trait for () {
2186 type TypeAlias = ();
2187}
2188
2189impl Trait for ((),) {
2190 type TypeAlias = ();
2191}
2192
2193fn f<T: Trait>() {
2194 let _: <() as Trait>::TypeAlias;
2195
2196 let _: T::TypeAlias;
2197}
2198"#,
2199 expect![[r#"
2200 TypeAlias TypeAlias FileId(0) 18..33 23..32 Trait
2201
2202 FileId(0) 66..75
2203 FileId(0) 117..126
2204 FileId(0) 181..190
2205 FileId(0) 207..216
2206 "#]],
2207 );
2208 check(
2209 r#"
2210trait Trait {
2211 fn function$0() {}
2212}
2213
2214impl Trait for () {
2215 fn function() {}
2216}
2217
2218impl Trait for ((),) {
2219 fn function() {}
2220}
2221
2222fn f<T: Trait>() {
2223 let _ = <()>::function;
2224
2225 let _ = T::function;
2226}
2227"#,
2228 expect![[r#"
2229 function Function FileId(0) 18..34 21..29 Trait
2230
2231 FileId(0) 65..73
2232 FileId(0) 112..120
2233 FileId(0) 166..174
2234 FileId(0) 192..200
2235 "#]],
2236 );
2237 }
2238
2239 #[test]
2240 fn assoc_items_trait_impl_def() {
2241 check(
2242 r#"
2243trait Trait {
2244 const CONST: usize;
2245}
2246
2247impl Trait for () {
2248 const CONST$0: usize = 0;
2249}
2250
2251impl Trait for ((),) {
2252 const CONST: usize = 0;
2253}
2254
2255fn f<T: Trait>() {
2256 let _ = <()>::CONST;
2257
2258 let _ = T::CONST;
2259}
2260"#,
2261 expect![[r#"
2262 CONST Const FileId(0) 65..88 71..76
2263
2264 FileId(0) 183..188
2265 "#]],
2266 );
2267 check(
2268 r#"
2269trait Trait {
2270 type TypeAlias;
2271}
2272
2273impl Trait for () {
2274 type TypeAlias$0 = ();
2275}
2276
2277impl Trait for ((),) {
2278 type TypeAlias = ();
2279}
2280
2281fn f<T: Trait>() {
2282 let _: <() as Trait>::TypeAlias;
2283
2284 let _: T::TypeAlias;
2285}
2286"#,
2287 expect![[r#"
2288 TypeAlias TypeAlias FileId(0) 61..81 66..75
2289
2290 FileId(0) 23..32
2291 FileId(0) 117..126
2292 FileId(0) 181..190
2293 FileId(0) 207..216
2294 "#]],
2295 );
2296 check(
2297 r#"
2298trait Trait {
2299 fn function() {}
2300}
2301
2302impl Trait for () {
2303 fn function$0() {}
2304}
2305
2306impl Trait for ((),) {
2307 fn function() {}
2308}
2309
2310fn f<T: Trait>() {
2311 let _ = <()>::function;
2312
2313 let _ = T::function;
2314}
2315"#,
2316 expect![[r#"
2317 function Function FileId(0) 62..78 65..73
2318
2319 FileId(0) 166..174
2320 "#]],
2321 );
2322 }
2323
2324 #[test]
2325 fn assoc_items_ref() {
2326 check(
2327 r#"
2328trait Trait {
2329 const CONST: usize;
2330}
2331
2332impl Trait for () {
2333 const CONST: usize = 0;
2334}
2335
2336impl Trait for ((),) {
2337 const CONST: usize = 0;
2338}
2339
2340fn f<T: Trait>() {
2341 let _ = <()>::CONST$0;
2342
2343 let _ = T::CONST;
2344}
2345"#,
2346 expect![[r#"
2347 CONST Const FileId(0) 65..88 71..76
2348
2349 FileId(0) 183..188
2350 "#]],
2351 );
2352 check(
2353 r#"
2354trait Trait {
2355 type TypeAlias;
2356}
2357
2358impl Trait for () {
2359 type TypeAlias = ();
2360}
2361
2362impl Trait for ((),) {
2363 type TypeAlias = ();
2364}
2365
2366fn f<T: Trait>() {
2367 let _: <() as Trait>::TypeAlias$0;
2368
2369 let _: T::TypeAlias;
2370}
2371"#,
2372 expect![[r#"
2373 TypeAlias TypeAlias FileId(0) 18..33 23..32 Trait
2374
2375 FileId(0) 66..75
2376 FileId(0) 117..126
2377 FileId(0) 181..190
2378 FileId(0) 207..216
2379 "#]],
2380 );
2381 check(
2382 r#"
2383trait Trait {
2384 fn function() {}
2385}
2386
2387impl Trait for () {
2388 fn function() {}
2389}
2390
2391impl Trait for ((),) {
2392 fn function() {}
2393}
2394
2395fn f<T: Trait>() {
2396 let _ = <()>::function$0;
2397
2398 let _ = T::function;
2399}
2400"#,
2401 expect![[r#"
2402 function Function FileId(0) 62..78 65..73
2403
2404 FileId(0) 166..174
2405 "#]],
2406 );
2407 }
2408
2409 #[test]
2410 fn name_clashes() {
2411 check(
2412 r#"
2413trait Foo {
2414 fn method$0(&self) -> u8;
2415}
2416
2417struct Bar {
2418 method: u8,
2419}
2420
2421impl Foo for Bar {
2422 fn method(&self) -> u8 {
2423 self.method
2424 }
2425}
2426fn method() {}
2427"#,
2428 expect![[r#"
2429 method Function FileId(0) 16..39 19..25 Foo
2430
2431 FileId(0) 101..107
2432 "#]],
2433 );
2434 check(
2435 r#"
2436trait Foo {
2437 fn method(&self) -> u8;
2438}
2439
2440struct Bar {
2441 method$0: u8,
2442}
2443
2444impl Foo for Bar {
2445 fn method(&self) -> u8 {
2446 self.method
2447 }
2448}
2449fn method() {}
2450"#,
2451 expect![[r#"
2452 method Field FileId(0) 60..70 60..66
2453
2454 FileId(0) 136..142 read
2455 "#]],
2456 );
2457 check(
2458 r#"
2459trait Foo {
2460 fn method(&self) -> u8;
2461}
2462
2463struct Bar {
2464 method: u8,
2465}
2466
2467impl Foo for Bar {
2468 fn method$0(&self) -> u8 {
2469 self.method
2470 }
2471}
2472fn method() {}
2473"#,
2474 expect![[r#"
2475 method Function FileId(0) 98..148 101..107
2476
2477 (no references)
2478 "#]],
2479 );
2480 check(
2481 r#"
2482trait Foo {
2483 fn method(&self) -> u8;
2484}
2485
2486struct Bar {
2487 method: u8,
2488}
2489
2490impl Foo for Bar {
2491 fn method(&self) -> u8 {
2492 self.method$0
2493 }
2494}
2495fn method() {}
2496"#,
2497 expect![[r#"
2498 method Field FileId(0) 60..70 60..66
2499
2500 FileId(0) 136..142 read
2501 "#]],
2502 );
2503 check(
2504 r#"
2505trait Foo {
2506 fn method(&self) -> u8;
2507}
2508
2509struct Bar {
2510 method: u8,
2511}
2512
2513impl Foo for Bar {
2514 fn method(&self) -> u8 {
2515 self.method
2516 }
2517}
2518fn method$0() {}
2519"#,
2520 expect![[r#"
2521 method Function FileId(0) 151..165 154..160
2522
2523 (no references)
2524 "#]],
2525 );
2526 }
2527
2528 #[test]
2529 fn raw_identifier() {
2530 check(
2531 r#"
2532fn r#fn$0() {}
2533fn main() { r#fn(); }
2534"#,
2535 expect![[r#"
2536 fn Function FileId(0) 0..12 3..7
2537
2538 FileId(0) 25..29
2539 "#]],
2540 );
2541 }
2542
2543 #[test]
2544 fn implicit_format_args() {
2545 check(
2546 r#"
2547//- minicore: fmt
2548fn test() {
2549 let a = "foo";
2550 format_args!("hello {a} {a$0} {}", a);
2551 // ^
2552 // ^
2553 // ^
2554}
2555"#,
2556 expect![[r#"
2557 a Local FileId(0) 20..21 20..21
2558
2559 FileId(0) 56..57 read
2560 FileId(0) 60..61 read
2561 FileId(0) 68..69 read
2562 "#]],
2563 );
2564 }
2565
2566 #[test]
2567 fn goto_ref_fn_kw() {
2568 check(
2569 r#"
2570macro_rules! N {
2571 ($i:ident, $x:expr, $blk:expr) => {
2572 for $i in 0..$x {
2573 $blk
2574 }
2575 };
2576}
2577
2578fn main() {
2579 $0fn f() {
2580 N!(i, 5, {
2581 println!("{}", i);
2582 return;
2583 });
2584
2585 for i in 1..5 {
2586 return;
2587 }
2588
2589 (|| {
2590 return;
2591 })();
2592 }
2593}
2594"#,
2595 expect![[r#"
2596 FileId(0) 136..138
2597 FileId(0) 207..213
2598 FileId(0) 264..270
2599 "#]],
2600 )
2601 }
2602
2603 #[test]
2604 fn goto_ref_exit_points() {
2605 check(
2606 r#"
2607fn$0 foo() -> u32 {
2608 if true {
2609 return 0;
2610 }
2611
2612 0?;
2613 0xDEAD_BEEF
2614}
2615"#,
2616 expect![[r#"
2617 FileId(0) 0..2
2618 FileId(0) 40..46
2619 FileId(0) 62..63
2620 FileId(0) 69..80
2621 "#]],
2622 );
2623 }
2624
2625 #[test]
2626 fn test_ref_yield_points() {
2627 check(
2628 r#"
2629pub async$0 fn foo() {
2630 let x = foo()
2631 .await
2632 .await;
2633 || { 0.await };
2634 (async { 0.await }).await
2635}
2636"#,
2637 expect![[r#"
2638 FileId(0) 4..9
2639 FileId(0) 48..53
2640 FileId(0) 63..68
2641 FileId(0) 114..119
2642 "#]],
2643 );
2644 }
2645
2646 #[test]
2647 fn goto_ref_for_kw() {
2648 check(
2649 r#"
2650fn main() {
2651 $0for i in 1..5 {
2652 break;
2653 continue;
2654 }
2655}
2656"#,
2657 expect![[r#"
2658 FileId(0) 16..19
2659 FileId(0) 40..45
2660 FileId(0) 55..63
2661 "#]],
2662 )
2663 }
2664
2665 #[test]
2666 fn goto_ref_on_break_kw() {
2667 check(
2668 r#"
2669fn main() {
2670 for i in 1..5 {
2671 $0break;
2672 continue;
2673 }
2674}
2675"#,
2676 expect![[r#"
2677 FileId(0) 16..19
2678 FileId(0) 40..45
2679 "#]],
2680 )
2681 }
2682
2683 #[test]
2684 fn goto_ref_on_break_kw_for_block() {
2685 check(
2686 r#"
2687fn main() {
2688 'a:{
2689 $0break 'a;
2690 }
2691}
2692"#,
2693 expect![[r#"
2694 FileId(0) 16..19
2695 FileId(0) 29..37
2696 "#]],
2697 )
2698 }
2699
2700 #[test]
2701 fn goto_ref_on_break_with_label() {
2702 check(
2703 r#"
2704fn foo() {
2705 'outer: loop {
2706 break;
2707 'inner: loop {
2708 'innermost: loop {
2709 }
2710 $0break 'outer;
2711 break;
2712 }
2713 break;
2714 }
2715}
2716"#,
2717 expect![[r#"
2718 FileId(0) 15..27
2719 FileId(0) 39..44
2720 FileId(0) 127..139
2721 FileId(0) 178..183
2722 "#]],
2723 );
2724 }
2725
2726 #[test]
2727 fn goto_ref_on_return_in_try() {
2728 check(
2729 r#"
2730fn main() {
2731 fn f() {
2732 try {
2733 $0return;
2734 }
2735
2736 return;
2737 }
2738 return;
2739}
2740"#,
2741 expect![[r#"
2742 FileId(0) 16..18
2743 FileId(0) 51..57
2744 FileId(0) 78..84
2745 "#]],
2746 )
2747 }
2748
2749 #[test]
2750 fn goto_ref_on_break_in_try() {
2751 check(
2752 r#"
2753fn main() {
2754 for i in 1..100 {
2755 let x: Result<(), ()> = try {
2756 $0break;
2757 };
2758 }
2759}
2760"#,
2761 expect![[r#"
2762 FileId(0) 16..19
2763 FileId(0) 84..89
2764 "#]],
2765 )
2766 }
2767
2768 #[test]
2769 fn goto_ref_on_return_in_async_block() {
2770 check(
2771 r#"
2772fn main() {
2773 $0async {
2774 return;
2775 }
2776}
2777"#,
2778 expect![[r#"
2779 FileId(0) 16..21
2780 FileId(0) 32..38
2781 "#]],
2782 )
2783 }
2784
2785 #[test]
2786 fn goto_ref_on_return_in_macro_call() {
2787 check(
2788 r#"
2789//- minicore:include
2790//- /lib.rs
2791macro_rules! M {
2792 ($blk:expr) => {
2793 fn f() {
2794 $blk
2795 }
2796
2797 $blk
2798 };
2799}
2800
2801fn main() {
2802 M!({
2803 return$0;
2804 });
2805
2806 f();
2807 include!("a.rs")
2808}
2809
2810//- /a.rs
2811{
2812 return;
2813}
2814"#,
2815 expect![[r#"
2816 FileId(0) 46..48
2817 FileId(0) 106..108
2818 FileId(0) 122..149
2819 FileId(0) 135..141
2820 FileId(0) 165..181
2821 FileId(1) 6..12
2822 "#]],
2823 )
2824 }
2825
2826 #[test]
2830 fn goto_ref_on_short_associated_function() {
2831 cov_mark::check!(short_associated_function_fast_search);
2832 check(
2833 r#"
2834struct Foo;
2835impl Foo {
2836 fn new$0() {}
2837}
2838
2839fn bar() {
2840 Foo::new();
2841}
2842fn baz() {
2843 Foo::new;
2844}
2845 "#,
2846 expect![[r#"
2847 new Function FileId(0) 27..38 30..33
2848
2849 FileId(0) 62..65
2850 FileId(0) 91..94
2851 "#]],
2852 );
2853 }
2854
2855 #[test]
2856 fn goto_ref_on_short_associated_function_with_aliases() {
2857 cov_mark::check!(short_associated_function_fast_search);
2858 cov_mark::check!(container_use_rename);
2859 cov_mark::check!(container_type_alias);
2860 check(
2861 r#"
2862//- /lib.rs
2863mod a;
2864mod b;
2865
2866struct Foo;
2867impl Foo {
2868 fn new$0() {}
2869}
2870
2871fn bar() {
2872 b::c::Baz::new();
2873}
2874
2875//- /a.rs
2876use crate::Foo as Bar;
2877
2878fn baz() { Bar::new(); }
2879fn quux() { <super::b::Other as super::b::Trait>::Assoc::new(); }
2880
2881//- /b.rs
2882pub(crate) mod c;
2883
2884pub(crate) struct Other;
2885pub(crate) trait Trait {
2886 type Assoc;
2887}
2888impl Trait for Other {
2889 type Assoc = super::Foo;
2890}
2891
2892//- /b/c.rs
2893type Itself<T> = T;
2894pub(in super::super) type Baz = Itself<crate::Foo>;
2895 "#,
2896 expect![[r#"
2897 new Function FileId(0) 42..53 45..48
2898
2899 FileId(0) 83..86
2900 FileId(1) 40..43
2901 FileId(1) 106..109
2902 "#]],
2903 );
2904 }
2905
2906 #[test]
2907 fn goto_ref_on_short_associated_function_self_works() {
2908 cov_mark::check!(short_associated_function_fast_search);
2909 cov_mark::check!(self_type_alias);
2910 check(
2911 r#"
2912//- /lib.rs
2913mod module;
2914
2915struct Foo;
2916impl Foo {
2917 fn new$0() {}
2918 fn bar() { Self::new(); }
2919}
2920trait Trait {
2921 type Assoc;
2922 fn baz();
2923}
2924impl Trait for Foo {
2925 type Assoc = Self;
2926 fn baz() { Self::new(); }
2927}
2928
2929//- /module.rs
2930impl super::Foo {
2931 fn quux() { Self::new(); }
2932}
2933fn foo() { <super::Foo as super::Trait>::Assoc::new(); }
2934 "#,
2935 expect![[r#"
2936 new Function FileId(0) 40..51 43..46
2937
2938 FileId(0) 73..76
2939 FileId(0) 195..198
2940 FileId(1) 40..43
2941 FileId(1) 99..102
2942 "#]],
2943 );
2944 }
2945
2946 #[test]
2947 fn goto_ref_on_short_associated_function_overlapping_self_ranges() {
2948 check(
2949 r#"
2950struct Foo;
2951impl Foo {
2952 fn new$0() {}
2953 fn bar() {
2954 Self::new();
2955 impl Foo {
2956 fn baz() { Self::new(); }
2957 }
2958 }
2959}
2960 "#,
2961 expect![[r#"
2962 new Function FileId(0) 27..38 30..33
2963
2964 FileId(0) 68..71
2965 FileId(0) 123..126
2966 "#]],
2967 );
2968 }
2969
2970 #[test]
2971 fn goto_ref_on_short_associated_function_no_direct_self_but_path_contains_self() {
2972 cov_mark::check!(short_associated_function_fast_search);
2973 check(
2974 r#"
2975struct Foo;
2976impl Foo {
2977 fn new$0() {}
2978}
2979trait Trait {
2980 type Assoc;
2981}
2982impl<A, B> Trait for (A, B) {
2983 type Assoc = B;
2984}
2985impl Foo {
2986 fn bar() {
2987 <((), Foo) as Trait>::Assoc::new();
2988 <((), Self) as Trait>::Assoc::new();
2989 }
2990}
2991 "#,
2992 expect![[r#"
2993 new Function FileId(0) 27..38 30..33
2994
2995 FileId(0) 188..191
2996 FileId(0) 233..236
2997 "#]],
2998 );
2999 }
3000
3001 #[test]
3005 fn goto_ref_on_short_associated_function_complicated_type_magic_can_confuse_our_logic() {
3006 cov_mark::check!(short_associated_function_fast_search);
3007 cov_mark::check!(same_name_different_def_type_alias);
3008 check(
3009 r#"
3010struct Foo;
3011impl Foo {
3012 fn new$0() {}
3013}
3014
3015struct ChoiceA;
3016struct ChoiceB;
3017trait Choice {
3018 type Choose<A, B>;
3019}
3020impl Choice for ChoiceA {
3021 type Choose<A, B> = A;
3022}
3023impl Choice for ChoiceB {
3024 type Choose<A, B> = B;
3025}
3026type Choose<A, C> = <C as Choice>::Choose<A, Foo>;
3027
3028fn bar() {
3029 Choose::<(), ChoiceB>::new();
3030}
3031 "#,
3032 expect![[r#"
3033 new Function FileId(0) 27..38 30..33
3034
3035 (no references)
3036 "#]],
3037 );
3038 }
3039
3040 #[test]
3041 fn goto_ref_on_short_associated_function_same_path_mention_alias_and_self() {
3042 cov_mark::check!(short_associated_function_fast_search);
3043 check(
3044 r#"
3045struct Foo;
3046impl Foo {
3047 fn new$0() {}
3048}
3049
3050type IgnoreFirst<A, B> = B;
3051
3052impl Foo {
3053 fn bar() {
3054 <IgnoreFirst<Foo, Self>>::new();
3055 }
3056}
3057 "#,
3058 expect![[r#"
3059 new Function FileId(0) 27..38 30..33
3060
3061 FileId(0) 131..134
3062 "#]],
3063 );
3064 }
3065
3066 #[test]
3067 fn goto_ref_on_included_file() {
3068 check(
3069 r#"
3070//- minicore:include
3071//- /lib.rs
3072include!("foo.rs");
3073fn howdy() {
3074 let _ = FOO;
3075}
3076//- /foo.rs
3077const FOO$0: i32 = 0;
3078"#,
3079 expect![[r#"
3080 FOO Const FileId(1) 0..19 6..9
3081
3082 FileId(0) 45..48
3083 "#]],
3084 );
3085 }
3086
3087 #[test]
3088 fn test_highlight_if_let_match_combined() {
3089 check(
3090 r#"
3091enum MyEnum { A(i32), B(String), C }
3092
3093fn main() {
3094 let val = MyEnum::A(42);
3095
3096 let x = $0if let MyEnum::A(x) = val {
3097 1
3098 } else if let MyEnum::B(s) = val {
3099 2
3100 } else {
3101 match val {
3102 MyEnum::C => 3,
3103 _ => 4,
3104 }
3105 };
3106}
3107"#,
3108 expect![[r#"
3109 FileId(0) 92..94
3110 FileId(0) 128..129
3111 FileId(0) 141..143
3112 FileId(0) 177..178
3113 FileId(0) 237..238
3114 FileId(0) 257..258
3115 "#]],
3116 );
3117 }
3118
3119 #[test]
3120 fn test_highlight_nested_match_expressions() {
3121 check(
3122 r#"
3123enum Outer { A(Inner), B }
3124enum Inner { X, Y(i32) }
3125
3126fn main() {
3127 let val = Outer::A(Inner::Y(42));
3128
3129 $0match val {
3130 Outer::A(inner) => match inner {
3131 Inner::X => println!("Inner::X"),
3132 Inner::Y(n) if n > 0 => println!("Inner::Y positive: {}", n),
3133 Inner::Y(_) => println!("Inner::Y non-positive"),
3134 },
3135 Outer::B => println!("Outer::B"),
3136 }
3137}
3138"#,
3139 expect![[r#"
3140 FileId(0) 108..113
3141 FileId(0) 185..205
3142 FileId(0) 243..279
3143 FileId(0) 308..341
3144 FileId(0) 374..394
3145 "#]],
3146 );
3147 }
3148
3149 #[test]
3150 fn raw_labels_and_lifetimes() {
3151 check(
3152 r#"
3153fn foo<'r#fn>(s: &'r#fn str) {
3154 let _a: &'r#fn str = s;
3155 let _b: &'r#fn str;
3156 'r#break$0: {
3157 break 'r#break;
3158 }
3159}
3160 "#,
3161 expect![[r#"
3162 'break Label FileId(0) 87..96 87..95
3163
3164 FileId(0) 113..121
3165 "#]],
3166 );
3167 check(
3168 r#"
3169fn foo<'r#fn$0>(s: &'r#fn str) {
3170 let _a: &'r#fn str = s;
3171 let _b: &'r#fn str;
3172 'r#break: {
3173 break 'r#break;
3174 }
3175}
3176 "#,
3177 expect![[r#"
3178 'fn LifetimeParam FileId(0) 7..12
3179
3180 FileId(0) 18..23
3181 FileId(0) 44..49
3182 FileId(0) 72..77
3183 "#]],
3184 );
3185 }
3186}