@@ -18,7 +18,10 @@ use hir::InFile;
18
18
use once_cell:: unsync:: Lazy ;
19
19
use ra_db:: { SourceDatabase , SourceDatabaseExt } ;
20
20
use ra_prof:: profile;
21
- use ra_syntax:: { algo:: find_node_at_offset, ast, AstNode , SourceFile , SyntaxNode , TextUnit } ;
21
+ use ra_syntax:: {
22
+ algo:: find_node_at_offset, ast, AstNode , SourceFile , SyntaxKind , SyntaxNode , TextUnit ,
23
+ TokenAtOffset ,
24
+ } ;
22
25
23
26
use crate :: {
24
27
db:: RootDatabase , display:: ToNav , FilePosition , FileRange , NavigationTarget , RangeInfo ,
@@ -35,15 +38,28 @@ pub use self::search_scope::SearchScope;
35
38
#[ derive( Debug , Clone ) ]
36
39
pub struct ReferenceSearchResult {
37
40
declaration : NavigationTarget ,
38
- references : Vec < FileRange > ,
41
+ declaration_kind : ReferenceKind ,
42
+ references : Vec < Reference > ,
43
+ }
44
+
45
+ #[ derive( Debug , Clone ) ]
46
+ pub struct Reference {
47
+ pub file_range : FileRange ,
48
+ pub kind : ReferenceKind ,
49
+ }
50
+
51
+ #[ derive( Debug , Clone , PartialEq ) ]
52
+ pub enum ReferenceKind {
53
+ StructLiteral ,
54
+ Other ,
39
55
}
40
56
41
57
impl ReferenceSearchResult {
42
58
pub fn declaration ( & self ) -> & NavigationTarget {
43
59
& self . declaration
44
60
}
45
61
46
- pub fn references ( & self ) -> & [ FileRange ] {
62
+ pub fn references ( & self ) -> & [ Reference ] {
47
63
& self . references
48
64
}
49
65
@@ -58,24 +74,43 @@ impl ReferenceSearchResult {
58
74
// allow turning ReferenceSearchResult into an iterator
59
75
// over FileRanges
60
76
impl IntoIterator for ReferenceSearchResult {
61
- type Item = FileRange ;
62
- type IntoIter = std:: vec:: IntoIter < FileRange > ;
77
+ type Item = Reference ;
78
+ type IntoIter = std:: vec:: IntoIter < Reference > ;
63
79
64
80
fn into_iter ( mut self ) -> Self :: IntoIter {
65
81
let mut v = Vec :: with_capacity ( self . len ( ) ) ;
66
- v. push ( FileRange { file_id : self . declaration . file_id ( ) , range : self . declaration . range ( ) } ) ;
82
+ v. push ( Reference {
83
+ file_range : FileRange {
84
+ file_id : self . declaration . file_id ( ) ,
85
+ range : self . declaration . range ( ) ,
86
+ } ,
87
+ kind : self . declaration_kind ,
88
+ } ) ;
67
89
v. append ( & mut self . references ) ;
68
90
v. into_iter ( )
69
91
}
70
92
}
71
93
72
94
pub ( crate ) fn find_all_refs (
73
95
db : & RootDatabase ,
74
- position : FilePosition ,
96
+ mut position : FilePosition ,
75
97
search_scope : Option < SearchScope > ,
76
98
) -> Option < RangeInfo < ReferenceSearchResult > > {
77
99
let parse = db. parse ( position. file_id ) ;
78
100
let syntax = parse. tree ( ) . syntax ( ) . clone ( ) ;
101
+
102
+ let token = syntax. token_at_offset ( position. offset ) ;
103
+ let mut search_kind = ReferenceKind :: Other ;
104
+
105
+ if let TokenAtOffset :: Between ( ref left, ref right) = token {
106
+ if ( right. kind ( ) == SyntaxKind :: L_CURLY || right. kind ( ) == SyntaxKind :: L_PAREN )
107
+ && left. kind ( ) != SyntaxKind :: IDENT
108
+ {
109
+ position = FilePosition { offset : left. text_range ( ) . start ( ) , ..position } ;
110
+ search_kind = ReferenceKind :: StructLiteral ;
111
+ }
112
+ }
113
+
79
114
let RangeInfo { range, info : ( name, def) } = find_name ( db, & syntax, position) ?;
80
115
81
116
let declaration = match def. kind {
@@ -96,9 +131,15 @@ pub(crate) fn find_all_refs(
96
131
}
97
132
} ;
98
133
99
- let references = process_definition ( db, def, name, search_scope) ;
134
+ let references = process_definition ( db, def, name, search_scope)
135
+ . into_iter ( )
136
+ . filter ( |r| search_kind == ReferenceKind :: Other || search_kind == r. kind )
137
+ . collect ( ) ;
100
138
101
- Some ( RangeInfo :: new ( range, ReferenceSearchResult { declaration, references } ) )
139
+ Some ( RangeInfo :: new (
140
+ range,
141
+ ReferenceSearchResult { declaration, references, declaration_kind : ReferenceKind :: Other } ,
142
+ ) )
102
143
}
103
144
104
145
fn find_name < ' a > (
@@ -122,7 +163,7 @@ fn process_definition(
122
163
def : NameDefinition ,
123
164
name : String ,
124
165
scope : SearchScope ,
125
- ) -> Vec < FileRange > {
166
+ ) -> Vec < Reference > {
126
167
let _p = profile ( "process_definition" ) ;
127
168
128
169
let pat = name. as_str ( ) ;
@@ -146,7 +187,21 @@ fn process_definition(
146
187
}
147
188
if let Some ( d) = classify_name_ref ( db, InFile :: new ( file_id. into ( ) , & name_ref) ) {
148
189
if d == def {
149
- refs. push ( FileRange { file_id, range } ) ;
190
+ let kind = if name_ref
191
+ . syntax ( )
192
+ . ancestors ( )
193
+ . find_map ( ast:: RecordLit :: cast)
194
+ . and_then ( |l| l. path ( ) )
195
+ . and_then ( |p| p. segment ( ) )
196
+ . and_then ( |p| p. name_ref ( ) )
197
+ . map ( |n| n == name_ref)
198
+ . unwrap_or ( false )
199
+ {
200
+ ReferenceKind :: StructLiteral
201
+ } else {
202
+ ReferenceKind :: Other
203
+ } ;
204
+ refs. push ( Reference { file_range : FileRange { file_id, range } , kind } ) ;
150
205
}
151
206
}
152
207
}
@@ -162,6 +217,24 @@ mod tests {
162
217
ReferenceSearchResult , SearchScope ,
163
218
} ;
164
219
220
+ #[ test]
221
+ fn test_struct_literal ( ) {
222
+ let code = r#"
223
+ struct Foo <|>{
224
+ a: i32,
225
+ }
226
+ impl Foo {
227
+ fn f() -> i32 { 42 }
228
+ }
229
+ fn main() {
230
+ let f: Foo;
231
+ f = Foo {a: Foo::f()};
232
+ }"# ;
233
+
234
+ let refs = get_all_refs ( code) ;
235
+ assert_eq ! ( refs. len( ) , 2 ) ;
236
+ }
237
+
165
238
#[ test]
166
239
fn test_find_all_refs_for_local ( ) {
167
240
let code = r#"
0 commit comments