99//! at the index that the match starts at and its tree parent is
1010//! resolved to the search element definition, we get a reference.
1111
12+ use std:: iter;
13+
14+ use either:: Either ;
1215use hir:: { PathResolution , Semantics } ;
1316use ide_db:: {
1417 base_db:: FileId ,
@@ -52,76 +55,91 @@ pub(crate) fn find_all_refs(
5255 sema : & Semantics < RootDatabase > ,
5356 position : FilePosition ,
5457 search_scope : Option < SearchScope > ,
55- ) -> Option < ReferenceSearchResult > {
58+ ) -> Option < Vec < ReferenceSearchResult > > {
5659 let _p = profile:: span ( "find_all_refs" ) ;
5760 let syntax = sema. parse ( position. file_id ) . syntax ( ) . clone ( ) ;
5861
5962 let mut is_literal_search = false ;
60- let def = if let Some ( name) = name_for_constructor_search ( & syntax, position) {
61- is_literal_search = true ;
62- match NameClass :: classify ( sema, & name) ? {
63- NameClass :: Definition ( it) | NameClass :: ConstReference ( it) => it,
64- NameClass :: PatFieldShorthand { local_def : _, field_ref } => {
65- Definition :: Field ( field_ref)
66- }
63+ let defs = match name_for_constructor_search ( & syntax, position) {
64+ Some ( name) => {
65+ is_literal_search = true ;
66+ let def = match NameClass :: classify ( sema, & name) ? {
67+ NameClass :: Definition ( it) | NameClass :: ConstReference ( it) => it,
68+ NameClass :: PatFieldShorthand { local_def : _, field_ref } => {
69+ Definition :: Field ( field_ref)
70+ }
71+ } ;
72+ Either :: Left ( iter:: once ( def) )
6773 }
68- } else {
69- find_def ( sema, & syntax, position. offset ) ?
74+ None => Either :: Right ( find_defs ( sema, & syntax, position. offset ) ) ,
7075 } ;
7176
72- let mut usages = def. usages ( sema) . set_scope ( search_scope) . include_self_refs ( ) . all ( ) ;
73- let declaration = match def {
74- Definition :: ModuleDef ( hir:: ModuleDef :: Module ( module) ) => {
75- Some ( NavigationTarget :: from_module_to_decl ( sema. db , module) )
76- }
77- def => def. try_to_nav ( sema. db ) ,
78- }
79- . map ( |nav| {
80- let decl_range = nav. focus_or_full_range ( ) ;
81- Declaration { nav, access : decl_access ( & def, & syntax, decl_range) }
82- } ) ;
83- if is_literal_search {
84- retain_adt_literal_usages ( & mut usages, def, sema) ;
85- }
86-
87- let references = usages
88- . into_iter ( )
89- . map ( |( file_id, refs) | {
90- ( file_id, refs. into_iter ( ) . map ( |file_ref| ( file_ref. range , file_ref. access ) ) . collect ( ) )
91- } )
92- . collect ( ) ;
77+ Some (
78+ defs. into_iter ( )
79+ . map ( |def| {
80+ let mut usages =
81+ def. usages ( sema) . set_scope ( search_scope. clone ( ) ) . include_self_refs ( ) . all ( ) ;
82+ let declaration = match def {
83+ Definition :: ModuleDef ( hir:: ModuleDef :: Module ( module) ) => {
84+ Some ( NavigationTarget :: from_module_to_decl ( sema. db , module) )
85+ }
86+ def => def. try_to_nav ( sema. db ) ,
87+ }
88+ . map ( |nav| {
89+ let decl_range = nav. focus_or_full_range ( ) ;
90+ Declaration { nav, access : decl_access ( & def, & syntax, decl_range) }
91+ } ) ;
92+ if is_literal_search {
93+ retain_adt_literal_usages ( & mut usages, def, sema) ;
94+ }
9395
94- Some ( ReferenceSearchResult { declaration, references } )
96+ let references = usages
97+ . into_iter ( )
98+ . map ( |( file_id, refs) | {
99+ (
100+ file_id,
101+ refs. into_iter ( )
102+ . map ( |file_ref| ( file_ref. range , file_ref. access ) )
103+ . collect ( ) ,
104+ )
105+ } )
106+ . collect ( ) ;
107+
108+ ReferenceSearchResult { declaration, references }
109+ } )
110+ . collect ( ) ,
111+ )
95112}
96113
97- pub ( crate ) fn find_def (
98- sema : & Semantics < RootDatabase > ,
114+ pub ( crate ) fn find_defs < ' a > (
115+ sema : & ' a Semantics < RootDatabase > ,
99116 syntax : & SyntaxNode ,
100117 offset : TextSize ,
101- ) -> Option < Definition > {
102- let def = match sema. find_node_at_offset_with_descend ( syntax, offset) ? {
103- ast:: NameLike :: NameRef ( name_ref) => match NameRefClass :: classify ( sema, & name_ref) ? {
104- NameRefClass :: Definition ( def) => def,
105- NameRefClass :: FieldShorthand { local_ref, field_ref : _ } => {
106- Definition :: Local ( local_ref)
107- }
108- } ,
109- ast:: NameLike :: Name ( name) => match NameClass :: classify ( sema, & name) ? {
110- NameClass :: Definition ( it) | NameClass :: ConstReference ( it) => it,
111- NameClass :: PatFieldShorthand { local_def, field_ref : _ } => {
112- Definition :: Local ( local_def)
113- }
114- } ,
115- ast:: NameLike :: Lifetime ( lifetime) => NameRefClass :: classify_lifetime ( sema, & lifetime)
116- . and_then ( |class| match class {
117- NameRefClass :: Definition ( it) => Some ( it) ,
118- _ => None ,
119- } )
120- . or_else ( || {
121- NameClass :: classify_lifetime ( sema, & lifetime) . and_then ( NameClass :: defined)
122- } ) ?,
123- } ;
124- Some ( def)
118+ ) -> impl Iterator < Item = Definition > + ' a {
119+ sema. find_nodes_at_offset_with_descend ( syntax, offset) . filter_map ( move |node| {
120+ Some ( match node {
121+ ast:: NameLike :: NameRef ( name_ref) => match NameRefClass :: classify ( sema, & name_ref) ? {
122+ NameRefClass :: Definition ( def) => def,
123+ NameRefClass :: FieldShorthand { local_ref, field_ref : _ } => {
124+ Definition :: Local ( local_ref)
125+ }
126+ } ,
127+ ast:: NameLike :: Name ( name) => match NameClass :: classify ( sema, & name) ? {
128+ NameClass :: Definition ( it) | NameClass :: ConstReference ( it) => it,
129+ NameClass :: PatFieldShorthand { local_def, field_ref : _ } => {
130+ Definition :: Local ( local_def)
131+ }
132+ } ,
133+ ast:: NameLike :: Lifetime ( lifetime) => NameRefClass :: classify_lifetime ( sema, & lifetime)
134+ . and_then ( |class| match class {
135+ NameRefClass :: Definition ( it) => Some ( it) ,
136+ _ => None ,
137+ } )
138+ . or_else ( || {
139+ NameClass :: classify_lifetime ( sema, & lifetime) . and_then ( NameClass :: defined)
140+ } ) ?,
141+ } )
142+ } )
125143}
126144
127145pub ( crate ) fn decl_access (
@@ -609,6 +627,7 @@ impl Foo {
609627 expect ! [ [ r#"
610628 f Function FileId(0) 27..43 30..31
611629
630+ (no references)
612631 "# ] ] ,
613632 ) ;
614633 }
@@ -626,6 +645,7 @@ enum Foo {
626645 expect ! [ [ r#"
627646 B Variant FileId(0) 22..23 22..23
628647
648+ (no references)
629649 "# ] ] ,
630650 ) ;
631651 }
@@ -643,6 +663,7 @@ enum Foo {
643663 expect ! [ [ r#"
644664 field Field FileId(0) 26..35 26..31
645665
666+ (no references)
646667 "# ] ] ,
647668 ) ;
648669 }
@@ -744,6 +765,7 @@ use self$0;
744765 expect ! [ [ r#"
745766 Module FileId(0) 0..10
746767
768+ (no references)
747769 "# ] ] ,
748770 ) ;
749771 }
@@ -1065,21 +1087,29 @@ impl Foo {
10651087 let refs = analysis. find_all_refs ( pos, search_scope) . unwrap ( ) . unwrap ( ) ;
10661088
10671089 let mut actual = String :: new ( ) ;
1068- if let Some ( decl) = refs. declaration {
1069- format_to ! ( actual, "{}" , decl. nav. debug_render( ) ) ;
1070- if let Some ( access) = decl. access {
1071- format_to ! ( actual, " {:?}" , access)
1072- }
1090+ for refs in refs {
10731091 actual += "\n \n " ;
1074- }
10751092
1076- for ( file_id, references) in refs. references {
1077- for ( range, access) in references {
1078- format_to ! ( actual, "{:?} {:?}" , file_id, range) ;
1079- if let Some ( access) = access {
1080- format_to ! ( actual, " {:?}" , access) ;
1093+ if let Some ( decl) = refs. declaration {
1094+ format_to ! ( actual, "{}" , decl. nav. debug_render( ) ) ;
1095+ if let Some ( access) = decl. access {
1096+ format_to ! ( actual, " {:?}" , access)
10811097 }
1082- actual += "\n " ;
1098+ actual += "\n \n " ;
1099+ }
1100+
1101+ for ( file_id, references) in & refs. references {
1102+ for ( range, access) in references {
1103+ format_to ! ( actual, "{:?} {:?}" , file_id, range) ;
1104+ if let Some ( access) = access {
1105+ format_to ! ( actual, " {:?}" , access) ;
1106+ }
1107+ actual += "\n " ;
1108+ }
1109+ }
1110+
1111+ if refs. references . is_empty ( ) {
1112+ actual += "(no references)\n " ;
10831113 }
10841114 }
10851115 expect. assert_eq ( actual. trim_start ( ) )
@@ -1440,4 +1470,38 @@ m$0!();
14401470 "# ] ] ,
14411471 ) ;
14421472 }
1473+
1474+ #[ test]
1475+ fn multi_def ( ) {
1476+ check (
1477+ r#"
1478+ macro_rules! m {
1479+ ($name:ident) => {
1480+ mod module {
1481+ pub fn $name() {}
1482+ }
1483+
1484+ pub fn $name() {}
1485+ }
1486+ }
1487+
1488+ m!(func$0);
1489+
1490+ fn f() {
1491+ func();
1492+ module::func();
1493+ }
1494+ "# ,
1495+ expect ! [ [ r#"
1496+ func Function FileId(0) 137..146 140..144
1497+
1498+ FileId(0) 161..165
1499+
1500+
1501+ func Function FileId(0) 137..146 140..144
1502+
1503+ FileId(0) 181..185
1504+ "# ] ] ,
1505+ )
1506+ }
14431507}
0 commit comments