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