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