ide/
references.rs

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