]> git.proxmox.com Git - rustc.git/blob - src/tools/rust-analyzer/crates/ide/src/references.rs
New upstream version 1.65.0+dfsg1
[rustc.git] / src / tools / rust-analyzer / crates / ide / src / references.rs
1 //! This module implements a reference search.
2 //! First, the element at the cursor position must be either an `ast::Name`
3 //! or `ast::NameRef`. If it's an `ast::NameRef`, at the classification step we
4 //! try to resolve the direct tree parent of this element, otherwise we
5 //! already have a definition and just need to get its HIR together with
6 //! some information that is needed for further steps of searching.
7 //! After that, we collect files that might contain references and look
8 //! for text occurrences of the identifier. If there's an `ast::NameRef`
9 //! at the index that the match starts at and its tree parent is
10 //! resolved to the search element definition, we get a reference.
11
12 use hir::{PathResolution, Semantics};
13 use ide_db::{
14 base_db::FileId,
15 defs::{Definition, NameClass, NameRefClass},
16 search::{ReferenceCategory, SearchScope, UsageSearchResult},
17 RootDatabase,
18 };
19 use stdx::hash::NoHashHashMap;
20 use syntax::{
21 algo::find_node_at_offset,
22 ast::{self, HasName},
23 match_ast, AstNode,
24 SyntaxKind::*,
25 SyntaxNode, TextRange, TextSize, T,
26 };
27
28 use crate::{FilePosition, NavigationTarget, TryToNav};
29
30 #[derive(Debug, Clone)]
31 pub struct ReferenceSearchResult {
32 pub declaration: Option<Declaration>,
33 pub references: NoHashHashMap<FileId, Vec<(TextRange, Option<ReferenceCategory>)>>,
34 }
35
36 #[derive(Debug, Clone)]
37 pub struct Declaration {
38 pub nav: NavigationTarget,
39 pub is_mut: bool,
40 }
41
42 // Feature: Find All References
43 //
44 // Shows all references of the item at the cursor location
45 //
46 // |===
47 // | Editor | Shortcut
48 //
49 // | VS Code | kbd:[Shift+Alt+F12]
50 // |===
51 //
52 // image::https://user-images.githubusercontent.com/48062697/113020670-b7c34f00-917a-11eb-8003-370ac5f2b3cb.gif[]
53 pub(crate) fn find_all_refs(
54 sema: &Semantics<'_, RootDatabase>,
55 position: FilePosition,
56 search_scope: Option<SearchScope>,
57 ) -> Option<Vec<ReferenceSearchResult>> {
58 let _p = profile::span("find_all_refs");
59 let syntax = sema.parse(position.file_id).syntax().clone();
60 let make_searcher = |literal_search: bool| {
61 move |def: Definition| {
62 let declaration = match def {
63 Definition::Module(module) => {
64 Some(NavigationTarget::from_module_to_decl(sema.db, module))
65 }
66 def => def.try_to_nav(sema.db),
67 }
68 .map(|nav| {
69 let decl_range = nav.focus_or_full_range();
70 Declaration {
71 is_mut: decl_mutability(&def, sema.parse(nav.file_id).syntax(), decl_range),
72 nav,
73 }
74 });
75 let mut usages =
76 def.usages(sema).set_scope(search_scope.clone()).include_self_refs().all();
77
78 if literal_search {
79 retain_adt_literal_usages(&mut usages, def, sema);
80 }
81
82 let references = usages
83 .into_iter()
84 .map(|(file_id, refs)| {
85 (
86 file_id,
87 refs.into_iter()
88 .map(|file_ref| (file_ref.range, file_ref.category))
89 .collect(),
90 )
91 })
92 .collect();
93
94 ReferenceSearchResult { declaration, references }
95 }
96 };
97
98 match name_for_constructor_search(&syntax, position) {
99 Some(name) => {
100 let def = match NameClass::classify(sema, &name)? {
101 NameClass::Definition(it) | NameClass::ConstReference(it) => it,
102 NameClass::PatFieldShorthand { local_def: _, field_ref } => {
103 Definition::Field(field_ref)
104 }
105 };
106 Some(vec![make_searcher(true)(def)])
107 }
108 None => {
109 let search = make_searcher(false);
110 Some(find_defs(sema, &syntax, position.offset)?.map(search).collect())
111 }
112 }
113 }
114
115 pub(crate) fn find_defs<'a>(
116 sema: &'a Semantics<'_, RootDatabase>,
117 syntax: &SyntaxNode,
118 offset: TextSize,
119 ) -> Option<impl Iterator<Item = Definition> + 'a> {
120 let token = syntax.token_at_offset(offset).find(|t| {
121 matches!(
122 t.kind(),
123 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self]
124 )
125 });
126 token.map(|token| {
127 sema.descend_into_macros_with_same_text(token)
128 .into_iter()
129 .filter_map(|it| ast::NameLike::cast(it.parent()?))
130 .filter_map(move |name_like| {
131 let def = match name_like {
132 ast::NameLike::NameRef(name_ref) => {
133 match NameRefClass::classify(sema, &name_ref)? {
134 NameRefClass::Definition(def) => def,
135 NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
136 Definition::Local(local_ref)
137 }
138 }
139 }
140 ast::NameLike::Name(name) => match NameClass::classify(sema, &name)? {
141 NameClass::Definition(it) | NameClass::ConstReference(it) => it,
142 NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
143 Definition::Local(local_def)
144 }
145 },
146 ast::NameLike::Lifetime(lifetime) => {
147 NameRefClass::classify_lifetime(sema, &lifetime)
148 .and_then(|class| match class {
149 NameRefClass::Definition(it) => Some(it),
150 _ => None,
151 })
152 .or_else(|| {
153 NameClass::classify_lifetime(sema, &lifetime)
154 .and_then(NameClass::defined)
155 })?
156 }
157 };
158 Some(def)
159 })
160 })
161 }
162
163 pub(crate) fn decl_mutability(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> bool {
164 match def {
165 Definition::Local(_) | Definition::Field(_) => {}
166 _ => return false,
167 };
168
169 match find_node_at_offset::<ast::LetStmt>(syntax, range.start()) {
170 Some(stmt) if stmt.initializer().is_some() => match stmt.pat() {
171 Some(ast::Pat::IdentPat(it)) => it.mut_token().is_some(),
172 _ => false,
173 },
174 _ => false,
175 }
176 }
177
178 /// Filter out all non-literal usages for adt-defs
179 fn retain_adt_literal_usages(
180 usages: &mut UsageSearchResult,
181 def: Definition,
182 sema: &Semantics<'_, RootDatabase>,
183 ) {
184 let refs = usages.references.values_mut();
185 match def {
186 Definition::Adt(hir::Adt::Enum(enum_)) => {
187 refs.for_each(|it| {
188 it.retain(|reference| {
189 reference
190 .name
191 .as_name_ref()
192 .map_or(false, |name_ref| is_enum_lit_name_ref(sema, enum_, name_ref))
193 })
194 });
195 usages.references.retain(|_, it| !it.is_empty());
196 }
197 Definition::Adt(_) | Definition::Variant(_) => {
198 refs.for_each(|it| {
199 it.retain(|reference| reference.name.as_name_ref().map_or(false, is_lit_name_ref))
200 });
201 usages.references.retain(|_, it| !it.is_empty());
202 }
203 _ => {}
204 }
205 }
206
207 /// Returns `Some` if the cursor is at a position for an item to search for all its constructor/literal usages
208 fn name_for_constructor_search(syntax: &SyntaxNode, position: FilePosition) -> Option<ast::Name> {
209 let token = syntax.token_at_offset(position.offset).right_biased()?;
210 let token_parent = token.parent()?;
211 let kind = token.kind();
212 if kind == T![;] {
213 ast::Struct::cast(token_parent)
214 .filter(|struct_| struct_.field_list().is_none())
215 .and_then(|struct_| struct_.name())
216 } else if kind == T!['{'] {
217 match_ast! {
218 match token_parent {
219 ast::RecordFieldList(rfl) => match_ast! {
220 match (rfl.syntax().parent()?) {
221 ast::Variant(it) => it.name(),
222 ast::Struct(it) => it.name(),
223 ast::Union(it) => it.name(),
224 _ => None,
225 }
226 },
227 ast::VariantList(vl) => ast::Enum::cast(vl.syntax().parent()?)?.name(),
228 _ => None,
229 }
230 }
231 } else if kind == T!['('] {
232 let tfl = ast::TupleFieldList::cast(token_parent)?;
233 match_ast! {
234 match (tfl.syntax().parent()?) {
235 ast::Variant(it) => it.name(),
236 ast::Struct(it) => it.name(),
237 _ => None,
238 }
239 }
240 } else {
241 None
242 }
243 }
244
245 fn is_enum_lit_name_ref(
246 sema: &Semantics<'_, RootDatabase>,
247 enum_: hir::Enum,
248 name_ref: &ast::NameRef,
249 ) -> bool {
250 let path_is_variant_of_enum = |path: ast::Path| {
251 matches!(
252 sema.resolve_path(&path),
253 Some(PathResolution::Def(hir::ModuleDef::Variant(variant)))
254 if variant.parent_enum(sema.db) == enum_
255 )
256 };
257 name_ref
258 .syntax()
259 .ancestors()
260 .find_map(|ancestor| {
261 match_ast! {
262 match ancestor {
263 ast::PathExpr(path_expr) => path_expr.path().map(path_is_variant_of_enum),
264 ast::RecordExpr(record_expr) => record_expr.path().map(path_is_variant_of_enum),
265 _ => None,
266 }
267 }
268 })
269 .unwrap_or(false)
270 }
271
272 fn path_ends_with(path: Option<ast::Path>, name_ref: &ast::NameRef) -> bool {
273 path.and_then(|path| path.segment())
274 .and_then(|segment| segment.name_ref())
275 .map_or(false, |segment| segment == *name_ref)
276 }
277
278 fn is_lit_name_ref(name_ref: &ast::NameRef) -> bool {
279 name_ref.syntax().ancestors().find_map(|ancestor| {
280 match_ast! {
281 match ancestor {
282 ast::PathExpr(path_expr) => Some(path_ends_with(path_expr.path(), name_ref)),
283 ast::RecordExpr(record_expr) => Some(path_ends_with(record_expr.path(), name_ref)),
284 _ => None,
285 }
286 }
287 }).unwrap_or(false)
288 }
289
290 #[cfg(test)]
291 mod tests {
292 use expect_test::{expect, Expect};
293 use ide_db::{base_db::FileId, search::ReferenceCategory};
294 use stdx::format_to;
295
296 use crate::{fixture, SearchScope};
297
298 #[test]
299 fn test_struct_literal_after_space() {
300 check(
301 r#"
302 struct Foo $0{
303 a: i32,
304 }
305 impl Foo {
306 fn f() -> i32 { 42 }
307 }
308 fn main() {
309 let f: Foo;
310 f = Foo {a: Foo::f()};
311 }
312 "#,
313 expect![[r#"
314 Foo Struct FileId(0) 0..26 7..10
315
316 FileId(0) 101..104
317 "#]],
318 );
319 }
320
321 #[test]
322 fn test_struct_literal_before_space() {
323 check(
324 r#"
325 struct Foo$0 {}
326 fn main() {
327 let f: Foo;
328 f = Foo {};
329 }
330 "#,
331 expect![[r#"
332 Foo Struct FileId(0) 0..13 7..10
333
334 FileId(0) 41..44
335 FileId(0) 54..57
336 "#]],
337 );
338 }
339
340 #[test]
341 fn test_struct_literal_with_generic_type() {
342 check(
343 r#"
344 struct Foo<T> $0{}
345 fn main() {
346 let f: Foo::<i32>;
347 f = Foo {};
348 }
349 "#,
350 expect![[r#"
351 Foo Struct FileId(0) 0..16 7..10
352
353 FileId(0) 64..67
354 "#]],
355 );
356 }
357
358 #[test]
359 fn test_struct_literal_for_tuple() {
360 check(
361 r#"
362 struct Foo$0(i32);
363
364 fn main() {
365 let f: Foo;
366 f = Foo(1);
367 }
368 "#,
369 expect![[r#"
370 Foo Struct FileId(0) 0..16 7..10
371
372 FileId(0) 54..57
373 "#]],
374 );
375 }
376
377 #[test]
378 fn test_struct_literal_for_union() {
379 check(
380 r#"
381 union Foo $0{
382 x: u32
383 }
384
385 fn main() {
386 let f: Foo;
387 f = Foo { x: 1 };
388 }
389 "#,
390 expect![[r#"
391 Foo Union FileId(0) 0..24 6..9
392
393 FileId(0) 62..65
394 "#]],
395 );
396 }
397
398 #[test]
399 fn test_enum_after_space() {
400 check(
401 r#"
402 enum Foo $0{
403 A,
404 B(),
405 C{},
406 }
407 fn main() {
408 let f: Foo;
409 f = Foo::A;
410 f = Foo::B();
411 f = Foo::C{};
412 }
413 "#,
414 expect![[r#"
415 Foo Enum FileId(0) 0..37 5..8
416
417 FileId(0) 74..77
418 FileId(0) 90..93
419 FileId(0) 108..111
420 "#]],
421 );
422 }
423
424 #[test]
425 fn test_variant_record_after_space() {
426 check(
427 r#"
428 enum Foo {
429 A $0{ n: i32 },
430 B,
431 }
432 fn main() {
433 let f: Foo;
434 f = Foo::B;
435 f = Foo::A { n: 92 };
436 }
437 "#,
438 expect![[r#"
439 A Variant FileId(0) 15..27 15..16
440
441 FileId(0) 95..96
442 "#]],
443 );
444 }
445 #[test]
446 fn test_variant_tuple_before_paren() {
447 check(
448 r#"
449 enum Foo {
450 A$0(i32),
451 B,
452 }
453 fn main() {
454 let f: Foo;
455 f = Foo::B;
456 f = Foo::A(92);
457 }
458 "#,
459 expect![[r#"
460 A Variant FileId(0) 15..21 15..16
461
462 FileId(0) 89..90
463 "#]],
464 );
465 }
466
467 #[test]
468 fn test_enum_before_space() {
469 check(
470 r#"
471 enum Foo$0 {
472 A,
473 B,
474 }
475 fn main() {
476 let f: Foo;
477 f = Foo::A;
478 }
479 "#,
480 expect![[r#"
481 Foo Enum FileId(0) 0..26 5..8
482
483 FileId(0) 50..53
484 FileId(0) 63..66
485 "#]],
486 );
487 }
488
489 #[test]
490 fn test_enum_with_generic_type() {
491 check(
492 r#"
493 enum Foo<T> $0{
494 A(T),
495 B,
496 }
497 fn main() {
498 let f: Foo<i8>;
499 f = Foo::A(1);
500 }
501 "#,
502 expect![[r#"
503 Foo Enum FileId(0) 0..32 5..8
504
505 FileId(0) 73..76
506 "#]],
507 );
508 }
509
510 #[test]
511 fn test_enum_for_tuple() {
512 check(
513 r#"
514 enum Foo$0{
515 A(i8),
516 B(i8),
517 }
518 fn main() {
519 let f: Foo;
520 f = Foo::A(1);
521 }
522 "#,
523 expect![[r#"
524 Foo Enum FileId(0) 0..33 5..8
525
526 FileId(0) 70..73
527 "#]],
528 );
529 }
530
531 #[test]
532 fn test_find_all_refs_for_local() {
533 check(
534 r#"
535 fn main() {
536 let mut i = 1;
537 let j = 1;
538 i = i$0 + j;
539
540 {
541 i = 0;
542 }
543
544 i = 5;
545 }"#,
546 expect![[r#"
547 i Local FileId(0) 20..25 24..25 Write
548
549 FileId(0) 50..51 Write
550 FileId(0) 54..55 Read
551 FileId(0) 76..77 Write
552 FileId(0) 94..95 Write
553 "#]],
554 );
555 }
556
557 #[test]
558 fn search_filters_by_range() {
559 check(
560 r#"
561 fn foo() {
562 let spam$0 = 92;
563 spam + spam
564 }
565 fn bar() {
566 let spam = 92;
567 spam + spam
568 }
569 "#,
570 expect![[r#"
571 spam Local FileId(0) 19..23 19..23
572
573 FileId(0) 34..38 Read
574 FileId(0) 41..45 Read
575 "#]],
576 );
577 }
578
579 #[test]
580 fn test_find_all_refs_for_param_inside() {
581 check(
582 r#"
583 fn foo(i : u32) -> u32 { i$0 }
584 "#,
585 expect![[r#"
586 i ValueParam FileId(0) 7..8 7..8
587
588 FileId(0) 25..26 Read
589 "#]],
590 );
591 }
592
593 #[test]
594 fn test_find_all_refs_for_fn_param() {
595 check(
596 r#"
597 fn foo(i$0 : u32) -> u32 { i }
598 "#,
599 expect![[r#"
600 i ValueParam FileId(0) 7..8 7..8
601
602 FileId(0) 25..26 Read
603 "#]],
604 );
605 }
606
607 #[test]
608 fn test_find_all_refs_field_name() {
609 check(
610 r#"
611 //- /lib.rs
612 struct Foo {
613 pub spam$0: u32,
614 }
615
616 fn main(s: Foo) {
617 let f = s.spam;
618 }
619 "#,
620 expect![[r#"
621 spam Field FileId(0) 17..30 21..25
622
623 FileId(0) 67..71 Read
624 "#]],
625 );
626 }
627
628 #[test]
629 fn test_find_all_refs_impl_item_name() {
630 check(
631 r#"
632 struct Foo;
633 impl Foo {
634 fn f$0(&self) { }
635 }
636 "#,
637 expect![[r#"
638 f Function FileId(0) 27..43 30..31
639
640 (no references)
641 "#]],
642 );
643 }
644
645 #[test]
646 fn test_find_all_refs_enum_var_name() {
647 check(
648 r#"
649 enum Foo {
650 A,
651 B$0,
652 C,
653 }
654 "#,
655 expect![[r#"
656 B Variant FileId(0) 22..23 22..23
657
658 (no references)
659 "#]],
660 );
661 }
662
663 #[test]
664 fn test_find_all_refs_enum_var_field() {
665 check(
666 r#"
667 enum Foo {
668 A,
669 B { field$0: u8 },
670 C,
671 }
672 "#,
673 expect![[r#"
674 field Field FileId(0) 26..35 26..31
675
676 (no references)
677 "#]],
678 );
679 }
680
681 #[test]
682 fn test_find_all_refs_two_modules() {
683 check(
684 r#"
685 //- /lib.rs
686 pub mod foo;
687 pub mod bar;
688
689 fn f() {
690 let i = foo::Foo { n: 5 };
691 }
692
693 //- /foo.rs
694 use crate::bar;
695
696 pub struct Foo {
697 pub n: u32,
698 }
699
700 fn f() {
701 let i = bar::Bar { n: 5 };
702 }
703
704 //- /bar.rs
705 use crate::foo;
706
707 pub struct Bar {
708 pub n: u32,
709 }
710
711 fn f() {
712 let i = foo::Foo$0 { n: 5 };
713 }
714 "#,
715 expect![[r#"
716 Foo Struct FileId(1) 17..51 28..31
717
718 FileId(0) 53..56
719 FileId(2) 79..82
720 "#]],
721 );
722 }
723
724 #[test]
725 fn test_find_all_refs_decl_module() {
726 check(
727 r#"
728 //- /lib.rs
729 mod foo$0;
730
731 use foo::Foo;
732
733 fn f() {
734 let i = Foo { n: 5 };
735 }
736
737 //- /foo.rs
738 pub struct Foo {
739 pub n: u32,
740 }
741 "#,
742 expect![[r#"
743 foo Module FileId(0) 0..8 4..7
744
745 FileId(0) 14..17
746 "#]],
747 );
748 }
749
750 #[test]
751 fn test_find_all_refs_decl_module_on_self() {
752 check(
753 r#"
754 //- /lib.rs
755 mod foo;
756
757 //- /foo.rs
758 use self$0;
759 "#,
760 expect![[r#"
761 foo Module FileId(0) 0..8 4..7
762
763 FileId(1) 4..8
764 "#]],
765 );
766 }
767
768 #[test]
769 fn test_find_all_refs_decl_module_on_self_crate_root() {
770 check(
771 r#"
772 //- /lib.rs
773 use self$0;
774 "#,
775 expect![[r#"
776 Module FileId(0) 0..10
777
778 FileId(0) 4..8
779 "#]],
780 );
781 }
782
783 #[test]
784 fn test_find_all_refs_super_mod_vis() {
785 check(
786 r#"
787 //- /lib.rs
788 mod foo;
789
790 //- /foo.rs
791 mod some;
792 use some::Foo;
793
794 fn f() {
795 let i = Foo { n: 5 };
796 }
797
798 //- /foo/some.rs
799 pub(super) struct Foo$0 {
800 pub n: u32,
801 }
802 "#,
803 expect![[r#"
804 Foo Struct FileId(2) 0..41 18..21
805
806 FileId(1) 20..23
807 FileId(1) 47..50
808 "#]],
809 );
810 }
811
812 #[test]
813 fn test_find_all_refs_with_scope() {
814 let code = r#"
815 //- /lib.rs
816 mod foo;
817 mod bar;
818
819 pub fn quux$0() {}
820
821 //- /foo.rs
822 fn f() { super::quux(); }
823
824 //- /bar.rs
825 fn f() { super::quux(); }
826 "#;
827
828 check_with_scope(
829 code,
830 None,
831 expect![[r#"
832 quux Function FileId(0) 19..35 26..30
833
834 FileId(1) 16..20
835 FileId(2) 16..20
836 "#]],
837 );
838
839 check_with_scope(
840 code,
841 Some(SearchScope::single_file(FileId(2))),
842 expect![[r#"
843 quux Function FileId(0) 19..35 26..30
844
845 FileId(2) 16..20
846 "#]],
847 );
848 }
849
850 #[test]
851 fn test_find_all_refs_macro_def() {
852 check(
853 r#"
854 #[macro_export]
855 macro_rules! m1$0 { () => (()) }
856
857 fn foo() {
858 m1();
859 m1();
860 }
861 "#,
862 expect![[r#"
863 m1 Macro FileId(0) 0..46 29..31
864
865 FileId(0) 63..65
866 FileId(0) 73..75
867 "#]],
868 );
869 }
870
871 #[test]
872 fn test_basic_highlight_read_write() {
873 check(
874 r#"
875 fn foo() {
876 let mut i$0 = 0;
877 i = i + 1;
878 }
879 "#,
880 expect![[r#"
881 i Local FileId(0) 19..24 23..24 Write
882
883 FileId(0) 34..35 Write
884 FileId(0) 38..39 Read
885 "#]],
886 );
887 }
888
889 #[test]
890 fn test_basic_highlight_field_read_write() {
891 check(
892 r#"
893 struct S {
894 f: u32,
895 }
896
897 fn foo() {
898 let mut s = S{f: 0};
899 s.f$0 = 0;
900 }
901 "#,
902 expect![[r#"
903 f Field FileId(0) 15..21 15..16
904
905 FileId(0) 55..56 Read
906 FileId(0) 68..69 Write
907 "#]],
908 );
909 }
910
911 #[test]
912 fn test_basic_highlight_decl_no_write() {
913 check(
914 r#"
915 fn foo() {
916 let i$0;
917 i = 1;
918 }
919 "#,
920 expect![[r#"
921 i Local FileId(0) 19..20 19..20
922
923 FileId(0) 26..27 Write
924 "#]],
925 );
926 }
927
928 #[test]
929 fn test_find_struct_function_refs_outside_module() {
930 check(
931 r#"
932 mod foo {
933 pub struct Foo;
934
935 impl Foo {
936 pub fn new$0() -> Foo { Foo }
937 }
938 }
939
940 fn main() {
941 let _f = foo::Foo::new();
942 }
943 "#,
944 expect![[r#"
945 new Function FileId(0) 54..81 61..64
946
947 FileId(0) 126..129
948 "#]],
949 );
950 }
951
952 #[test]
953 fn test_find_all_refs_nested_module() {
954 check(
955 r#"
956 //- /lib.rs
957 mod foo { mod bar; }
958
959 fn f$0() {}
960
961 //- /foo/bar.rs
962 use crate::f;
963
964 fn g() { f(); }
965 "#,
966 expect![[r#"
967 f Function FileId(0) 22..31 25..26
968
969 FileId(1) 11..12
970 FileId(1) 24..25
971 "#]],
972 );
973 }
974
975 #[test]
976 fn test_find_all_refs_struct_pat() {
977 check(
978 r#"
979 struct S {
980 field$0: u8,
981 }
982
983 fn f(s: S) {
984 match s {
985 S { field } => {}
986 }
987 }
988 "#,
989 expect![[r#"
990 field Field FileId(0) 15..24 15..20
991
992 FileId(0) 68..73 Read
993 "#]],
994 );
995 }
996
997 #[test]
998 fn test_find_all_refs_enum_var_pat() {
999 check(
1000 r#"
1001 enum En {
1002 Variant {
1003 field$0: u8,
1004 }
1005 }
1006
1007 fn f(e: En) {
1008 match e {
1009 En::Variant { field } => {}
1010 }
1011 }
1012 "#,
1013 expect![[r#"
1014 field Field FileId(0) 32..41 32..37
1015
1016 FileId(0) 102..107 Read
1017 "#]],
1018 );
1019 }
1020
1021 #[test]
1022 fn test_find_all_refs_enum_var_privacy() {
1023 check(
1024 r#"
1025 mod m {
1026 pub enum En {
1027 Variant {
1028 field$0: u8,
1029 }
1030 }
1031 }
1032
1033 fn f() -> m::En {
1034 m::En::Variant { field: 0 }
1035 }
1036 "#,
1037 expect![[r#"
1038 field Field FileId(0) 56..65 56..61
1039
1040 FileId(0) 125..130 Read
1041 "#]],
1042 );
1043 }
1044
1045 #[test]
1046 fn test_find_self_refs() {
1047 check(
1048 r#"
1049 struct Foo { bar: i32 }
1050
1051 impl Foo {
1052 fn foo(self) {
1053 let x = self$0.bar;
1054 if true {
1055 let _ = match () {
1056 () => self,
1057 };
1058 }
1059 }
1060 }
1061 "#,
1062 expect![[r#"
1063 self SelfParam FileId(0) 47..51 47..51
1064
1065 FileId(0) 71..75 Read
1066 FileId(0) 152..156 Read
1067 "#]],
1068 );
1069 }
1070
1071 #[test]
1072 fn test_find_self_refs_decl() {
1073 check(
1074 r#"
1075 struct Foo { bar: i32 }
1076
1077 impl Foo {
1078 fn foo(self$0) {
1079 self;
1080 }
1081 }
1082 "#,
1083 expect![[r#"
1084 self SelfParam FileId(0) 47..51 47..51
1085
1086 FileId(0) 63..67 Read
1087 "#]],
1088 );
1089 }
1090
1091 fn check(ra_fixture: &str, expect: Expect) {
1092 check_with_scope(ra_fixture, None, expect)
1093 }
1094
1095 fn check_with_scope(ra_fixture: &str, search_scope: Option<SearchScope>, expect: Expect) {
1096 let (analysis, pos) = fixture::position(ra_fixture);
1097 let refs = analysis.find_all_refs(pos, search_scope).unwrap().unwrap();
1098
1099 let mut actual = String::new();
1100 for refs in refs {
1101 actual += "\n\n";
1102
1103 if let Some(decl) = refs.declaration {
1104 format_to!(actual, "{}", decl.nav.debug_render());
1105 if decl.is_mut {
1106 format_to!(actual, " {:?}", ReferenceCategory::Write)
1107 }
1108 actual += "\n\n";
1109 }
1110
1111 for (file_id, references) in &refs.references {
1112 for (range, access) in references {
1113 format_to!(actual, "{:?} {:?}", file_id, range);
1114 if let Some(access) = access {
1115 format_to!(actual, " {:?}", access);
1116 }
1117 actual += "\n";
1118 }
1119 }
1120
1121 if refs.references.is_empty() {
1122 actual += "(no references)\n";
1123 }
1124 }
1125 expect.assert_eq(actual.trim_start())
1126 }
1127
1128 #[test]
1129 fn test_find_lifetimes_function() {
1130 check(
1131 r#"
1132 trait Foo<'a> {}
1133 impl<'a> Foo<'a> for &'a () {}
1134 fn foo<'a, 'b: 'a>(x: &'a$0 ()) -> &'a () where &'a (): Foo<'a> {
1135 fn bar<'a>(_: &'a ()) {}
1136 x
1137 }
1138 "#,
1139 expect![[r#"
1140 'a LifetimeParam FileId(0) 55..57 55..57
1141
1142 FileId(0) 63..65
1143 FileId(0) 71..73
1144 FileId(0) 82..84
1145 FileId(0) 95..97
1146 FileId(0) 106..108
1147 "#]],
1148 );
1149 }
1150
1151 #[test]
1152 fn test_find_lifetimes_type_alias() {
1153 check(
1154 r#"
1155 type Foo<'a, T> where T: 'a$0 = &'a T;
1156 "#,
1157 expect![[r#"
1158 'a LifetimeParam FileId(0) 9..11 9..11
1159
1160 FileId(0) 25..27
1161 FileId(0) 31..33
1162 "#]],
1163 );
1164 }
1165
1166 #[test]
1167 fn test_find_lifetimes_trait_impl() {
1168 check(
1169 r#"
1170 trait Foo<'a> {
1171 fn foo() -> &'a ();
1172 }
1173 impl<'a> Foo<'a> for &'a () {
1174 fn foo() -> &'a$0 () {
1175 unimplemented!()
1176 }
1177 }
1178 "#,
1179 expect![[r#"
1180 'a LifetimeParam FileId(0) 47..49 47..49
1181
1182 FileId(0) 55..57
1183 FileId(0) 64..66
1184 FileId(0) 89..91
1185 "#]],
1186 );
1187 }
1188
1189 #[test]
1190 fn test_map_range_to_original() {
1191 check(
1192 r#"
1193 macro_rules! foo {($i:ident) => {$i} }
1194 fn main() {
1195 let a$0 = "test";
1196 foo!(a);
1197 }
1198 "#,
1199 expect![[r#"
1200 a Local FileId(0) 59..60 59..60
1201
1202 FileId(0) 80..81 Read
1203 "#]],
1204 );
1205 }
1206
1207 #[test]
1208 fn test_map_range_to_original_ref() {
1209 check(
1210 r#"
1211 macro_rules! foo {($i:ident) => {$i} }
1212 fn main() {
1213 let a = "test";
1214 foo!(a$0);
1215 }
1216 "#,
1217 expect![[r#"
1218 a Local FileId(0) 59..60 59..60
1219
1220 FileId(0) 80..81 Read
1221 "#]],
1222 );
1223 }
1224
1225 #[test]
1226 fn test_find_labels() {
1227 check(
1228 r#"
1229 fn foo<'a>() -> &'a () {
1230 'a: loop {
1231 'b: loop {
1232 continue 'a$0;
1233 }
1234 break 'a;
1235 }
1236 }
1237 "#,
1238 expect![[r#"
1239 'a Label FileId(0) 29..32 29..31
1240
1241 FileId(0) 80..82
1242 FileId(0) 108..110
1243 "#]],
1244 );
1245 }
1246
1247 #[test]
1248 fn test_find_const_param() {
1249 check(
1250 r#"
1251 fn foo<const FOO$0: usize>() -> usize {
1252 FOO
1253 }
1254 "#,
1255 expect![[r#"
1256 FOO ConstParam FileId(0) 7..23 13..16
1257
1258 FileId(0) 42..45
1259 "#]],
1260 );
1261 }
1262
1263 #[test]
1264 fn test_trait() {
1265 check(
1266 r#"
1267 trait Foo$0 where Self: {}
1268
1269 impl Foo for () {}
1270 "#,
1271 expect![[r#"
1272 Foo Trait FileId(0) 0..24 6..9
1273
1274 FileId(0) 31..34
1275 "#]],
1276 );
1277 }
1278
1279 #[test]
1280 fn test_trait_self() {
1281 check(
1282 r#"
1283 trait Foo where Self$0 {
1284 fn f() -> Self;
1285 }
1286
1287 impl Foo for () {}
1288 "#,
1289 expect![[r#"
1290 Self TypeParam FileId(0) 6..9 6..9
1291
1292 FileId(0) 16..20
1293 FileId(0) 37..41
1294 "#]],
1295 );
1296 }
1297
1298 #[test]
1299 fn test_self_ty() {
1300 check(
1301 r#"
1302 struct $0Foo;
1303
1304 impl Foo where Self: {
1305 fn f() -> Self;
1306 }
1307 "#,
1308 expect![[r#"
1309 Foo Struct FileId(0) 0..11 7..10
1310
1311 FileId(0) 18..21
1312 FileId(0) 28..32
1313 FileId(0) 50..54
1314 "#]],
1315 );
1316 check(
1317 r#"
1318 struct Foo;
1319
1320 impl Foo where Self: {
1321 fn f() -> Self$0;
1322 }
1323 "#,
1324 expect![[r#"
1325 impl Impl FileId(0) 13..57 18..21
1326
1327 FileId(0) 18..21
1328 FileId(0) 28..32
1329 FileId(0) 50..54
1330 "#]],
1331 );
1332 }
1333 #[test]
1334 fn test_self_variant_with_payload() {
1335 check(
1336 r#"
1337 enum Foo { Bar() }
1338
1339 impl Foo {
1340 fn foo(self) {
1341 match self {
1342 Self::Bar$0() => (),
1343 }
1344 }
1345 }
1346
1347 "#,
1348 expect![[r#"
1349 Bar Variant FileId(0) 11..16 11..14
1350
1351 FileId(0) 89..92
1352 "#]],
1353 );
1354 }
1355
1356 #[test]
1357 fn test_attr_differs_from_fn_with_same_name() {
1358 check(
1359 r#"
1360 #[test]
1361 fn test$0() {
1362 test();
1363 }
1364 "#,
1365 expect![[r#"
1366 test Function FileId(0) 0..33 11..15
1367
1368 FileId(0) 24..28
1369 "#]],
1370 );
1371 }
1372
1373 #[test]
1374 fn test_const_in_pattern() {
1375 check(
1376 r#"
1377 const A$0: i32 = 42;
1378
1379 fn main() {
1380 match A {
1381 A => (),
1382 _ => (),
1383 }
1384 if let A = A {}
1385 }
1386 "#,
1387 expect![[r#"
1388 A Const FileId(0) 0..18 6..7
1389
1390 FileId(0) 42..43
1391 FileId(0) 54..55
1392 FileId(0) 97..98
1393 FileId(0) 101..102
1394 "#]],
1395 );
1396 }
1397
1398 #[test]
1399 fn test_primitives() {
1400 check(
1401 r#"
1402 fn foo(_: bool) -> bo$0ol { true }
1403 "#,
1404 expect![[r#"
1405 FileId(0) 10..14
1406 FileId(0) 19..23
1407 "#]],
1408 );
1409 }
1410
1411 #[test]
1412 fn test_transitive() {
1413 check(
1414 r#"
1415 //- /level3.rs new_source_root:local crate:level3
1416 pub struct Fo$0o;
1417 //- /level2.rs new_source_root:local crate:level2 deps:level3
1418 pub use level3::Foo;
1419 //- /level1.rs new_source_root:local crate:level1 deps:level2
1420 pub use level2::Foo;
1421 //- /level0.rs new_source_root:local crate:level0 deps:level1
1422 pub use level1::Foo;
1423 "#,
1424 expect![[r#"
1425 Foo Struct FileId(0) 0..15 11..14
1426
1427 FileId(1) 16..19
1428 FileId(2) 16..19
1429 FileId(3) 16..19
1430 "#]],
1431 );
1432 }
1433
1434 #[test]
1435 fn test_decl_macro_references() {
1436 check(
1437 r#"
1438 //- /lib.rs crate:lib
1439 #[macro_use]
1440 mod qux;
1441 mod bar;
1442
1443 pub use self::foo;
1444 //- /qux.rs
1445 #[macro_export]
1446 macro_rules! foo$0 {
1447 () => {struct Foo;};
1448 }
1449 //- /bar.rs
1450 foo!();
1451 //- /other.rs crate:other deps:lib new_source_root:local
1452 lib::foo!();
1453 "#,
1454 expect![[r#"
1455 foo Macro FileId(1) 0..61 29..32
1456
1457 FileId(0) 46..49
1458 FileId(2) 0..3
1459 FileId(3) 5..8
1460 "#]],
1461 );
1462 }
1463
1464 #[test]
1465 fn macro_doesnt_reference_attribute_on_call() {
1466 check(
1467 r#"
1468 macro_rules! m {
1469 () => {};
1470 }
1471
1472 #[proc_macro_test::attr_noop]
1473 m$0!();
1474
1475 "#,
1476 expect![[r#"
1477 m Macro FileId(0) 0..32 13..14
1478
1479 FileId(0) 64..65
1480 "#]],
1481 );
1482 }
1483
1484 #[test]
1485 fn multi_def() {
1486 check(
1487 r#"
1488 macro_rules! m {
1489 ($name:ident) => {
1490 mod module {
1491 pub fn $name() {}
1492 }
1493
1494 pub fn $name() {}
1495 }
1496 }
1497
1498 m!(func$0);
1499
1500 fn f() {
1501 func();
1502 module::func();
1503 }
1504 "#,
1505 expect![[r#"
1506 func Function FileId(0) 137..146 140..144
1507
1508 FileId(0) 161..165
1509
1510
1511 func Function FileId(0) 137..146 140..144
1512
1513 FileId(0) 181..185
1514 "#]],
1515 )
1516 }
1517
1518 #[test]
1519 fn attr_expanded() {
1520 check(
1521 r#"
1522 //- proc_macros: identity
1523 #[proc_macros::identity]
1524 fn func$0() {
1525 func();
1526 }
1527 "#,
1528 expect![[r#"
1529 func Function FileId(0) 25..50 28..32
1530
1531 FileId(0) 41..45
1532 "#]],
1533 )
1534 }
1535
1536 #[test]
1537 fn attr_assoc_item() {
1538 check(
1539 r#"
1540 //- proc_macros: identity
1541
1542 trait Trait {
1543 #[proc_macros::identity]
1544 fn func() {
1545 Self::func$0();
1546 }
1547 }
1548 "#,
1549 expect![[r#"
1550 func Function FileId(0) 48..87 51..55
1551
1552 FileId(0) 74..78
1553 "#]],
1554 )
1555 }
1556
1557 // FIXME: import is classified as function
1558 #[test]
1559 fn attr() {
1560 check(
1561 r#"
1562 //- proc_macros: identity
1563 use proc_macros::identity;
1564
1565 #[proc_macros::$0identity]
1566 fn func() {}
1567 "#,
1568 expect![[r#"
1569 identity Attribute FileId(1) 1..107 32..40
1570
1571 FileId(0) 43..51
1572 "#]],
1573 );
1574 check(
1575 r#"
1576 #![crate_type="proc-macro"]
1577 #[proc_macro_attribute]
1578 fn func$0() {}
1579 "#,
1580 expect![[r#"
1581 func Attribute FileId(0) 28..64 55..59
1582
1583 (no references)
1584 "#]],
1585 );
1586 }
1587
1588 // FIXME: import is classified as function
1589 #[test]
1590 fn proc_macro() {
1591 check(
1592 r#"
1593 //- proc_macros: mirror
1594 use proc_macros::mirror;
1595
1596 mirror$0! {}
1597 "#,
1598 expect![[r#"
1599 mirror Macro FileId(1) 1..77 22..28
1600
1601 FileId(0) 26..32
1602 "#]],
1603 )
1604 }
1605
1606 #[test]
1607 fn derive() {
1608 check(
1609 r#"
1610 //- proc_macros: derive_identity
1611 //- minicore: derive
1612 use proc_macros::DeriveIdentity;
1613
1614 #[derive(proc_macros::DeriveIdentity$0)]
1615 struct Foo;
1616 "#,
1617 expect![[r#"
1618 derive_identity Derive FileId(2) 1..107 45..60
1619
1620 FileId(0) 17..31
1621 FileId(0) 56..70
1622 "#]],
1623 );
1624 check(
1625 r#"
1626 #![crate_type="proc-macro"]
1627 #[proc_macro_derive(Derive, attributes(x))]
1628 pub fn deri$0ve(_stream: TokenStream) -> TokenStream {}
1629 "#,
1630 expect![[r#"
1631 derive Derive FileId(0) 28..125 79..85
1632
1633 (no references)
1634 "#]],
1635 );
1636 }
1637 }