Skip to main content

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