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