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