@@ -18,7 +18,10 @@ use hir::InFile;
1818use once_cell:: unsync:: Lazy ;
1919use ra_db:: { SourceDatabase , SourceDatabaseExt } ;
2020use 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+ } ;
2225
2326use crate :: {
2427 db:: RootDatabase , display:: ToNav , FilePosition , FileRange , NavigationTarget , RangeInfo ,
@@ -35,15 +38,28 @@ pub use self::search_scope::SearchScope;
3538#[ derive( Debug , Clone ) ]
3639pub struct ReferenceSearchResult {
3740 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 ,
3955}
4056
4157impl ReferenceSearchResult {
4258 pub fn declaration ( & self ) -> & NavigationTarget {
4359 & self . declaration
4460 }
4561
46- pub fn references ( & self ) -> & [ FileRange ] {
62+ pub fn references ( & self ) -> & [ Reference ] {
4763 & self . references
4864 }
4965
@@ -58,24 +74,43 @@ impl ReferenceSearchResult {
5874// allow turning ReferenceSearchResult into an iterator
5975// over FileRanges
6076impl 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 > ;
6379
6480 fn into_iter ( mut self ) -> Self :: IntoIter {
6581 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+ } ) ;
6789 v. append ( & mut self . references ) ;
6890 v. into_iter ( )
6991 }
7092}
7193
7294pub ( crate ) fn find_all_refs (
7395 db : & RootDatabase ,
74- position : FilePosition ,
96+ mut position : FilePosition ,
7597 search_scope : Option < SearchScope > ,
7698) -> Option < RangeInfo < ReferenceSearchResult > > {
7799 let parse = db. parse ( position. file_id ) ;
78100 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+
79114 let RangeInfo { range, info : ( name, def) } = find_name ( db, & syntax, position) ?;
80115
81116 let declaration = match def. kind {
@@ -96,9 +131,15 @@ pub(crate) fn find_all_refs(
96131 }
97132 } ;
98133
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 ( ) ;
100138
101- Some ( RangeInfo :: new ( range, ReferenceSearchResult { declaration, references } ) )
139+ Some ( RangeInfo :: new (
140+ range,
141+ ReferenceSearchResult { declaration, references, declaration_kind : ReferenceKind :: Other } ,
142+ ) )
102143}
103144
104145fn find_name < ' a > (
@@ -122,7 +163,7 @@ fn process_definition(
122163 def : NameDefinition ,
123164 name : String ,
124165 scope : SearchScope ,
125- ) -> Vec < FileRange > {
166+ ) -> Vec < Reference > {
126167 let _p = profile ( "process_definition" ) ;
127168
128169 let pat = name. as_str ( ) ;
@@ -146,7 +187,21 @@ fn process_definition(
146187 }
147188 if let Some ( d) = classify_name_ref ( db, InFile :: new ( file_id. into ( ) , & name_ref) ) {
148189 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 } ) ;
150205 }
151206 }
152207 }
@@ -162,6 +217,24 @@ mod tests {
162217 ReferenceSearchResult , SearchScope ,
163218 } ;
164219
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+
165238 #[ test]
166239 fn test_find_all_refs_for_local ( ) {
167240 let code = r#"
0 commit comments