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