aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/references.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/references.rs')
-rw-r--r--crates/ide/src/references.rs181
1 files changed, 102 insertions, 79 deletions
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 21b2d7ca1..7d4757e02 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -3,7 +3,7 @@
3//! or `ast::NameRef`. If it's a `ast::NameRef`, at the classification step we 3//! or `ast::NameRef`. If it's a `ast::NameRef`, at the classification step we
4//! try to resolve the direct tree parent of this element, otherwise 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 5//! already have a definition and just need to get its HIR together with
6//! some information that is needed for futher steps of searching. 6//! some information that is needed for further steps of searching.
7//! After that, we collect files that might contain references and look 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` 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 9//! at the index that the match starts at and its tree parent is
@@ -13,15 +13,15 @@ pub(crate) mod rename;
13 13
14use hir::Semantics; 14use hir::Semantics;
15use ide_db::{ 15use ide_db::{
16 base_db::FileId,
16 defs::{Definition, NameClass, NameRefClass}, 17 defs::{Definition, NameClass, NameRefClass},
17 search::Reference, 18 search::{FileReference, ReferenceAccess, ReferenceKind, SearchScope, UsageSearchResult},
18 search::{ReferenceAccess, ReferenceKind, SearchScope},
19 RootDatabase, 19 RootDatabase,
20}; 20};
21use syntax::{ 21use syntax::{
22 algo::find_node_at_offset, 22 algo::find_node_at_offset,
23 ast::{self, NameOwner}, 23 ast::{self, NameOwner},
24 match_ast, AstNode, SyntaxKind, SyntaxNode, TextRange, TokenAtOffset, 24 match_ast, AstNode, SyntaxNode, TextRange, TokenAtOffset, T,
25}; 25};
26 26
27use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo, SymbolKind}; 27use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo, SymbolKind};
@@ -29,7 +29,7 @@ use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeI
29#[derive(Debug, Clone)] 29#[derive(Debug, Clone)]
30pub struct ReferenceSearchResult { 30pub struct ReferenceSearchResult {
31 declaration: Declaration, 31 declaration: Declaration,
32 references: Vec<Reference>, 32 references: UsageSearchResult,
33} 33}
34 34
35#[derive(Debug, Clone)] 35#[derive(Debug, Clone)]
@@ -48,10 +48,21 @@ impl ReferenceSearchResult {
48 &self.declaration.nav 48 &self.declaration.nav
49 } 49 }
50 50
51 pub fn references(&self) -> &[Reference] { 51 pub fn references(&self) -> &UsageSearchResult {
52 &self.references 52 &self.references
53 } 53 }
54 54
55 pub fn references_with_declaration(mut self) -> UsageSearchResult {
56 let decl_ref = FileReference {
57 range: self.declaration.nav.focus_or_full_range(),
58 kind: self.declaration.kind,
59 access: self.declaration.access,
60 };
61 let file_id = self.declaration.nav.file_id;
62 self.references.references.entry(file_id).or_default().push(decl_ref);
63 self.references
64 }
65
55 /// Total number of references 66 /// Total number of references
56 /// At least 1 since all valid references should 67 /// At least 1 since all valid references should
57 /// Have a declaration 68 /// Have a declaration
@@ -63,21 +74,11 @@ impl ReferenceSearchResult {
63// allow turning ReferenceSearchResult into an iterator 74// allow turning ReferenceSearchResult into an iterator
64// over References 75// over References
65impl IntoIterator for ReferenceSearchResult { 76impl IntoIterator for ReferenceSearchResult {
66 type Item = Reference; 77 type Item = (FileId, Vec<FileReference>);
67 type IntoIter = std::vec::IntoIter<Reference>; 78 type IntoIter = std::collections::hash_map::IntoIter<FileId, Vec<FileReference>>;
68 79
69 fn into_iter(mut self) -> Self::IntoIter { 80 fn into_iter(self) -> Self::IntoIter {
70 let mut v = Vec::with_capacity(self.len()); 81 self.references_with_declaration().into_iter()
71 v.push(Reference {
72 file_range: FileRange {
73 file_id: self.declaration.nav.file_id,
74 range: self.declaration.nav.focus_or_full_range(),
75 },
76 kind: self.declaration.kind,
77 access: self.declaration.access,
78 });
79 v.append(&mut self.references);
80 v.into_iter()
81 } 82 }
82} 83}
83 84
@@ -109,13 +110,12 @@ pub(crate) fn find_all_refs(
109 110
110 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?; 111 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?;
111 112
112 let references = def 113 let mut usages = def.usages(sema).set_scope(search_scope).all();
113 .usages(sema) 114 usages
114 .set_scope(search_scope) 115 .references
115 .all() 116 .values_mut()
116 .into_iter() 117 .for_each(|it| it.retain(|r| search_kind == ReferenceKind::Other || search_kind == r.kind));
117 .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) 118 usages.references.retain(|_, it| !it.is_empty());
118 .collect();
119 119
120 let nav = def.try_to_nav(sema.db)?; 120 let nav = def.try_to_nav(sema.db)?;
121 let decl_range = nav.focus_or_full_range(); 121 let decl_range = nav.focus_or_full_range();
@@ -130,13 +130,16 @@ pub(crate) fn find_all_refs(
130 kind = ReferenceKind::FieldShorthandForLocal; 130 kind = ReferenceKind::FieldShorthandForLocal;
131 } 131 }
132 } 132 }
133 } else if matches!(def, Definition::LifetimeParam(_) | Definition::Label(_)) { 133 } else if matches!(
134 def,
135 Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_)
136 ) {
134 kind = ReferenceKind::Lifetime; 137 kind = ReferenceKind::Lifetime;
135 }; 138 };
136 139
137 let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) }; 140 let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) };
138 141
139 Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })) 142 Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references: usages }))
140} 143}
141 144
142fn find_name( 145fn find_name(
@@ -200,7 +203,7 @@ fn get_struct_def_name_for_struct_literal_search(
200 position: FilePosition, 203 position: FilePosition,
201) -> Option<ast::Name> { 204) -> Option<ast::Name> {
202 if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { 205 if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) {
203 if right.kind() != SyntaxKind::L_CURLY && right.kind() != SyntaxKind::L_PAREN { 206 if right.kind() != T!['{'] && right.kind() != T!['('] {
204 return None; 207 return None;
205 } 208 }
206 if let Some(name) = 209 if let Some(name) =
@@ -227,7 +230,7 @@ fn get_enum_def_name_for_struct_literal_search(
227 position: FilePosition, 230 position: FilePosition,
228) -> Option<ast::Name> { 231) -> Option<ast::Name> {
229 if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { 232 if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) {
230 if right.kind() != SyntaxKind::L_CURLY && right.kind() != SyntaxKind::L_PAREN { 233 if right.kind() != T!['{'] && right.kind() != T!['('] {
231 return None; 234 return None;
232 } 235 }
233 if let Some(name) = 236 if let Some(name) =
@@ -252,8 +255,8 @@ fn try_find_self_references(
252 syntax: &SyntaxNode, 255 syntax: &SyntaxNode,
253 position: FilePosition, 256 position: FilePosition,
254) -> Option<RangeInfo<ReferenceSearchResult>> { 257) -> Option<RangeInfo<ReferenceSearchResult>> {
255 let self_token = 258 let FilePosition { file_id, offset } = position;
256 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)?; 259 let self_token = syntax.token_at_offset(offset).find(|t| t.kind() == T![self])?;
257 let parent = self_token.parent(); 260 let parent = self_token.parent();
258 match_ast! { 261 match_ast! {
259 match parent { 262 match parent {
@@ -274,7 +277,7 @@ fn try_find_self_references(
274 277
275 let declaration = Declaration { 278 let declaration = Declaration {
276 nav: NavigationTarget { 279 nav: NavigationTarget {
277 file_id: position.file_id, 280 file_id,
278 full_range: self_param.syntax().text_range(), 281 full_range: self_param.syntax().text_range(),
279 focus_range: Some(param_self_token.text_range()), 282 focus_range: Some(param_self_token.text_range()),
280 name: param_self_token.text().clone(), 283 name: param_self_token.text().clone(),
@@ -290,7 +293,7 @@ fn try_find_self_references(
290 ReferenceAccess::Read 293 ReferenceAccess::Read
291 }), 294 }),
292 }; 295 };
293 let references = function 296 let refs = function
294 .body() 297 .body()
295 .map(|body| { 298 .map(|body| {
296 body.syntax() 299 body.syntax()
@@ -304,14 +307,16 @@ fn try_find_self_references(
304 None 307 None
305 } 308 }
306 }) 309 })
307 .map(|token| Reference { 310 .map(|token| FileReference {
308 file_range: FileRange { file_id: position.file_id, range: token.text_range() }, 311 range: token.text_range(),
309 kind: ReferenceKind::SelfKw, 312 kind: ReferenceKind::SelfKw,
310 access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration 313 access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration
311 }) 314 })
312 .collect() 315 .collect()
313 }) 316 })
314 .unwrap_or_default(); 317 .unwrap_or_default();
318 let mut references = UsageSearchResult::default();
319 references.references.insert(file_id, refs);
315 320
316 Some(RangeInfo::new( 321 Some(RangeInfo::new(
317 param_self_token.text_range(), 322 param_self_token.text_range(),
@@ -331,7 +336,7 @@ mod tests {
331 fn test_struct_literal_after_space() { 336 fn test_struct_literal_after_space() {
332 check( 337 check(
333 r#" 338 r#"
334struct Foo <|>{ 339struct Foo $0{
335 a: i32, 340 a: i32,
336} 341}
337impl Foo { 342impl Foo {
@@ -354,7 +359,7 @@ fn main() {
354 fn test_struct_literal_before_space() { 359 fn test_struct_literal_before_space() {
355 check( 360 check(
356 r#" 361 r#"
357struct Foo<|> {} 362struct Foo$0 {}
358 fn main() { 363 fn main() {
359 let f: Foo; 364 let f: Foo;
360 f = Foo {}; 365 f = Foo {};
@@ -373,7 +378,7 @@ struct Foo<|> {}
373 fn test_struct_literal_with_generic_type() { 378 fn test_struct_literal_with_generic_type() {
374 check( 379 check(
375 r#" 380 r#"
376struct Foo<T> <|>{} 381struct Foo<T> $0{}
377 fn main() { 382 fn main() {
378 let f: Foo::<i32>; 383 let f: Foo::<i32>;
379 f = Foo {}; 384 f = Foo {};
@@ -391,7 +396,7 @@ struct Foo<T> <|>{}
391 fn test_struct_literal_for_tuple() { 396 fn test_struct_literal_for_tuple() {
392 check( 397 check(
393 r#" 398 r#"
394struct Foo<|>(i32); 399struct Foo$0(i32);
395 400
396fn main() { 401fn main() {
397 let f: Foo; 402 let f: Foo;
@@ -410,7 +415,7 @@ fn main() {
410 fn test_enum_after_space() { 415 fn test_enum_after_space() {
411 check( 416 check(
412 r#" 417 r#"
413enum Foo <|>{ 418enum Foo $0{
414 A, 419 A,
415 B, 420 B,
416} 421}
@@ -431,7 +436,7 @@ fn main() {
431 fn test_enum_before_space() { 436 fn test_enum_before_space() {
432 check( 437 check(
433 r#" 438 r#"
434enum Foo<|> { 439enum Foo$0 {
435 A, 440 A,
436 B, 441 B,
437} 442}
@@ -453,7 +458,7 @@ fn main() {
453 fn test_enum_with_generic_type() { 458 fn test_enum_with_generic_type() {
454 check( 459 check(
455 r#" 460 r#"
456enum Foo<T> <|>{ 461enum Foo<T> $0{
457 A(T), 462 A(T),
458 B, 463 B,
459} 464}
@@ -474,7 +479,7 @@ fn main() {
474 fn test_enum_for_tuple() { 479 fn test_enum_for_tuple() {
475 check( 480 check(
476 r#" 481 r#"
477enum Foo<|>{ 482enum Foo$0{
478 A(i8), 483 A(i8),
479 B(i8), 484 B(i8),
480} 485}
@@ -498,7 +503,7 @@ fn main() {
498fn main() { 503fn main() {
499 let mut i = 1; 504 let mut i = 1;
500 let j = 1; 505 let j = 1;
501 i = i<|> + j; 506 i = i$0 + j;
502 507
503 { 508 {
504 i = 0; 509 i = 0;
@@ -522,7 +527,7 @@ fn main() {
522 check( 527 check(
523 r#" 528 r#"
524fn foo() { 529fn foo() {
525 let spam<|> = 92; 530 let spam$0 = 92;
526 spam + spam 531 spam + spam
527} 532}
528fn bar() { 533fn bar() {
@@ -543,7 +548,7 @@ fn bar() {
543 fn test_find_all_refs_for_param_inside() { 548 fn test_find_all_refs_for_param_inside() {
544 check( 549 check(
545 r#" 550 r#"
546fn foo(i : u32) -> u32 { i<|> } 551fn foo(i : u32) -> u32 { i$0 }
547"#, 552"#,
548 expect![[r#" 553 expect![[r#"
549 i ValueParam FileId(0) 7..8 Other 554 i ValueParam FileId(0) 7..8 Other
@@ -557,7 +562,7 @@ fn foo(i : u32) -> u32 { i<|> }
557 fn test_find_all_refs_for_fn_param() { 562 fn test_find_all_refs_for_fn_param() {
558 check( 563 check(
559 r#" 564 r#"
560fn foo(i<|> : u32) -> u32 { i } 565fn foo(i$0 : u32) -> u32 { i }
561"#, 566"#,
562 expect![[r#" 567 expect![[r#"
563 i ValueParam FileId(0) 7..8 Other 568 i ValueParam FileId(0) 7..8 Other
@@ -573,7 +578,7 @@ fn foo(i<|> : u32) -> u32 { i }
573 r#" 578 r#"
574//- /lib.rs 579//- /lib.rs
575struct Foo { 580struct Foo {
576 pub spam<|>: u32, 581 pub spam$0: u32,
577} 582}
578 583
579fn main(s: Foo) { 584fn main(s: Foo) {
@@ -594,7 +599,7 @@ fn main(s: Foo) {
594 r#" 599 r#"
595struct Foo; 600struct Foo;
596impl Foo { 601impl Foo {
597 fn f<|>(&self) { } 602 fn f$0(&self) { }
598} 603}
599"#, 604"#,
600 expect![[r#" 605 expect![[r#"
@@ -610,7 +615,7 @@ impl Foo {
610 r#" 615 r#"
611enum Foo { 616enum Foo {
612 A, 617 A,
613 B<|>, 618 B$0,
614 C, 619 C,
615} 620}
616"#, 621"#,
@@ -627,7 +632,7 @@ enum Foo {
627 r#" 632 r#"
628enum Foo { 633enum Foo {
629 A, 634 A,
630 B { field<|>: u8 }, 635 B { field$0: u8 },
631 C, 636 C,
632} 637}
633"#, 638"#,
@@ -669,7 +674,7 @@ pub struct Bar {
669} 674}
670 675
671fn f() { 676fn f() {
672 let i = foo::Foo<|> { n: 5 }; 677 let i = foo::Foo$0 { n: 5 };
673} 678}
674"#, 679"#,
675 expect![[r#" 680 expect![[r#"
@@ -689,7 +694,7 @@ fn f() {
689 check( 694 check(
690 r#" 695 r#"
691//- /lib.rs 696//- /lib.rs
692mod foo<|>; 697mod foo$0;
693 698
694use foo::Foo; 699use foo::Foo;
695 700
@@ -726,7 +731,7 @@ fn f() {
726} 731}
727 732
728//- /foo/some.rs 733//- /foo/some.rs
729pub(super) struct Foo<|> { 734pub(super) struct Foo$0 {
730 pub n: u32, 735 pub n: u32,
731} 736}
732"#, 737"#,
@@ -746,7 +751,7 @@ pub(super) struct Foo<|> {
746 mod foo; 751 mod foo;
747 mod bar; 752 mod bar;
748 753
749 pub fn quux<|>() {} 754 pub fn quux$0() {}
750 755
751 //- /foo.rs 756 //- /foo.rs
752 fn f() { super::quux(); } 757 fn f() { super::quux(); }
@@ -782,7 +787,7 @@ pub(super) struct Foo<|> {
782 check( 787 check(
783 r#" 788 r#"
784#[macro_export] 789#[macro_export]
785macro_rules! m1<|> { () => (()) } 790macro_rules! m1$0 { () => (()) }
786 791
787fn foo() { 792fn foo() {
788 m1(); 793 m1();
@@ -803,7 +808,7 @@ fn foo() {
803 check( 808 check(
804 r#" 809 r#"
805fn foo() { 810fn foo() {
806 let mut i<|> = 0; 811 let mut i$0 = 0;
807 i = i + 1; 812 i = i + 1;
808} 813}
809"#, 814"#,
@@ -826,7 +831,7 @@ struct S {
826 831
827fn foo() { 832fn foo() {
828 let mut s = S{f: 0}; 833 let mut s = S{f: 0};
829 s.f<|> = 0; 834 s.f$0 = 0;
830} 835}
831"#, 836"#,
832 expect![[r#" 837 expect![[r#"
@@ -843,7 +848,7 @@ fn foo() {
843 check( 848 check(
844 r#" 849 r#"
845fn foo() { 850fn foo() {
846 let i<|>; 851 let i$0;
847 i = 1; 852 i = 1;
848} 853}
849"#, 854"#,
@@ -863,7 +868,7 @@ mod foo {
863 pub struct Foo; 868 pub struct Foo;
864 869
865 impl Foo { 870 impl Foo {
866 pub fn new<|>() -> Foo { Foo } 871 pub fn new$0() -> Foo { Foo }
867 } 872 }
868} 873}
869 874
@@ -886,7 +891,7 @@ fn main() {
886//- /lib.rs 891//- /lib.rs
887mod foo { mod bar; } 892mod foo { mod bar; }
888 893
889fn f<|>() {} 894fn f$0() {}
890 895
891//- /foo/bar.rs 896//- /foo/bar.rs
892use crate::f; 897use crate::f;
@@ -907,7 +912,7 @@ fn g() { f(); }
907 check( 912 check(
908 r#" 913 r#"
909struct S { 914struct S {
910 field<|>: u8, 915 field$0: u8,
911} 916}
912 917
913fn f(s: S) { 918fn f(s: S) {
@@ -930,7 +935,7 @@ fn f(s: S) {
930 r#" 935 r#"
931enum En { 936enum En {
932 Variant { 937 Variant {
933 field<|>: u8, 938 field$0: u8,
934 } 939 }
935} 940}
936 941
@@ -955,7 +960,7 @@ fn f(e: En) {
955mod m { 960mod m {
956 pub enum En { 961 pub enum En {
957 Variant { 962 Variant {
958 field<|>: u8, 963 field$0: u8,
959 } 964 }
960 } 965 }
961} 966}
@@ -980,7 +985,7 @@ struct Foo { bar: i32 }
980 985
981impl Foo { 986impl Foo {
982 fn foo(self) { 987 fn foo(self) {
983 let x = self<|>.bar; 988 let x = self$0.bar;
984 if true { 989 if true {
985 let _ = match () { 990 let _ = match () {
986 () => self, 991 () => self,
@@ -1016,12 +1021,14 @@ impl Foo {
1016 actual += "\n\n"; 1021 actual += "\n\n";
1017 } 1022 }
1018 1023
1019 for r in &refs.references { 1024 for (file_id, references) in refs.references {
1020 format_to!(actual, "{:?} {:?} {:?}", r.file_range.file_id, r.file_range.range, r.kind); 1025 for r in references {
1021 if let Some(access) = r.access { 1026 format_to!(actual, "{:?} {:?} {:?}", file_id, r.range, r.kind);
1022 format_to!(actual, " {:?}", access); 1027 if let Some(access) = r.access {
1028 format_to!(actual, " {:?}", access);
1029 }
1030 actual += "\n";
1023 } 1031 }
1024 actual += "\n";
1025 } 1032 }
1026 expect.assert_eq(&actual) 1033 expect.assert_eq(&actual)
1027 } 1034 }
@@ -1032,7 +1039,7 @@ impl Foo {
1032 r#" 1039 r#"
1033trait Foo<'a> {} 1040trait Foo<'a> {}
1034impl<'a> Foo<'a> for &'a () {} 1041impl<'a> Foo<'a> for &'a () {}
1035fn foo<'a, 'b: 'a>(x: &'a<|> ()) -> &'a () where &'a (): Foo<'a> { 1042fn foo<'a, 'b: 'a>(x: &'a$0 ()) -> &'a () where &'a (): Foo<'a> {
1036 fn bar<'a>(_: &'a ()) {} 1043 fn bar<'a>(_: &'a ()) {}
1037 x 1044 x
1038} 1045}
@@ -1053,7 +1060,7 @@ fn foo<'a, 'b: 'a>(x: &'a<|> ()) -> &'a () where &'a (): Foo<'a> {
1053 fn test_find_lifetimes_type_alias() { 1060 fn test_find_lifetimes_type_alias() {
1054 check( 1061 check(
1055 r#" 1062 r#"
1056type Foo<'a, T> where T: 'a<|> = &'a T; 1063type Foo<'a, T> where T: 'a$0 = &'a T;
1057"#, 1064"#,
1058 expect![[r#" 1065 expect![[r#"
1059 'a LifetimeParam FileId(0) 9..11 9..11 Lifetime 1066 'a LifetimeParam FileId(0) 9..11 9..11 Lifetime
@@ -1072,7 +1079,7 @@ trait Foo<'a> {
1072 fn foo() -> &'a (); 1079 fn foo() -> &'a ();
1073} 1080}
1074impl<'a> Foo<'a> for &'a () { 1081impl<'a> Foo<'a> for &'a () {
1075 fn foo() -> &'a<|> () { 1082 fn foo() -> &'a$0 () {
1076 unimplemented!() 1083 unimplemented!()
1077 } 1084 }
1078} 1085}
@@ -1093,7 +1100,7 @@ impl<'a> Foo<'a> for &'a () {
1093 r#" 1100 r#"
1094macro_rules! foo {($i:ident) => {$i} } 1101macro_rules! foo {($i:ident) => {$i} }
1095fn main() { 1102fn main() {
1096 let a<|> = "test"; 1103 let a$0 = "test";
1097 foo!(a); 1104 foo!(a);
1098} 1105}
1099"#, 1106"#,
@@ -1112,7 +1119,7 @@ fn main() {
1112macro_rules! foo {($i:ident) => {$i} } 1119macro_rules! foo {($i:ident) => {$i} }
1113fn main() { 1120fn main() {
1114 let a = "test"; 1121 let a = "test";
1115 foo!(a<|>); 1122 foo!(a$0);
1116} 1123}
1117"#, 1124"#,
1118 expect![[r#" 1125 expect![[r#"
@@ -1130,7 +1137,7 @@ fn main() {
1130fn foo<'a>() -> &'a () { 1137fn foo<'a>() -> &'a () {
1131 'a: loop { 1138 'a: loop {
1132 'b: loop { 1139 'b: loop {
1133 continue 'a<|>; 1140 continue 'a$0;
1134 } 1141 }
1135 break 'a; 1142 break 'a;
1136 } 1143 }
@@ -1144,4 +1151,20 @@ fn foo<'a>() -> &'a () {
1144 "#]], 1151 "#]],
1145 ); 1152 );
1146 } 1153 }
1154
1155 #[test]
1156 fn test_find_const_param() {
1157 check(
1158 r#"
1159fn foo<const FOO$0: usize>() -> usize {
1160 FOO
1161}
1162"#,
1163 expect![[r#"
1164 FOO ConstParam FileId(0) 7..23 13..16 Other
1165
1166 FileId(0) 42..45 Other
1167 "#]],
1168 );
1169 }
1147} 1170}