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