1- use std:: convert:: TryInto ;
1+ use std:: { convert:: TryInto , iter } ;
22
33use either:: Either ;
44use hir:: { AsAssocItem , InFile , ModuleDef , Semantics } ;
@@ -11,7 +11,7 @@ use ide_db::{
1111use syntax:: { ast, match_ast, AstNode , AstToken , SyntaxKind :: * , SyntaxToken , TextRange , T } ;
1212
1313use crate :: {
14- display:: TryToNav ,
14+ display:: { ToNav , TryToNav } ,
1515 doc_links:: { doc_attributes, extract_definitions_from_markdown, resolve_doc_path_for_def} ,
1616 FilePosition , NavigationTarget , RangeInfo ,
1717} ;
@@ -54,41 +54,44 @@ pub(crate) fn goto_definition(
5454 let nav = resolve_doc_path_for_def ( db, def, & link, ns) ?. try_to_nav ( db) ?;
5555 return Some ( RangeInfo :: new ( original_token. text_range ( ) , vec ! [ nav] ) ) ;
5656 }
57- let nav = match_ast ! {
57+
58+ let navs = match_ast ! {
5859 match parent {
5960 ast:: NameRef ( name_ref) => {
6061 reference_definition( & sema, Either :: Right ( & name_ref) )
6162 } ,
6263 ast:: Name ( name) => {
63- let def = match NameClass :: classify( & sema, & name) ? {
64- NameClass :: Definition ( it) | NameClass :: ConstReference ( it) => it,
65- NameClass :: PatFieldShorthand { local_def, field_ref: _ } => Definition :: Local ( local_def) ,
66- } ;
67- try_find_trait_item_definition( sema. db, & def) . or_else( || def. try_to_nav( sema. db) )
64+ match NameClass :: classify( & sema, & name) ? {
65+ NameClass :: Definition ( def) | NameClass :: ConstReference ( def) => {
66+ try_find_trait_item_definition( sema. db, & def) . unwrap_or_else( || def_to_nav( sema. db, def) )
67+ }
68+ NameClass :: PatFieldShorthand { local_def, field_ref } => {
69+ local_and_field_to_nav( sema. db, local_def, field_ref)
70+ } ,
71+ }
6872 } ,
6973 ast:: Lifetime ( lt) => if let Some ( name_class) = NameClass :: classify_lifetime( & sema, & lt) {
70- let def = match name_class {
71- NameClass :: Definition ( it) | NameClass :: ConstReference ( it) => it,
72- NameClass :: PatFieldShorthand { local_def, field_ref: _ } => Definition :: Local ( local_def) ,
73- } ;
74- def. try_to_nav( sema. db)
74+ match name_class {
75+ NameClass :: Definition ( def) => def_to_nav( sema. db, def) ,
76+ _ => return None ,
77+ }
7578 } else {
7679 reference_definition( & sema, Either :: Left ( & lt) )
7780 } ,
78- ast:: TokenTree ( tt) => try_lookup_include_path( sema. db, tt, token, position. file_id) ,
81+ ast:: TokenTree ( tt) => try_lookup_include_path( sema. db, tt, token, position. file_id) ? ,
7982 _ => return None ,
8083 }
8184 } ;
8285
83- Some ( RangeInfo :: new ( original_token. text_range ( ) , nav . into_iter ( ) . collect ( ) ) )
86+ Some ( RangeInfo :: new ( original_token. text_range ( ) , navs ) )
8487}
8588
8689fn try_lookup_include_path (
8790 db : & RootDatabase ,
8891 tt : ast:: TokenTree ,
8992 token : SyntaxToken ,
9093 file_id : FileId ,
91- ) -> Option < NavigationTarget > {
94+ ) -> Option < Vec < NavigationTarget > > {
9295 let path = ast:: String :: cast ( token) ?. value ( ) ?. into_owned ( ) ;
9396 let macro_call = tt. syntax ( ) . parent ( ) . and_then ( ast:: MacroCall :: cast) ?;
9497 let name = macro_call. path ( ) ?. segment ( ) ?. name_ref ( ) ?;
@@ -97,7 +100,7 @@ fn try_lookup_include_path(
97100 }
98101 let file_id = db. resolve_path ( AnchoredPath { anchor : file_id, path : & path } ) ?;
99102 let size = db. file_text ( file_id) . len ( ) . try_into ( ) . ok ( ) ?;
100- Some ( NavigationTarget {
103+ Some ( vec ! [ NavigationTarget {
101104 file_id,
102105 full_range: TextRange :: new( 0 . into( ) , size) ,
103106 name: path. into( ) ,
@@ -106,7 +109,7 @@ fn try_lookup_include_path(
106109 container_name: None ,
107110 description: None ,
108111 docs: None ,
109- } )
112+ } ] )
110113}
111114
112115/// finds the trait definition of an impl'd item
@@ -116,7 +119,10 @@ fn try_lookup_include_path(
116119/// struct S;
117120/// impl A for S { fn a(); } // <-- on this function, will get the location of a() in the trait
118121/// ```
119- fn try_find_trait_item_definition ( db : & RootDatabase , def : & Definition ) -> Option < NavigationTarget > {
122+ fn try_find_trait_item_definition (
123+ db : & RootDatabase ,
124+ def : & Definition ,
125+ ) -> Option < Vec < NavigationTarget > > {
120126 let name = def. name ( db) ?;
121127 let assoc = match def {
122128 Definition :: ModuleDef ( ModuleDef :: Function ( f) ) => f. as_assoc_item ( db) ,
@@ -135,40 +141,66 @@ fn try_find_trait_item_definition(db: &RootDatabase, def: &Definition) -> Option
135141 . items ( db)
136142 . iter ( )
137143 . find_map ( |itm| ( itm. name ( db) ? == name) . then ( || itm. try_to_nav ( db) ) . flatten ( ) )
144+ . map ( |it| vec ! [ it] )
138145}
139146
140147pub ( crate ) fn reference_definition (
141148 sema : & Semantics < RootDatabase > ,
142149 name_ref : Either < & ast:: Lifetime , & ast:: NameRef > ,
143- ) -> Option < NavigationTarget > {
144- let name_kind = name_ref. either (
150+ ) -> Vec < NavigationTarget > {
151+ let name_kind = match name_ref. either (
145152 |lifetime| NameRefClass :: classify_lifetime ( sema, lifetime) ,
146153 |name_ref| NameRefClass :: classify ( sema, name_ref) ,
147- ) ?;
148- let def = match name_kind {
149- NameRefClass :: Definition ( def) => def,
150- NameRefClass :: FieldShorthand { local_ref, field_ref : _ } => Definition :: Local ( local_ref) ,
154+ ) {
155+ Some ( class) => class,
156+ None => return Vec :: new ( ) ,
151157 } ;
152- def. try_to_nav ( sema. db )
158+ match name_kind {
159+ NameRefClass :: Definition ( def) => def_to_nav ( sema. db , def) ,
160+ NameRefClass :: FieldShorthand { local_ref, field_ref } => {
161+ local_and_field_to_nav ( sema. db , local_ref, field_ref)
162+ }
163+ }
164+ }
165+
166+ fn def_to_nav ( db : & RootDatabase , def : Definition ) -> Vec < NavigationTarget > {
167+ def. try_to_nav ( db) . map ( |it| vec ! [ it] ) . unwrap_or_default ( )
168+ }
169+
170+ fn local_and_field_to_nav (
171+ db : & RootDatabase ,
172+ local : hir:: Local ,
173+ field : hir:: Field ,
174+ ) -> Vec < NavigationTarget > {
175+ iter:: once ( local. to_nav ( db) ) . chain ( field. try_to_nav ( db) ) . collect ( )
153176}
154177
155178#[ cfg( test) ]
156179mod tests {
157180 use ide_db:: base_db:: FileRange ;
181+ use itertools:: Itertools ;
158182
159183 use crate :: fixture;
160184
161185 fn check ( ra_fixture : & str ) {
162- let ( analysis, position, expected) = fixture:: nav_target_annotation ( ra_fixture) ;
163- let mut navs =
164- analysis. goto_definition ( position) . unwrap ( ) . expect ( "no definition found" ) . info ;
186+ let ( analysis, position, expected) = fixture:: annotations ( ra_fixture) ;
187+ let navs = analysis. goto_definition ( position) . unwrap ( ) . expect ( "no definition found" ) . info ;
165188 if navs. len ( ) == 0 {
166189 panic ! ( "unresolved reference" )
167190 }
168- assert_eq ! ( navs. len( ) , 1 ) ;
169191
170- let nav = navs. pop ( ) . unwrap ( ) ;
171- assert_eq ! ( expected, FileRange { file_id: nav. file_id, range: nav. focus_or_full_range( ) } ) ;
192+ let cmp = |& FileRange { file_id, range } : & _ | ( file_id, range. start ( ) ) ;
193+ let navs = navs
194+ . into_iter ( )
195+ . map ( |nav| FileRange { file_id : nav. file_id , range : nav. focus_or_full_range ( ) } )
196+ . sorted_by_key ( cmp)
197+ . collect :: < Vec < _ > > ( ) ;
198+ let expected = expected
199+ . into_iter ( )
200+ . map ( |( FileRange { file_id, range } , _) | FileRange { file_id, range } )
201+ . sorted_by_key ( cmp)
202+ . collect :: < Vec < _ > > ( ) ;
203+ assert_eq ! ( expected, navs) ;
172204 }
173205
174206 fn check_unresolved ( ra_fixture : & str ) {
@@ -871,6 +903,7 @@ fn bar() {
871903 check (
872904 r#"
873905struct Foo { x: i32 }
906+ //^
874907fn main() {
875908 let x = 92;
876909 //^
@@ -886,6 +919,7 @@ fn main() {
886919 r#"
887920enum Foo {
888921 Bar { x: i32 }
922+ //^
889923}
890924fn baz(foo: Foo) {
891925 match foo {
@@ -1135,13 +1169,15 @@ fn foo<'foobar>(_: &'foobar ()) {
11351169 fn goto_lifetime_hrtb ( ) {
11361170 // FIXME: requires the HIR to somehow track these hrtb lifetimes
11371171 check_unresolved (
1138- r#"trait Foo<T> {}
1172+ r#"
1173+ trait Foo<T> {}
11391174fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {}
11401175 //^^
11411176"# ,
11421177 ) ;
11431178 check_unresolved (
1144- r#"trait Foo<T> {}
1179+ r#"
1180+ trait Foo<T> {}
11451181fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {}
11461182 //^^
11471183"# ,
0 commit comments