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