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                _ CrateRoot 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) 17..25 import
2077                FileId(0) 43..51
2078            "#]],
2079        );
2080        check(
2081            r#"
2082#![crate_type="proc-macro"]
2083#[proc_macro_attribute]
2084fn func$0() {}
2085"#,
2086            expect![[r#"
2087                func Attribute FileId(0) 28..64 55..59
2088
2089                (no references)
2090            "#]],
2091        );
2092    }
2093
2094    // FIXME: import is classified as function
2095    #[test]
2096    fn proc_macro() {
2097        check(
2098            r#"
2099//- proc_macros: mirror
2100use proc_macros::mirror;
2101
2102mirror$0! {}
2103"#,
2104            expect![[r#"
2105                mirror ProcMacro FileId(1) 1..77 22..28
2106
2107                FileId(0) 17..23 import
2108                FileId(0) 26..32
2109            "#]],
2110        )
2111    }
2112
2113    #[test]
2114    fn derive() {
2115        check(
2116            r#"
2117//- proc_macros: derive_identity
2118//- minicore: derive
2119use proc_macros::DeriveIdentity;
2120
2121#[derive(proc_macros::DeriveIdentity$0)]
2122struct Foo;
2123"#,
2124            expect![[r#"
2125                derive_identity Derive FileId(2) 1..107 45..60
2126
2127                FileId(0) 17..31 import
2128                FileId(0) 56..70
2129            "#]],
2130        );
2131        check(
2132            r#"
2133#![crate_type="proc-macro"]
2134#[proc_macro_derive(Derive, attributes(x))]
2135pub fn deri$0ve(_stream: TokenStream) -> TokenStream {}
2136"#,
2137            expect![[r#"
2138                derive Derive FileId(0) 28..125 79..85
2139
2140                (no references)
2141            "#]],
2142        );
2143    }
2144
2145    #[test]
2146    fn assoc_items_trait_def() {
2147        check(
2148            r#"
2149trait Trait {
2150    const CONST$0: usize;
2151}
2152
2153impl Trait for () {
2154    const CONST: usize = 0;
2155}
2156
2157impl Trait for ((),) {
2158    const CONST: usize = 0;
2159}
2160
2161fn f<T: Trait>() {
2162    let _ = <()>::CONST;
2163
2164    let _ = T::CONST;
2165}
2166"#,
2167            expect![[r#"
2168                CONST Const FileId(0) 18..37 24..29 Trait
2169
2170                FileId(0) 71..76
2171                FileId(0) 125..130
2172                FileId(0) 183..188
2173                FileId(0) 206..211
2174            "#]],
2175        );
2176        check(
2177            r#"
2178trait Trait {
2179    type TypeAlias$0;
2180}
2181
2182impl Trait for () {
2183    type TypeAlias = ();
2184}
2185
2186impl Trait for ((),) {
2187    type TypeAlias = ();
2188}
2189
2190fn f<T: Trait>() {
2191    let _: <() as Trait>::TypeAlias;
2192
2193    let _: T::TypeAlias;
2194}
2195"#,
2196            expect![[r#"
2197                TypeAlias TypeAlias FileId(0) 18..33 23..32 Trait
2198
2199                FileId(0) 66..75
2200                FileId(0) 117..126
2201                FileId(0) 181..190
2202                FileId(0) 207..216
2203            "#]],
2204        );
2205        check(
2206            r#"
2207trait Trait {
2208    fn function$0() {}
2209}
2210
2211impl Trait for () {
2212    fn function() {}
2213}
2214
2215impl Trait for ((),) {
2216    fn function() {}
2217}
2218
2219fn f<T: Trait>() {
2220    let _ = <()>::function;
2221
2222    let _ = T::function;
2223}
2224"#,
2225            expect![[r#"
2226                function Function FileId(0) 18..34 21..29 Trait
2227
2228                FileId(0) 65..73
2229                FileId(0) 112..120
2230                FileId(0) 166..174
2231                FileId(0) 192..200
2232            "#]],
2233        );
2234    }
2235
2236    #[test]
2237    fn assoc_items_trait_impl_def() {
2238        check(
2239            r#"
2240trait Trait {
2241    const CONST: usize;
2242}
2243
2244impl Trait for () {
2245    const CONST$0: usize = 0;
2246}
2247
2248impl Trait for ((),) {
2249    const CONST: usize = 0;
2250}
2251
2252fn f<T: Trait>() {
2253    let _ = <()>::CONST;
2254
2255    let _ = T::CONST;
2256}
2257"#,
2258            expect![[r#"
2259                CONST Const FileId(0) 65..88 71..76
2260
2261                FileId(0) 183..188
2262            "#]],
2263        );
2264        check(
2265            r#"
2266trait Trait {
2267    type TypeAlias;
2268}
2269
2270impl Trait for () {
2271    type TypeAlias$0 = ();
2272}
2273
2274impl Trait for ((),) {
2275    type TypeAlias = ();
2276}
2277
2278fn f<T: Trait>() {
2279    let _: <() as Trait>::TypeAlias;
2280
2281    let _: T::TypeAlias;
2282}
2283"#,
2284            expect![[r#"
2285                TypeAlias TypeAlias FileId(0) 61..81 66..75
2286
2287                FileId(0) 23..32
2288                FileId(0) 117..126
2289                FileId(0) 181..190
2290                FileId(0) 207..216
2291            "#]],
2292        );
2293        check(
2294            r#"
2295trait Trait {
2296    fn function() {}
2297}
2298
2299impl Trait for () {
2300    fn function$0() {}
2301}
2302
2303impl Trait for ((),) {
2304    fn function() {}
2305}
2306
2307fn f<T: Trait>() {
2308    let _ = <()>::function;
2309
2310    let _ = T::function;
2311}
2312"#,
2313            expect![[r#"
2314                function Function FileId(0) 62..78 65..73
2315
2316                FileId(0) 166..174
2317            "#]],
2318        );
2319    }
2320
2321    #[test]
2322    fn assoc_items_ref() {
2323        check(
2324            r#"
2325trait Trait {
2326    const CONST: usize;
2327}
2328
2329impl Trait for () {
2330    const CONST: usize = 0;
2331}
2332
2333impl Trait for ((),) {
2334    const CONST: usize = 0;
2335}
2336
2337fn f<T: Trait>() {
2338    let _ = <()>::CONST$0;
2339
2340    let _ = T::CONST;
2341}
2342"#,
2343            expect![[r#"
2344                CONST Const FileId(0) 65..88 71..76
2345
2346                FileId(0) 183..188
2347            "#]],
2348        );
2349        check(
2350            r#"
2351trait Trait {
2352    type TypeAlias;
2353}
2354
2355impl Trait for () {
2356    type TypeAlias = ();
2357}
2358
2359impl Trait for ((),) {
2360    type TypeAlias = ();
2361}
2362
2363fn f<T: Trait>() {
2364    let _: <() as Trait>::TypeAlias$0;
2365
2366    let _: T::TypeAlias;
2367}
2368"#,
2369            expect![[r#"
2370                TypeAlias TypeAlias FileId(0) 18..33 23..32 Trait
2371
2372                FileId(0) 66..75
2373                FileId(0) 117..126
2374                FileId(0) 181..190
2375                FileId(0) 207..216
2376            "#]],
2377        );
2378        check(
2379            r#"
2380trait Trait {
2381    fn function() {}
2382}
2383
2384impl Trait for () {
2385    fn function() {}
2386}
2387
2388impl Trait for ((),) {
2389    fn function() {}
2390}
2391
2392fn f<T: Trait>() {
2393    let _ = <()>::function$0;
2394
2395    let _ = T::function;
2396}
2397"#,
2398            expect![[r#"
2399                function Function FileId(0) 62..78 65..73
2400
2401                FileId(0) 166..174
2402            "#]],
2403        );
2404    }
2405
2406    #[test]
2407    fn name_clashes() {
2408        check(
2409            r#"
2410trait Foo {
2411    fn method$0(&self) -> u8;
2412}
2413
2414struct Bar {
2415    method: u8,
2416}
2417
2418impl Foo for Bar {
2419    fn method(&self) -> u8 {
2420        self.method
2421    }
2422}
2423fn method() {}
2424"#,
2425            expect![[r#"
2426                method Function FileId(0) 16..39 19..25 Foo
2427
2428                FileId(0) 101..107
2429            "#]],
2430        );
2431        check(
2432            r#"
2433trait Foo {
2434    fn method(&self) -> u8;
2435}
2436
2437struct Bar {
2438    method$0: u8,
2439}
2440
2441impl Foo for Bar {
2442    fn method(&self) -> u8 {
2443        self.method
2444    }
2445}
2446fn method() {}
2447"#,
2448            expect![[r#"
2449                method Field FileId(0) 60..70 60..66
2450
2451                FileId(0) 136..142 read
2452            "#]],
2453        );
2454        check(
2455            r#"
2456trait Foo {
2457    fn method(&self) -> u8;
2458}
2459
2460struct Bar {
2461    method: u8,
2462}
2463
2464impl Foo for Bar {
2465    fn method$0(&self) -> u8 {
2466        self.method
2467    }
2468}
2469fn method() {}
2470"#,
2471            expect![[r#"
2472                method Function FileId(0) 98..148 101..107
2473
2474                (no references)
2475            "#]],
2476        );
2477        check(
2478            r#"
2479trait Foo {
2480    fn method(&self) -> u8;
2481}
2482
2483struct Bar {
2484    method: u8,
2485}
2486
2487impl Foo for Bar {
2488    fn method(&self) -> u8 {
2489        self.method$0
2490    }
2491}
2492fn method() {}
2493"#,
2494            expect![[r#"
2495                method Field FileId(0) 60..70 60..66
2496
2497                FileId(0) 136..142 read
2498            "#]],
2499        );
2500        check(
2501            r#"
2502trait Foo {
2503    fn method(&self) -> u8;
2504}
2505
2506struct Bar {
2507    method: u8,
2508}
2509
2510impl Foo for Bar {
2511    fn method(&self) -> u8 {
2512        self.method
2513    }
2514}
2515fn method$0() {}
2516"#,
2517            expect![[r#"
2518                method Function FileId(0) 151..165 154..160
2519
2520                (no references)
2521            "#]],
2522        );
2523    }
2524
2525    #[test]
2526    fn raw_identifier() {
2527        check(
2528            r#"
2529fn r#fn$0() {}
2530fn main() { r#fn(); }
2531"#,
2532            expect![[r#"
2533                fn Function FileId(0) 0..12 3..7
2534
2535                FileId(0) 25..29
2536            "#]],
2537        );
2538    }
2539
2540    #[test]
2541    fn implicit_format_args() {
2542        check(
2543            r#"
2544//- minicore: fmt
2545fn test() {
2546    let a = "foo";
2547    format_args!("hello {a} {a$0} {}", a);
2548                      // ^
2549                          // ^
2550                                   // ^
2551}
2552"#,
2553            expect![[r#"
2554                a Local FileId(0) 20..21 20..21
2555
2556                FileId(0) 56..57 read
2557                FileId(0) 60..61 read
2558                FileId(0) 68..69 read
2559            "#]],
2560        );
2561    }
2562
2563    #[test]
2564    fn goto_ref_fn_kw() {
2565        check(
2566            r#"
2567macro_rules! N {
2568    ($i:ident, $x:expr, $blk:expr) => {
2569        for $i in 0..$x {
2570            $blk
2571        }
2572    };
2573}
2574
2575fn main() {
2576    $0fn f() {
2577        N!(i, 5, {
2578            println!("{}", i);
2579            return;
2580        });
2581
2582        for i in 1..5 {
2583            return;
2584        }
2585
2586       (|| {
2587            return;
2588        })();
2589    }
2590}
2591"#,
2592            expect![[r#"
2593                FileId(0) 136..138
2594                FileId(0) 207..213
2595                FileId(0) 264..270
2596            "#]],
2597        )
2598    }
2599
2600    #[test]
2601    fn goto_ref_exit_points() {
2602        check(
2603            r#"
2604fn$0 foo() -> u32 {
2605    if true {
2606        return 0;
2607    }
2608
2609    0?;
2610    0xDEAD_BEEF
2611}
2612"#,
2613            expect![[r#"
2614                FileId(0) 0..2
2615                FileId(0) 40..46
2616                FileId(0) 62..63
2617                FileId(0) 69..80
2618            "#]],
2619        );
2620    }
2621
2622    #[test]
2623    fn test_ref_yield_points() {
2624        check(
2625            r#"
2626pub async$0 fn foo() {
2627    let x = foo()
2628        .await
2629        .await;
2630    || { 0.await };
2631    (async { 0.await }).await
2632}
2633"#,
2634            expect![[r#"
2635                FileId(0) 4..9
2636                FileId(0) 48..53
2637                FileId(0) 63..68
2638                FileId(0) 114..119
2639            "#]],
2640        );
2641    }
2642
2643    #[test]
2644    fn goto_ref_for_kw() {
2645        check(
2646            r#"
2647fn main() {
2648    $0for i in 1..5 {
2649        break;
2650        continue;
2651    }
2652}
2653"#,
2654            expect![[r#"
2655                FileId(0) 16..19
2656                FileId(0) 40..45
2657                FileId(0) 55..63
2658            "#]],
2659        )
2660    }
2661
2662    #[test]
2663    fn goto_ref_on_break_kw() {
2664        check(
2665            r#"
2666fn main() {
2667    for i in 1..5 {
2668        $0break;
2669        continue;
2670    }
2671}
2672"#,
2673            expect![[r#"
2674                FileId(0) 16..19
2675                FileId(0) 40..45
2676            "#]],
2677        )
2678    }
2679
2680    #[test]
2681    fn goto_ref_on_break_kw_for_block() {
2682        check(
2683            r#"
2684fn main() {
2685    'a:{
2686        $0break 'a;
2687    }
2688}
2689"#,
2690            expect![[r#"
2691                FileId(0) 16..19
2692                FileId(0) 29..37
2693            "#]],
2694        )
2695    }
2696
2697    #[test]
2698    fn goto_ref_on_break_with_label() {
2699        check(
2700            r#"
2701fn foo() {
2702    'outer: loop {
2703         break;
2704         'inner: loop {
2705            'innermost: loop {
2706            }
2707            $0break 'outer;
2708            break;
2709        }
2710        break;
2711    }
2712}
2713"#,
2714            expect![[r#"
2715                FileId(0) 15..27
2716                FileId(0) 39..44
2717                FileId(0) 127..139
2718                FileId(0) 178..183
2719            "#]],
2720        );
2721    }
2722
2723    #[test]
2724    fn goto_ref_on_return_in_try() {
2725        check(
2726            r#"
2727fn main() {
2728    fn f() {
2729        try {
2730            $0return;
2731        }
2732
2733        return;
2734    }
2735    return;
2736}
2737"#,
2738            expect![[r#"
2739                FileId(0) 16..18
2740                FileId(0) 51..57
2741                FileId(0) 78..84
2742            "#]],
2743        )
2744    }
2745
2746    #[test]
2747    fn goto_ref_on_break_in_try() {
2748        check(
2749            r#"
2750fn main() {
2751    for i in 1..100 {
2752        let x: Result<(), ()> = try {
2753            $0break;
2754        };
2755    }
2756}
2757"#,
2758            expect![[r#"
2759                FileId(0) 16..19
2760                FileId(0) 84..89
2761            "#]],
2762        )
2763    }
2764
2765    #[test]
2766    fn goto_ref_on_return_in_async_block() {
2767        check(
2768            r#"
2769fn main() {
2770    $0async {
2771        return;
2772    }
2773}
2774"#,
2775            expect![[r#"
2776                FileId(0) 16..21
2777                FileId(0) 32..38
2778            "#]],
2779        )
2780    }
2781
2782    #[test]
2783    fn goto_ref_on_return_in_macro_call() {
2784        check(
2785            r#"
2786//- minicore:include
2787//- /lib.rs
2788macro_rules! M {
2789    ($blk:expr) => {
2790        fn f() {
2791            $blk
2792        }
2793
2794        $blk
2795    };
2796}
2797
2798fn main() {
2799    M!({
2800        return$0;
2801    });
2802
2803    f();
2804    include!("a.rs")
2805}
2806
2807//- /a.rs
2808{
2809    return;
2810}
2811"#,
2812            expect![[r#"
2813                FileId(0) 46..48
2814                FileId(0) 106..108
2815                FileId(0) 122..149
2816                FileId(0) 135..141
2817                FileId(0) 165..181
2818                FileId(1) 6..12
2819            "#]],
2820        )
2821    }
2822
2823    // The following are tests for short_associated_function_fast_search() in crates/ide-db/src/search.rs, because find all references
2824    // use `FindUsages` and I found it easy to test it here.
2825
2826    #[test]
2827    fn goto_ref_on_short_associated_function() {
2828        cov_mark::check!(short_associated_function_fast_search);
2829        check(
2830            r#"
2831struct Foo;
2832impl Foo {
2833    fn new$0() {}
2834}
2835
2836fn bar() {
2837    Foo::new();
2838}
2839fn baz() {
2840    Foo::new;
2841}
2842        "#,
2843            expect![[r#"
2844                new Function FileId(0) 27..38 30..33
2845
2846                FileId(0) 62..65
2847                FileId(0) 91..94
2848            "#]],
2849        );
2850    }
2851
2852    #[test]
2853    fn goto_ref_on_short_associated_function_with_aliases() {
2854        cov_mark::check!(short_associated_function_fast_search);
2855        cov_mark::check!(container_use_rename);
2856        cov_mark::check!(container_type_alias);
2857        check(
2858            r#"
2859//- /lib.rs
2860mod a;
2861mod b;
2862
2863struct Foo;
2864impl Foo {
2865    fn new$0() {}
2866}
2867
2868fn bar() {
2869    b::c::Baz::new();
2870}
2871
2872//- /a.rs
2873use crate::Foo as Bar;
2874
2875fn baz() { Bar::new(); }
2876fn quux() { <super::b::Other as super::b::Trait>::Assoc::new(); }
2877
2878//- /b.rs
2879pub(crate) mod c;
2880
2881pub(crate) struct Other;
2882pub(crate) trait Trait {
2883    type Assoc;
2884}
2885impl Trait for Other {
2886    type Assoc = super::Foo;
2887}
2888
2889//- /b/c.rs
2890type Itself<T> = T;
2891pub(in super::super) type Baz = Itself<crate::Foo>;
2892        "#,
2893            expect![[r#"
2894                new Function FileId(0) 42..53 45..48
2895
2896                FileId(0) 83..86
2897                FileId(1) 40..43
2898                FileId(1) 106..109
2899            "#]],
2900        );
2901    }
2902
2903    #[test]
2904    fn goto_ref_on_short_associated_function_self_works() {
2905        cov_mark::check!(short_associated_function_fast_search);
2906        cov_mark::check!(self_type_alias);
2907        check(
2908            r#"
2909//- /lib.rs
2910mod module;
2911
2912struct Foo;
2913impl Foo {
2914    fn new$0() {}
2915    fn bar() { Self::new(); }
2916}
2917trait Trait {
2918    type Assoc;
2919    fn baz();
2920}
2921impl Trait for Foo {
2922    type Assoc = Self;
2923    fn baz() { Self::new(); }
2924}
2925
2926//- /module.rs
2927impl super::Foo {
2928    fn quux() { Self::new(); }
2929}
2930fn foo() { <super::Foo as super::Trait>::Assoc::new(); }
2931                "#,
2932            expect![[r#"
2933                new Function FileId(0) 40..51 43..46
2934
2935                FileId(0) 73..76
2936                FileId(0) 195..198
2937                FileId(1) 40..43
2938                FileId(1) 99..102
2939            "#]],
2940        );
2941    }
2942
2943    #[test]
2944    fn goto_ref_on_short_associated_function_overlapping_self_ranges() {
2945        check(
2946            r#"
2947struct Foo;
2948impl Foo {
2949    fn new$0() {}
2950    fn bar() {
2951        Self::new();
2952        impl Foo {
2953            fn baz() { Self::new(); }
2954        }
2955    }
2956}
2957            "#,
2958            expect![[r#"
2959                new Function FileId(0) 27..38 30..33
2960
2961                FileId(0) 68..71
2962                FileId(0) 123..126
2963            "#]],
2964        );
2965    }
2966
2967    #[test]
2968    fn goto_ref_on_short_associated_function_no_direct_self_but_path_contains_self() {
2969        cov_mark::check!(short_associated_function_fast_search);
2970        check(
2971            r#"
2972struct Foo;
2973impl Foo {
2974    fn new$0() {}
2975}
2976trait Trait {
2977    type Assoc;
2978}
2979impl<A, B> Trait for (A, B) {
2980    type Assoc = B;
2981}
2982impl Foo {
2983    fn bar() {
2984        <((), Foo) as Trait>::Assoc::new();
2985        <((), Self) as Trait>::Assoc::new();
2986    }
2987}
2988            "#,
2989            expect![[r#"
2990                new Function FileId(0) 27..38 30..33
2991
2992                FileId(0) 188..191
2993                FileId(0) 233..236
2994            "#]],
2995        );
2996    }
2997
2998    // Checks that we can circumvent our fast path logic using complicated type level functions.
2999    // This mainly exists as a documentation. I don't believe it is fixable.
3000    // Usages search is not 100% accurate anyway; we miss macros.
3001    #[test]
3002    fn goto_ref_on_short_associated_function_complicated_type_magic_can_confuse_our_logic() {
3003        cov_mark::check!(short_associated_function_fast_search);
3004        cov_mark::check!(same_name_different_def_type_alias);
3005        check(
3006            r#"
3007struct Foo;
3008impl Foo {
3009    fn new$0() {}
3010}
3011
3012struct ChoiceA;
3013struct ChoiceB;
3014trait Choice {
3015    type Choose<A, B>;
3016}
3017impl Choice for ChoiceA {
3018    type Choose<A, B> = A;
3019}
3020impl Choice for ChoiceB {
3021    type Choose<A, B> = B;
3022}
3023type Choose<A, C> = <C as Choice>::Choose<A, Foo>;
3024
3025fn bar() {
3026    Choose::<(), ChoiceB>::new();
3027}
3028                "#,
3029            expect![[r#"
3030                new Function FileId(0) 27..38 30..33
3031
3032                (no references)
3033            "#]],
3034        );
3035    }
3036
3037    #[test]
3038    fn goto_ref_on_short_associated_function_same_path_mention_alias_and_self() {
3039        cov_mark::check!(short_associated_function_fast_search);
3040        check(
3041            r#"
3042struct Foo;
3043impl Foo {
3044    fn new$0() {}
3045}
3046
3047type IgnoreFirst<A, B> = B;
3048
3049impl Foo {
3050    fn bar() {
3051        <IgnoreFirst<Foo, Self>>::new();
3052    }
3053}
3054                "#,
3055            expect![[r#"
3056                new Function FileId(0) 27..38 30..33
3057
3058                FileId(0) 131..134
3059            "#]],
3060        );
3061    }
3062
3063    #[test]
3064    fn goto_ref_on_included_file() {
3065        check(
3066            r#"
3067//- minicore:include
3068//- /lib.rs
3069include!("foo.rs");
3070fn howdy() {
3071    let _ = FOO;
3072}
3073//- /foo.rs
3074const FOO$0: i32 = 0;
3075"#,
3076            expect![[r#"
3077                FOO Const FileId(1) 0..19 6..9
3078
3079                FileId(0) 45..48
3080            "#]],
3081        );
3082    }
3083
3084    #[test]
3085    fn test_highlight_if_let_match_combined() {
3086        check(
3087            r#"
3088enum MyEnum { A(i32), B(String), C }
3089
3090fn main() {
3091    let val = MyEnum::A(42);
3092
3093    let x = $0if let MyEnum::A(x) = val {
3094        1
3095    } else if let MyEnum::B(s) = val {
3096        2
3097    } else {
3098        match val {
3099            MyEnum::C => 3,
3100            _ => 4,
3101        }
3102    };
3103}
3104"#,
3105            expect![[r#"
3106                FileId(0) 92..94
3107                FileId(0) 128..129
3108                FileId(0) 141..143
3109                FileId(0) 177..178
3110                FileId(0) 237..238
3111                FileId(0) 257..258
3112            "#]],
3113        );
3114    }
3115
3116    #[test]
3117    fn test_highlight_nested_match_expressions() {
3118        check(
3119            r#"
3120enum Outer { A(Inner), B }
3121enum Inner { X, Y(i32) }
3122
3123fn main() {
3124    let val = Outer::A(Inner::Y(42));
3125
3126    $0match val {
3127        Outer::A(inner) => match inner {
3128            Inner::X => println!("Inner::X"),
3129            Inner::Y(n) if n > 0 => println!("Inner::Y positive: {}", n),
3130            Inner::Y(_) => println!("Inner::Y non-positive"),
3131        },
3132        Outer::B => println!("Outer::B"),
3133    }
3134}
3135"#,
3136            expect![[r#"
3137                FileId(0) 108..113
3138                FileId(0) 185..205
3139                FileId(0) 243..279
3140                FileId(0) 308..341
3141                FileId(0) 374..394
3142            "#]],
3143        );
3144    }
3145
3146    #[test]
3147    fn raw_labels_and_lifetimes() {
3148        check(
3149            r#"
3150fn foo<'r#fn>(s: &'r#fn str) {
3151    let _a: &'r#fn str = s;
3152    let _b: &'r#fn str;
3153    'r#break$0: {
3154        break 'r#break;
3155    }
3156}
3157        "#,
3158            expect![[r#"
3159                'break Label FileId(0) 87..96 87..95
3160
3161                FileId(0) 113..121
3162            "#]],
3163        );
3164        check(
3165            r#"
3166fn foo<'r#fn$0>(s: &'r#fn str) {
3167    let _a: &'r#fn str = s;
3168    let _b: &'r#fn str;
3169    'r#break: {
3170        break 'r#break;
3171    }
3172}
3173        "#,
3174            expect![[r#"
3175                'fn LifetimeParam FileId(0) 7..12
3176
3177                FileId(0) 18..23
3178                FileId(0) 44..49
3179                FileId(0) 72..77
3180            "#]],
3181        );
3182    }
3183}