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