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