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