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.rs686
1 files changed, 415 insertions, 271 deletions
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index df9c31aef..fef70533d 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -11,171 +11,120 @@
11 11
12pub(crate) mod rename; 12pub(crate) mod rename;
13 13
14use either::Either; 14use hir::{PathResolution, Semantics};
15use hir::Semantics;
16use ide_db::{ 15use ide_db::{
17 base_db::FileId, 16 base_db::FileId,
18 defs::{Definition, NameClass, NameRefClass}, 17 defs::{Definition, NameClass, NameRefClass},
19 search::{FileReference, ReferenceAccess, ReferenceKind, SearchScope, UsageSearchResult}, 18 search::{ReferenceAccess, SearchScope},
20 RootDatabase, 19 RootDatabase,
21}; 20};
21use rustc_hash::FxHashMap;
22use syntax::{ 22use syntax::{
23 algo::find_node_at_offset, 23 algo::find_node_at_offset,
24 ast::{self, NameOwner}, 24 ast::{self, NameOwner},
25 AstNode, SyntaxNode, TextRange, TokenAtOffset, T, 25 match_ast, AstNode, SyntaxNode, TextRange, T,
26}; 26};
27 27
28use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo}; 28use crate::{display::TryToNav, FilePosition, NavigationTarget};
29 29
30#[derive(Debug, Clone)] 30#[derive(Debug, Clone)]
31pub struct ReferenceSearchResult { 31pub struct ReferenceSearchResult {
32 declaration: Declaration, 32 pub declaration: Declaration,
33 references: UsageSearchResult, 33 pub references: FxHashMap<FileId, Vec<(TextRange, Option<ReferenceAccess>)>>,
34} 34}
35 35
36#[derive(Debug, Clone)] 36#[derive(Debug, Clone)]
37pub struct Declaration { 37pub struct Declaration {
38 pub nav: NavigationTarget, 38 pub nav: NavigationTarget,
39 pub kind: ReferenceKind,
40 pub access: Option<ReferenceAccess>, 39 pub access: Option<ReferenceAccess>,
41} 40}
42 41
43impl ReferenceSearchResult { 42// Feature: Find All References
44 pub fn declaration(&self) -> &Declaration { 43//
45 &self.declaration 44// Shows all references of the item at the cursor location
46 } 45//
47 46// |===
48 pub fn decl_target(&self) -> &NavigationTarget { 47// | Editor | Shortcut
49 &self.declaration.nav 48//
50 } 49// | VS Code | kbd:[Shift+Alt+F12]
51 50// |===
52 pub fn references(&self) -> &UsageSearchResult {
53 &self.references
54 }
55
56 pub fn references_with_declaration(mut self) -> UsageSearchResult {
57 let decl_ref = FileReference {
58 range: self.declaration.nav.focus_or_full_range(),
59 kind: self.declaration.kind,
60 access: self.declaration.access,
61 };
62 let file_id = self.declaration.nav.file_id;
63 self.references.references.entry(file_id).or_default().push(decl_ref);
64 self.references
65 }
66
67 /// Total number of references
68 /// At least 1 since all valid references should
69 /// Have a declaration
70 pub fn len(&self) -> usize {
71 self.references.len() + 1
72 }
73}
74
75// allow turning ReferenceSearchResult into an iterator
76// over References
77impl IntoIterator for ReferenceSearchResult {
78 type Item = (FileId, Vec<FileReference>);
79 type IntoIter = std::collections::hash_map::IntoIter<FileId, Vec<FileReference>>;
80
81 fn into_iter(self) -> Self::IntoIter {
82 self.references_with_declaration().into_iter()
83 }
84}
85
86pub(crate) fn find_all_refs( 51pub(crate) fn find_all_refs(
87 sema: &Semantics<RootDatabase>, 52 sema: &Semantics<RootDatabase>,
88 position: FilePosition, 53 position: FilePosition,
89 search_scope: Option<SearchScope>, 54 search_scope: Option<SearchScope>,
90) -> Option<RangeInfo<ReferenceSearchResult>> { 55) -> Option<ReferenceSearchResult> {
91 let _p = profile::span("find_all_refs"); 56 let _p = profile::span("find_all_refs");
92 let syntax = sema.parse(position.file_id).syntax().clone(); 57 let syntax = sema.parse(position.file_id).syntax().clone();
93 58
94 let (opt_name, search_kind) = if let Some(name) = 59 let (def, is_literal_search) =
95 get_struct_def_name_for_struct_literal_search(&sema, &syntax, position) 60 if let Some(name) = get_name_of_item_declaration(&syntax, position) {
96 { 61 (NameClass::classify(sema, &name)?.referenced_or_defined(sema.db), true)
97 (Some(name), ReferenceKind::StructLiteral) 62 } else {
98 } else if let Some(name) = get_enum_def_name_for_struct_literal_search(&sema, &syntax, position) 63 (find_def(&sema, &syntax, position)?, false)
99 { 64 };
100 (Some(name), ReferenceKind::EnumLiteral)
101 } else {
102 (
103 sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, position.offset),
104 ReferenceKind::Other,
105 )
106 };
107
108 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?;
109 65
110 let mut usages = def.usages(sema).set_scope(search_scope).all(); 66 let mut usages = def.usages(sema).set_scope(search_scope).all();
111 usages 67 if is_literal_search {
112 .references 68 // filter for constructor-literals
113 .values_mut() 69 let refs = usages.references.values_mut();
114 .for_each(|it| it.retain(|r| search_kind == ReferenceKind::Other || search_kind == r.kind)); 70 match def {
115 usages.references.retain(|_, it| !it.is_empty()); 71 Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(enum_))) => {
116 72 refs.for_each(|it| {
117 let nav = def.try_to_nav(sema.db)?; 73 it.retain(|reference| {
118 let decl_range = nav.focus_or_full_range(); 74 reference
119 75 .name
120 let mut kind = ReferenceKind::Other; 76 .as_name_ref()
121 if let Definition::Local(local) = def { 77 .map_or(false, |name_ref| is_enum_lit_name_ref(sema, enum_, name_ref))
122 match local.source(sema.db).value { 78 })
123 Either::Left(pat) => { 79 });
124 if matches!( 80 usages.references.retain(|_, it| !it.is_empty());
125 pat.syntax().parent().and_then(ast::RecordPatField::cast),
126 Some(pat_field) if pat_field.name_ref().is_none()
127 ) {
128 kind = ReferenceKind::FieldShorthandForLocal;
129 }
130 } 81 }
131 Either::Right(_) => kind = ReferenceKind::SelfParam, 82 Definition::ModuleDef(hir::ModuleDef::Adt(_))
83 | Definition::ModuleDef(hir::ModuleDef::Variant(_)) => {
84 refs.for_each(|it| {
85 it.retain(|reference| {
86 reference.name.as_name_ref().map_or(false, is_lit_name_ref)
87 })
88 });
89 usages.references.retain(|_, it| !it.is_empty());
90 }
91 _ => {}
132 } 92 }
133 } else if matches!( 93 }
134 def, 94 let nav = def.try_to_nav(sema.db)?;
135 Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_) 95 let decl_range = nav.focus_or_full_range();
136 ) {
137 kind = ReferenceKind::Lifetime;
138 };
139 96
140 let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) }; 97 let declaration = Declaration { nav, access: decl_access(&def, &syntax, decl_range) };
98 let references = usages
99 .into_iter()
100 .map(|(file_id, refs)| {
101 (file_id, refs.into_iter().map(|file_ref| (file_ref.range, file_ref.access)).collect())
102 })
103 .collect();
141 104
142 Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references: usages })) 105 Some(ReferenceSearchResult { declaration, references })
143} 106}
144 107
145fn find_name( 108fn find_def(
146 sema: &Semantics<RootDatabase>, 109 sema: &Semantics<RootDatabase>,
147 syntax: &SyntaxNode, 110 syntax: &SyntaxNode,
148 position: FilePosition, 111 position: FilePosition,
149 opt_name: Option<ast::Name>, 112) -> Option<Definition> {
150) -> Option<RangeInfo<Definition>> { 113 let def = match sema.find_node_at_offset_with_descend(syntax, position.offset)? {
151 if let Some(name) = opt_name { 114 ast::NameLike::NameRef(name_ref) => {
152 let def = NameClass::classify(sema, &name)?.referenced_or_defined(sema.db); 115 NameRefClass::classify(sema, &name_ref)?.referenced(sema.db)
153 let FileRange { range, .. } = sema.original_range(name.syntax());
154 return Some(RangeInfo::new(range, def));
155 }
156
157 let (FileRange { range, .. }, def) = if let Some(lifetime) =
158 sema.find_node_at_offset_with_descend::<ast::Lifetime>(&syntax, position.offset)
159 {
160 if let Some(def) = NameRefClass::classify_lifetime(sema, &lifetime)
161 .map(|class| NameRefClass::referenced(class, sema.db))
162 {
163 (sema.original_range(lifetime.syntax()), def)
164 } else {
165 (
166 sema.original_range(lifetime.syntax()),
167 NameClass::classify_lifetime(sema, &lifetime)?.referenced_or_defined(sema.db),
168 )
169 } 116 }
170 } else { 117 ast::NameLike::Name(name) => {
171 let name_ref = 118 NameClass::classify(sema, &name)?.referenced_or_defined(sema.db)
172 sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?; 119 }
173 ( 120 ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime)
174 sema.original_range(name_ref.syntax()), 121 .map(|class| class.referenced(sema.db))
175 NameRefClass::classify(sema, &name_ref)?.referenced(sema.db), 122 .or_else(|| {
176 ) 123 NameClass::classify_lifetime(sema, &lifetime)
124 .map(|class| class.referenced_or_defined(sema.db))
125 })?,
177 }; 126 };
178 Some(RangeInfo::new(range, def)) 127 Some(def)
179} 128}
180 129
181fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option<ReferenceAccess> { 130fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option<ReferenceAccess> {
@@ -197,58 +146,85 @@ fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Optio
197 None 146 None
198} 147}
199 148
200fn get_struct_def_name_for_struct_literal_search( 149fn get_name_of_item_declaration(syntax: &SyntaxNode, position: FilePosition) -> Option<ast::Name> {
201 sema: &Semantics<RootDatabase>, 150 let token = syntax.token_at_offset(position.offset).right_biased()?;
202 syntax: &SyntaxNode, 151 let kind = token.kind();
203 position: FilePosition, 152 if kind == T![;] {
204) -> Option<ast::Name> { 153 ast::Struct::cast(token.parent())
205 if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { 154 .filter(|struct_| struct_.field_list().is_none())
206 if right.kind() != T!['{'] && right.kind() != T!['('] { 155 .and_then(|struct_| struct_.name())
207 return None; 156 } else if kind == T!['{'] {
208 } 157 match_ast! {
209 if let Some(name) = 158 match (token.parent()) {
210 sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, left.text_range().start()) 159 ast::RecordFieldList(rfl) => match_ast! {
211 { 160 match (rfl.syntax().parent()?) {
212 return name.syntax().ancestors().find_map(ast::Struct::cast).and_then(|l| l.name()); 161 ast::Variant(it) => it.name(),
162 ast::Struct(it) => it.name(),
163 ast::Union(it) => it.name(),
164 _ => None,
165 }
166 },
167 ast::VariantList(vl) => ast::Enum::cast(vl.syntax().parent()?)?.name(),
168 _ => None,
169 }
213 } 170 }
214 if sema 171 } else if kind == T!['('] {
215 .find_node_at_offset_with_descend::<ast::GenericParamList>( 172 let tfl = ast::TupleFieldList::cast(token.parent())?;
216 &syntax, 173 match_ast! {
217 left.text_range().start(), 174 match (tfl.syntax().parent()?) {
218 ) 175 ast::Variant(it) => it.name(),
219 .is_some() 176 ast::Struct(it) => it.name(),
220 { 177 _ => None,
221 return left.ancestors().find_map(ast::Struct::cast).and_then(|l| l.name()); 178 }
222 } 179 }
180 } else {
181 None
223 } 182 }
224 None
225} 183}
226 184
227fn get_enum_def_name_for_struct_literal_search( 185fn is_enum_lit_name_ref(
228 sema: &Semantics<RootDatabase>, 186 sema: &Semantics<RootDatabase>,
229 syntax: &SyntaxNode, 187 enum_: hir::Enum,
230 position: FilePosition, 188 name_ref: &ast::NameRef,
231) -> Option<ast::Name> { 189) -> bool {
232 if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { 190 let path_is_variant_of_enum = |path: ast::Path| {
233 if right.kind() != T!['{'] && right.kind() != T!['('] { 191 matches!(
234 return None; 192 sema.resolve_path(&path),
235 } 193 Some(PathResolution::Def(hir::ModuleDef::Variant(variant)))
236 if let Some(name) = 194 if variant.parent_enum(sema.db) == enum_
237 sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, left.text_range().start()) 195 )
238 { 196 };
239 return name.syntax().ancestors().find_map(ast::Enum::cast).and_then(|l| l.name()); 197 name_ref
240 } 198 .syntax()
241 if sema 199 .ancestors()
242 .find_node_at_offset_with_descend::<ast::GenericParamList>( 200 .find_map(|ancestor| {
243 &syntax, 201 match_ast! {
244 left.text_range().start(), 202 match ancestor {
245 ) 203 ast::PathExpr(path_expr) => path_expr.path().map(path_is_variant_of_enum),
246 .is_some() 204 ast::RecordExpr(record_expr) => record_expr.path().map(path_is_variant_of_enum),
247 { 205 _ => None,
248 return left.ancestors().find_map(ast::Enum::cast).and_then(|l| l.name()); 206 }
207 }
208 })
209 .unwrap_or(false)
210}
211
212fn path_ends_with(path: Option<ast::Path>, name_ref: &ast::NameRef) -> bool {
213 path.and_then(|path| path.segment())
214 .and_then(|segment| segment.name_ref())
215 .map_or(false, |segment| segment == *name_ref)
216}
217
218fn is_lit_name_ref(name_ref: &ast::NameRef) -> bool {
219 name_ref.syntax().ancestors().find_map(|ancestor| {
220 match_ast! {
221 match ancestor {
222 ast::PathExpr(path_expr) => Some(path_ends_with(path_expr.path(), name_ref)),
223 ast::RecordExpr(record_expr) => Some(path_ends_with(record_expr.path(), name_ref)),
224 _ => None,
225 }
249 } 226 }
250 } 227 }).unwrap_or(false)
251 None
252} 228}
253 229
254#[cfg(test)] 230#[cfg(test)]
@@ -275,9 +251,9 @@ fn main() {
275} 251}
276"#, 252"#,
277 expect![[r#" 253 expect![[r#"
278 Foo Struct FileId(0) 0..26 7..10 Other 254 Foo Struct FileId(0) 0..26 7..10
279 255
280 FileId(0) 101..104 StructLiteral 256 FileId(0) 101..104
281 "#]], 257 "#]],
282 ); 258 );
283 } 259 }
@@ -293,10 +269,10 @@ struct Foo$0 {}
293} 269}
294"#, 270"#,
295 expect![[r#" 271 expect![[r#"
296 Foo Struct FileId(0) 0..13 7..10 Other 272 Foo Struct FileId(0) 0..13 7..10
297 273
298 FileId(0) 41..44 Other 274 FileId(0) 41..44
299 FileId(0) 54..57 StructLiteral 275 FileId(0) 54..57
300 "#]], 276 "#]],
301 ); 277 );
302 } 278 }
@@ -312,9 +288,9 @@ struct Foo<T> $0{}
312} 288}
313"#, 289"#,
314 expect![[r#" 290 expect![[r#"
315 Foo Struct FileId(0) 0..16 7..10 Other 291 Foo Struct FileId(0) 0..16 7..10
316 292
317 FileId(0) 64..67 StructLiteral 293 FileId(0) 64..67
318 "#]], 294 "#]],
319 ); 295 );
320 } 296 }
@@ -331,9 +307,30 @@ fn main() {
331} 307}
332"#, 308"#,
333 expect![[r#" 309 expect![[r#"
334 Foo Struct FileId(0) 0..16 7..10 Other 310 Foo Struct FileId(0) 0..16 7..10
311
312 FileId(0) 54..57
313 "#]],
314 );
315 }
316
317 #[test]
318 fn test_struct_literal_for_union() {
319 check(
320 r#"
321union Foo $0{
322 x: u32
323}
324
325fn main() {
326 let f: Foo;
327 f = Foo { x: 1 };
328}
329"#,
330 expect![[r#"
331 Foo Union FileId(0) 0..24 6..9
335 332
336 FileId(0) 54..57 StructLiteral 333 FileId(0) 62..65
337 "#]], 334 "#]],
338 ); 335 );
339 } 336 }
@@ -344,17 +341,65 @@ fn main() {
344 r#" 341 r#"
345enum Foo $0{ 342enum Foo $0{
346 A, 343 A,
347 B, 344 B(),
345 C{},
348} 346}
349fn main() { 347fn main() {
350 let f: Foo; 348 let f: Foo;
351 f = Foo::A; 349 f = Foo::A;
350 f = Foo::B();
351 f = Foo::C{};
352}
353"#,
354 expect![[r#"
355 Foo Enum FileId(0) 0..37 5..8
356
357 FileId(0) 74..77
358 FileId(0) 90..93
359 FileId(0) 108..111
360 "#]],
361 );
362 }
363
364 #[test]
365 fn test_variant_record_after_space() {
366 check(
367 r#"
368enum Foo {
369 A $0{ n: i32 },
370 B,
371}
372fn main() {
373 let f: Foo;
374 f = Foo::B;
375 f = Foo::A { n: 92 };
352} 376}
353"#, 377"#,
354 expect![[r#" 378 expect![[r#"
355 Foo Enum FileId(0) 0..26 5..8 Other 379 A Variant FileId(0) 15..27 15..16
356 380
357 FileId(0) 63..66 EnumLiteral 381 FileId(0) 95..96
382 "#]],
383 );
384 }
385 #[test]
386 fn test_variant_tuple_before_paren() {
387 check(
388 r#"
389enum Foo {
390 A$0(i32),
391 B,
392}
393fn main() {
394 let f: Foo;
395 f = Foo::B;
396 f = Foo::A(92);
397}
398"#,
399 expect![[r#"
400 A Variant FileId(0) 15..21 15..16
401
402 FileId(0) 89..90
358 "#]], 403 "#]],
359 ); 404 );
360 } 405 }
@@ -373,10 +418,10 @@ fn main() {
373} 418}
374"#, 419"#,
375 expect![[r#" 420 expect![[r#"
376 Foo Enum FileId(0) 0..26 5..8 Other 421 Foo Enum FileId(0) 0..26 5..8
377 422
378 FileId(0) 50..53 Other 423 FileId(0) 50..53
379 FileId(0) 63..66 EnumLiteral 424 FileId(0) 63..66
380 "#]], 425 "#]],
381 ); 426 );
382 } 427 }
@@ -395,9 +440,9 @@ fn main() {
395} 440}
396"#, 441"#,
397 expect![[r#" 442 expect![[r#"
398 Foo Enum FileId(0) 0..32 5..8 Other 443 Foo Enum FileId(0) 0..32 5..8
399 444
400 FileId(0) 73..76 EnumLiteral 445 FileId(0) 73..76
401 "#]], 446 "#]],
402 ); 447 );
403 } 448 }
@@ -416,9 +461,9 @@ fn main() {
416} 461}
417"#, 462"#,
418 expect![[r#" 463 expect![[r#"
419 Foo Enum FileId(0) 0..33 5..8 Other 464 Foo Enum FileId(0) 0..33 5..8
420 465
421 FileId(0) 70..73 EnumLiteral 466 FileId(0) 70..73
422 "#]], 467 "#]],
423 ); 468 );
424 } 469 }
@@ -439,12 +484,12 @@ fn main() {
439 i = 5; 484 i = 5;
440}"#, 485}"#,
441 expect![[r#" 486 expect![[r#"
442 i Local FileId(0) 20..25 24..25 Other Write 487 i Local FileId(0) 20..25 24..25 Write
443 488
444 FileId(0) 50..51 Other Write 489 FileId(0) 50..51 Write
445 FileId(0) 54..55 Other Read 490 FileId(0) 54..55 Read
446 FileId(0) 76..77 Other Write 491 FileId(0) 76..77 Write
447 FileId(0) 94..95 Other Write 492 FileId(0) 94..95 Write
448 "#]], 493 "#]],
449 ); 494 );
450 } 495 }
@@ -463,10 +508,10 @@ fn bar() {
463} 508}
464"#, 509"#,
465 expect![[r#" 510 expect![[r#"
466 spam Local FileId(0) 19..23 19..23 Other 511 spam Local FileId(0) 19..23 19..23
467 512
468 FileId(0) 34..38 Other Read 513 FileId(0) 34..38 Read
469 FileId(0) 41..45 Other Read 514 FileId(0) 41..45 Read
470 "#]], 515 "#]],
471 ); 516 );
472 } 517 }
@@ -478,9 +523,9 @@ fn bar() {
478fn foo(i : u32) -> u32 { i$0 } 523fn foo(i : u32) -> u32 { i$0 }
479"#, 524"#,
480 expect![[r#" 525 expect![[r#"
481 i ValueParam FileId(0) 7..8 7..8 Other 526 i ValueParam FileId(0) 7..8 7..8
482 527
483 FileId(0) 25..26 Other Read 528 FileId(0) 25..26 Read
484 "#]], 529 "#]],
485 ); 530 );
486 } 531 }
@@ -492,9 +537,9 @@ fn foo(i : u32) -> u32 { i$0 }
492fn foo(i$0 : u32) -> u32 { i } 537fn foo(i$0 : u32) -> u32 { i }
493"#, 538"#,
494 expect![[r#" 539 expect![[r#"
495 i ValueParam FileId(0) 7..8 7..8 Other 540 i ValueParam FileId(0) 7..8 7..8
496 541
497 FileId(0) 25..26 Other Read 542 FileId(0) 25..26 Read
498 "#]], 543 "#]],
499 ); 544 );
500 } 545 }
@@ -513,9 +558,9 @@ fn main(s: Foo) {
513} 558}
514"#, 559"#,
515 expect![[r#" 560 expect![[r#"
516 spam Field FileId(0) 17..30 21..25 Other 561 spam Field FileId(0) 17..30 21..25
517 562
518 FileId(0) 67..71 Other Read 563 FileId(0) 67..71 Read
519 "#]], 564 "#]],
520 ); 565 );
521 } 566 }
@@ -530,7 +575,7 @@ impl Foo {
530} 575}
531"#, 576"#,
532 expect![[r#" 577 expect![[r#"
533 f Function FileId(0) 27..43 30..31 Other 578 f Function FileId(0) 27..43 30..31
534 579
535 "#]], 580 "#]],
536 ); 581 );
@@ -547,7 +592,7 @@ enum Foo {
547} 592}
548"#, 593"#,
549 expect![[r#" 594 expect![[r#"
550 B Variant FileId(0) 22..23 22..23 Other 595 B Variant FileId(0) 22..23 22..23
551 596
552 "#]], 597 "#]],
553 ); 598 );
@@ -564,7 +609,7 @@ enum Foo {
564} 609}
565"#, 610"#,
566 expect![[r#" 611 expect![[r#"
567 field Field FileId(0) 26..35 26..31 Other 612 field Field FileId(0) 26..35 26..31
568 613
569 "#]], 614 "#]],
570 ); 615 );
@@ -605,10 +650,10 @@ fn f() {
605} 650}
606"#, 651"#,
607 expect![[r#" 652 expect![[r#"
608 Foo Struct FileId(1) 17..51 28..31 Other 653 Foo Struct FileId(1) 17..51 28..31
609 654
610 FileId(0) 53..56 StructLiteral 655 FileId(0) 53..56
611 FileId(2) 79..82 StructLiteral 656 FileId(2) 79..82
612 "#]], 657 "#]],
613 ); 658 );
614 } 659 }
@@ -635,9 +680,9 @@ pub struct Foo {
635} 680}
636"#, 681"#,
637 expect![[r#" 682 expect![[r#"
638 foo Module FileId(1) 0..35 Other 683 foo Module FileId(1) 0..35
639 684
640 FileId(0) 14..17 Other 685 FileId(0) 14..17
641 "#]], 686 "#]],
642 ); 687 );
643 } 688 }
@@ -663,10 +708,10 @@ pub(super) struct Foo$0 {
663} 708}
664"#, 709"#,
665 expect![[r#" 710 expect![[r#"
666 Foo Struct FileId(2) 0..41 18..21 Other 711 Foo Struct FileId(2) 0..41 18..21
667 712
668 FileId(1) 20..23 Other 713 FileId(1) 20..23
669 FileId(1) 47..50 StructLiteral 714 FileId(1) 47..50
670 "#]], 715 "#]],
671 ); 716 );
672 } 717 }
@@ -691,10 +736,10 @@ pub(super) struct Foo$0 {
691 code, 736 code,
692 None, 737 None,
693 expect![[r#" 738 expect![[r#"
694 quux Function FileId(0) 19..35 26..30 Other 739 quux Function FileId(0) 19..35 26..30
695 740
696 FileId(1) 16..20 StructLiteral 741 FileId(1) 16..20
697 FileId(2) 16..20 StructLiteral 742 FileId(2) 16..20
698 "#]], 743 "#]],
699 ); 744 );
700 745
@@ -702,9 +747,9 @@ pub(super) struct Foo$0 {
702 code, 747 code,
703 Some(SearchScope::single_file(FileId(2))), 748 Some(SearchScope::single_file(FileId(2))),
704 expect![[r#" 749 expect![[r#"
705 quux Function FileId(0) 19..35 26..30 Other 750 quux Function FileId(0) 19..35 26..30
706 751
707 FileId(2) 16..20 StructLiteral 752 FileId(2) 16..20
708 "#]], 753 "#]],
709 ); 754 );
710 } 755 }
@@ -722,10 +767,10 @@ fn foo() {
722} 767}
723"#, 768"#,
724 expect![[r#" 769 expect![[r#"
725 m1 Macro FileId(0) 0..46 29..31 Other 770 m1 Macro FileId(0) 0..46 29..31
726 771
727 FileId(0) 63..65 StructLiteral 772 FileId(0) 63..65
728 FileId(0) 73..75 StructLiteral 773 FileId(0) 73..75
729 "#]], 774 "#]],
730 ); 775 );
731 } 776 }
@@ -740,10 +785,10 @@ fn foo() {
740} 785}
741"#, 786"#,
742 expect![[r#" 787 expect![[r#"
743 i Local FileId(0) 19..24 23..24 Other Write 788 i Local FileId(0) 19..24 23..24 Write
744 789
745 FileId(0) 34..35 Other Write 790 FileId(0) 34..35 Write
746 FileId(0) 38..39 Other Read 791 FileId(0) 38..39 Read
747 "#]], 792 "#]],
748 ); 793 );
749 } 794 }
@@ -762,10 +807,10 @@ fn foo() {
762} 807}
763"#, 808"#,
764 expect![[r#" 809 expect![[r#"
765 f Field FileId(0) 15..21 15..16 Other 810 f Field FileId(0) 15..21 15..16
766 811
767 FileId(0) 55..56 RecordFieldExprOrPat Read 812 FileId(0) 55..56 Read
768 FileId(0) 68..69 Other Write 813 FileId(0) 68..69 Write
769 "#]], 814 "#]],
770 ); 815 );
771 } 816 }
@@ -780,9 +825,9 @@ fn foo() {
780} 825}
781"#, 826"#,
782 expect![[r#" 827 expect![[r#"
783 i Local FileId(0) 19..20 19..20 Other 828 i Local FileId(0) 19..20 19..20
784 829
785 FileId(0) 26..27 Other Write 830 FileId(0) 26..27 Write
786 "#]], 831 "#]],
787 ); 832 );
788 } 833 }
@@ -804,9 +849,9 @@ fn main() {
804} 849}
805"#, 850"#,
806 expect![[r#" 851 expect![[r#"
807 new Function FileId(0) 54..81 61..64 Other 852 new Function FileId(0) 54..81 61..64
808 853
809 FileId(0) 126..129 StructLiteral 854 FileId(0) 126..129
810 "#]], 855 "#]],
811 ); 856 );
812 } 857 }
@@ -826,10 +871,10 @@ use crate::f;
826fn g() { f(); } 871fn g() { f(); }
827"#, 872"#,
828 expect![[r#" 873 expect![[r#"
829 f Function FileId(0) 22..31 25..26 Other 874 f Function FileId(0) 22..31 25..26
830 875
831 FileId(1) 11..12 Other 876 FileId(1) 11..12
832 FileId(1) 24..25 StructLiteral 877 FileId(1) 24..25
833 "#]], 878 "#]],
834 ); 879 );
835 } 880 }
@@ -849,9 +894,9 @@ fn f(s: S) {
849} 894}
850"#, 895"#,
851 expect![[r#" 896 expect![[r#"
852 field Field FileId(0) 15..24 15..20 Other 897 field Field FileId(0) 15..24 15..20
853 898
854 FileId(0) 68..73 FieldShorthandForField Read 899 FileId(0) 68..73 Read
855 "#]], 900 "#]],
856 ); 901 );
857 } 902 }
@@ -873,9 +918,9 @@ fn f(e: En) {
873} 918}
874"#, 919"#,
875 expect![[r#" 920 expect![[r#"
876 field Field FileId(0) 32..41 32..37 Other 921 field Field FileId(0) 32..41 32..37
877 922
878 FileId(0) 102..107 FieldShorthandForField Read 923 FileId(0) 102..107 Read
879 "#]], 924 "#]],
880 ); 925 );
881 } 926 }
@@ -897,9 +942,9 @@ fn f() -> m::En {
897} 942}
898"#, 943"#,
899 expect![[r#" 944 expect![[r#"
900 field Field FileId(0) 56..65 56..61 Other 945 field Field FileId(0) 56..65 56..61
901 946
902 FileId(0) 125..130 RecordFieldExprOrPat Read 947 FileId(0) 125..130 Read
903 "#]], 948 "#]],
904 ); 949 );
905 } 950 }
@@ -922,10 +967,10 @@ impl Foo {
922} 967}
923"#, 968"#,
924 expect![[r#" 969 expect![[r#"
925 self SelfParam FileId(0) 47..51 47..51 SelfParam 970 self SelfParam FileId(0) 47..51 47..51
926 971
927 FileId(0) 71..75 Other Read 972 FileId(0) 71..75 Read
928 FileId(0) 152..156 Other Read 973 FileId(0) 152..156 Read
929 "#]], 974 "#]],
930 ); 975 );
931 } 976 }
@@ -943,9 +988,9 @@ impl Foo {
943} 988}
944"#, 989"#,
945 expect![[r#" 990 expect![[r#"
946 self SelfParam FileId(0) 47..51 47..51 SelfParam 991 self SelfParam FileId(0) 47..51 47..51
947 992
948 FileId(0) 63..67 Other Read 993 FileId(0) 63..67 Read
949 "#]], 994 "#]],
950 ); 995 );
951 } 996 }
@@ -961,7 +1006,7 @@ impl Foo {
961 let mut actual = String::new(); 1006 let mut actual = String::new();
962 { 1007 {
963 let decl = refs.declaration; 1008 let decl = refs.declaration;
964 format_to!(actual, "{} {:?}", decl.nav.debug_render(), decl.kind); 1009 format_to!(actual, "{}", decl.nav.debug_render());
965 if let Some(access) = decl.access { 1010 if let Some(access) = decl.access {
966 format_to!(actual, " {:?}", access) 1011 format_to!(actual, " {:?}", access)
967 } 1012 }
@@ -969,9 +1014,9 @@ impl Foo {
969 } 1014 }
970 1015
971 for (file_id, references) in refs.references { 1016 for (file_id, references) in refs.references {
972 for r in references { 1017 for (range, access) in references {
973 format_to!(actual, "{:?} {:?} {:?}", file_id, r.range, r.kind); 1018 format_to!(actual, "{:?} {:?}", file_id, range);
974 if let Some(access) = r.access { 1019 if let Some(access) = access {
975 format_to!(actual, " {:?}", access); 1020 format_to!(actual, " {:?}", access);
976 } 1021 }
977 actual += "\n"; 1022 actual += "\n";
@@ -992,13 +1037,13 @@ fn foo<'a, 'b: 'a>(x: &'a$0 ()) -> &'a () where &'a (): Foo<'a> {
992} 1037}
993"#, 1038"#,
994 expect![[r#" 1039 expect![[r#"
995 'a LifetimeParam FileId(0) 55..57 55..57 Lifetime 1040 'a LifetimeParam FileId(0) 55..57 55..57
996 1041
997 FileId(0) 63..65 Lifetime 1042 FileId(0) 63..65
998 FileId(0) 71..73 Lifetime 1043 FileId(0) 71..73
999 FileId(0) 82..84 Lifetime 1044 FileId(0) 82..84
1000 FileId(0) 95..97 Lifetime 1045 FileId(0) 95..97
1001 FileId(0) 106..108 Lifetime 1046 FileId(0) 106..108
1002 "#]], 1047 "#]],
1003 ); 1048 );
1004 } 1049 }
@@ -1010,10 +1055,10 @@ fn foo<'a, 'b: 'a>(x: &'a$0 ()) -> &'a () where &'a (): Foo<'a> {
1010type Foo<'a, T> where T: 'a$0 = &'a T; 1055type Foo<'a, T> where T: 'a$0 = &'a T;
1011"#, 1056"#,
1012 expect![[r#" 1057 expect![[r#"
1013 'a LifetimeParam FileId(0) 9..11 9..11 Lifetime 1058 'a LifetimeParam FileId(0) 9..11 9..11
1014 1059
1015 FileId(0) 25..27 Lifetime 1060 FileId(0) 25..27
1016 FileId(0) 31..33 Lifetime 1061 FileId(0) 31..33
1017 "#]], 1062 "#]],
1018 ); 1063 );
1019 } 1064 }
@@ -1032,11 +1077,11 @@ impl<'a> Foo<'a> for &'a () {
1032} 1077}
1033"#, 1078"#,
1034 expect![[r#" 1079 expect![[r#"
1035 'a LifetimeParam FileId(0) 47..49 47..49 Lifetime 1080 'a LifetimeParam FileId(0) 47..49 47..49
1036 1081
1037 FileId(0) 55..57 Lifetime 1082 FileId(0) 55..57
1038 FileId(0) 64..66 Lifetime 1083 FileId(0) 64..66
1039 FileId(0) 89..91 Lifetime 1084 FileId(0) 89..91
1040 "#]], 1085 "#]],
1041 ); 1086 );
1042 } 1087 }
@@ -1052,9 +1097,9 @@ fn main() {
1052} 1097}
1053"#, 1098"#,
1054 expect![[r#" 1099 expect![[r#"
1055 a Local FileId(0) 59..60 59..60 Other 1100 a Local FileId(0) 59..60 59..60
1056 1101
1057 FileId(0) 80..81 Other Read 1102 FileId(0) 80..81 Read
1058 "#]], 1103 "#]],
1059 ); 1104 );
1060 } 1105 }
@@ -1070,9 +1115,9 @@ fn main() {
1070} 1115}
1071"#, 1116"#,
1072 expect![[r#" 1117 expect![[r#"
1073 a Local FileId(0) 59..60 59..60 Other 1118 a Local FileId(0) 59..60 59..60
1074 1119
1075 FileId(0) 80..81 Other Read 1120 FileId(0) 80..81 Read
1076 "#]], 1121 "#]],
1077 ); 1122 );
1078 } 1123 }
@@ -1091,10 +1136,10 @@ fn foo<'a>() -> &'a () {
1091} 1136}
1092"#, 1137"#,
1093 expect![[r#" 1138 expect![[r#"
1094 'a Label FileId(0) 29..32 29..31 Lifetime 1139 'a Label FileId(0) 29..32 29..31
1095 1140
1096 FileId(0) 80..82 Lifetime 1141 FileId(0) 80..82
1097 FileId(0) 108..110 Lifetime 1142 FileId(0) 108..110
1098 "#]], 1143 "#]],
1099 ); 1144 );
1100 } 1145 }
@@ -1108,9 +1153,108 @@ fn foo<const FOO$0: usize>() -> usize {
1108} 1153}
1109"#, 1154"#,
1110 expect![[r#" 1155 expect![[r#"
1111 FOO ConstParam FileId(0) 7..23 13..16 Other 1156 FOO ConstParam FileId(0) 7..23 13..16
1157
1158 FileId(0) 42..45
1159 "#]],
1160 );
1161 }
1162
1163 #[test]
1164 fn test_find_self_ty_in_trait_def() {
1165 check(
1166 r#"
1167trait Foo {
1168 fn f() -> Self$0;
1169}
1170"#,
1171 expect![[r#"
1172 Self TypeParam FileId(0) 6..9 6..9
1173
1174 FileId(0) 26..30
1175 "#]],
1176 );
1177 }
1178
1179 #[test]
1180 fn test_self_variant_with_payload() {
1181 check(
1182 r#"
1183enum Foo { Bar() }
1184
1185impl Foo {
1186 fn foo(self) {
1187 match self {
1188 Self::Bar$0() => (),
1189 }
1190 }
1191}
1192
1193"#,
1194 expect![[r#"
1195 Bar Variant FileId(0) 11..16 11..14
1196
1197 FileId(0) 89..92
1198 "#]],
1199 );
1200 }
1201
1202 #[test]
1203 fn test_attr_differs_from_fn_with_same_name() {
1204 check(
1205 r#"
1206#[test]
1207fn test$0() {
1208 test();
1209}
1210"#,
1211 expect![[r#"
1212 test Function FileId(0) 0..33 11..15
1213
1214 FileId(0) 24..28
1215 "#]],
1216 );
1217 }
1218
1219 #[test]
1220 fn test_attr_matches_proc_macro_fn() {
1221 check(
1222 r#"
1223#[proc_macro_attribute]
1224fn my_proc_macro() {}
1225
1226#[my_proc_macro$0]
1227fn test() {}
1228"#,
1229 expect![[r#"
1230 my_proc_macro Function FileId(0) 0..45 27..40
1231
1232 FileId(0) 49..62
1233 "#]],
1234 );
1235 }
1236
1237 #[test]
1238 fn test_const_in_pattern() {
1239 check(
1240 r#"
1241const A$0: i32 = 42;
1242
1243fn main() {
1244 match A {
1245 A => (),
1246 _ => (),
1247 }
1248 if let A = A {}
1249}
1250"#,
1251 expect![[r#"
1252 A Const FileId(0) 0..18 6..7
1112 1253
1113 FileId(0) 42..45 Other 1254 FileId(0) 42..43
1255 FileId(0) 54..55
1256 FileId(0) 97..98
1257 FileId(0) 101..102
1114 "#]], 1258 "#]],
1115 ); 1259 );
1116 } 1260 }