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