@@ -21,7 +21,7 @@ use ide_db::{
2121use syntax:: {
2222 algo:: find_node_at_offset,
2323 ast:: { self , NameOwner } ,
24- AstNode , SyntaxKind , SyntaxNode , TextRange , TokenAtOffset ,
24+ match_ast , AstNode , SyntaxKind , SyntaxNode , TextRange , TokenAtOffset ,
2525} ;
2626
2727use crate :: { display:: TryToNav , FilePosition , FileRange , NavigationTarget , RangeInfo } ;
@@ -89,6 +89,10 @@ pub(crate) fn find_all_refs(
8989 let _p = profile:: span ( "find_all_refs" ) ;
9090 let syntax = sema. parse ( position. file_id ) . syntax ( ) . clone ( ) ;
9191
92+ if let Some ( res) = try_find_self_references ( & syntax, position) {
93+ return Some ( res) ;
94+ }
95+
9296 let ( opt_name, search_kind) = if let Some ( name) =
9397 get_struct_def_name_for_struct_literal_search ( & sema, & syntax, position)
9498 {
@@ -194,6 +198,77 @@ fn get_struct_def_name_for_struct_literal_search(
194198 None
195199}
196200
201+ fn try_find_self_references (
202+ syntax : & SyntaxNode ,
203+ position : FilePosition ,
204+ ) -> Option < RangeInfo < ReferenceSearchResult > > {
205+ let self_token =
206+ syntax. token_at_offset ( position. offset ) . find ( |t| t. kind ( ) == SyntaxKind :: SELF_KW ) ?;
207+ let parent = self_token. parent ( ) ;
208+ match_ast ! {
209+ match parent {
210+ ast:: SelfParam ( it) => ( ) ,
211+ ast:: PathSegment ( segment) => {
212+ segment. self_token( ) ?;
213+ let path = segment. parent_path( ) ;
214+ if path. qualifier( ) . is_some( ) && !ast:: PathExpr :: can_cast( path. syntax( ) . parent( ) ?. kind( ) ) {
215+ return None ;
216+ }
217+ } ,
218+ _ => return None ,
219+ }
220+ } ;
221+ let function = parent. ancestors ( ) . find_map ( ast:: Fn :: cast) ?;
222+ let self_param = function. param_list ( ) ?. self_param ( ) ?;
223+ let param_self_token = self_param. self_token ( ) ?;
224+
225+ let declaration = Declaration {
226+ nav : NavigationTarget {
227+ file_id : position. file_id ,
228+ full_range : self_param. syntax ( ) . text_range ( ) ,
229+ focus_range : Some ( param_self_token. text_range ( ) ) ,
230+ name : param_self_token. text ( ) . clone ( ) ,
231+ kind : param_self_token. kind ( ) ,
232+ container_name : None ,
233+ description : None ,
234+ docs : None ,
235+ } ,
236+ kind : ReferenceKind :: SelfKw ,
237+ access : Some ( if self_param. mut_token ( ) . is_some ( ) {
238+ ReferenceAccess :: Write
239+ } else {
240+ ReferenceAccess :: Read
241+ } ) ,
242+ } ;
243+ let references = function
244+ . body ( )
245+ . map ( |body| {
246+ body. syntax ( )
247+ . descendants ( )
248+ . filter_map ( ast:: PathExpr :: cast)
249+ . filter_map ( |expr| {
250+ let path = expr. path ( ) ?;
251+ if path. qualifier ( ) . is_none ( ) {
252+ path. segment ( ) ?. self_token ( )
253+ } else {
254+ None
255+ }
256+ } )
257+ . map ( |token| Reference {
258+ file_range : FileRange { file_id : position. file_id , range : token. text_range ( ) } ,
259+ kind : ReferenceKind :: SelfKw ,
260+ access : declaration. access , // FIXME: properly check access kind here instead of copying it from the declaration
261+ } )
262+ . collect ( )
263+ } )
264+ . unwrap_or_default ( ) ;
265+
266+ Some ( RangeInfo :: new (
267+ param_self_token. text_range ( ) ,
268+ ReferenceSearchResult { declaration, references } ,
269+ ) )
270+ }
271+
197272#[ cfg( test) ]
198273mod tests {
199274 use expect_test:: { expect, Expect } ;
@@ -762,6 +837,32 @@ fn f() -> m::En {
762837 ) ;
763838 }
764839
840+ #[ test]
841+ fn test_find_self_refs ( ) {
842+ check (
843+ r#"
844+ struct Foo { bar: i32 }
845+
846+ impl Foo {
847+ fn foo(self) {
848+ let x = self<|>.bar;
849+ if true {
850+ let _ = match () {
851+ () => self,
852+ };
853+ }
854+ }
855+ }
856+ "# ,
857+ expect ! [ [ r#"
858+ self SELF_KW FileId(0) 47..51 47..51 SelfKw Read
859+
860+ FileId(0) 71..75 SelfKw Read
861+ FileId(0) 152..156 SelfKw Read
862+ "# ] ] ,
863+ ) ;
864+ }
865+
765866 fn check ( ra_fixture : & str , expect : Expect ) {
766867 check_with_scope ( ra_fixture, None , expect)
767868 }
0 commit comments