@@ -10,7 +10,10 @@ use syntax::{
1010 match_ast, SyntaxNode ,
1111} ;
1212
13- use crate :: { display:: ToNav , FileId , NavigationTarget } ;
13+ use crate :: {
14+ display:: { ToNav , TryToNav } ,
15+ FileId , NavigationTarget ,
16+ } ;
1417
1518#[ derive( Debug , Clone ) ]
1619pub struct Runnable {
@@ -101,117 +104,109 @@ pub(crate) fn runnable(
101104 item : SyntaxNode ,
102105 file_id : FileId ,
103106) -> Option < Runnable > {
104- match_ast ! {
105- match item {
106- ast:: Struct ( it) => runnable_struct( sema, it, file_id) ,
107+ let runnable_item = match_ast ! {
108+ match ( item. clone( ) ) {
107109 ast:: Fn ( it) => runnable_fn( sema, it, file_id) ,
108110 ast:: Module ( it) => runnable_mod( sema, it) ,
109111 _ => None ,
110112 }
111- }
113+ } ;
114+ runnable_item. or_else ( || runnable_doctest ( sema, item) )
112115}
113116
114117fn runnable_fn ( sema : & Semantics < RootDatabase > , func : ast:: Fn , file_id : FileId ) -> Option < Runnable > {
115118 let def = sema. to_def ( & func) ?;
116119 let name_string = func. name ( ) ?. text ( ) . to_string ( ) ;
117120
118- let attrs = def. attrs ( sema. db ) ;
119121 let kind = if name_string == "main" {
120122 RunnableKind :: Bin
121123 } else {
122- let test_id = match sema. to_def ( & func) . map ( |def| def. module ( sema. db ) ) {
123- Some ( module) => {
124- let def = sema. to_def ( & func) ?;
125- let impl_trait_name = def. as_assoc_item ( sema. db ) . and_then ( |assoc_item| {
126- match assoc_item. container ( sema. db ) {
127- hir:: AssocItemContainer :: Trait ( trait_item) => {
128- Some ( trait_item. name ( sema. db ) . to_string ( ) )
129- }
130- hir:: AssocItemContainer :: Impl ( impl_def) => impl_def
131- . target_ty ( sema. db )
132- . as_adt ( )
133- . map ( |adt| adt. name ( sema. db ) . to_string ( ) ) ,
134- }
135- } ) ;
136-
137- let path_iter = module
138- . path_to_root ( sema. db )
139- . into_iter ( )
140- . rev ( )
141- . filter_map ( |it| it. name ( sema. db ) )
142- . map ( |name| name. to_string ( ) ) ;
143-
144- let path = if let Some ( impl_trait_name) = impl_trait_name {
145- path_iter
146- . chain ( std:: iter:: once ( impl_trait_name) )
147- . chain ( std:: iter:: once ( name_string) )
148- . join ( "::" )
149- } else {
150- path_iter. chain ( std:: iter:: once ( name_string) ) . join ( "::" )
151- } ;
152-
153- TestId :: Path ( path)
154- }
155- None => TestId :: Name ( name_string) ,
156- } ;
124+ let canonical_path = sema. to_def ( & func) . and_then ( |def| {
125+ let def: hir:: ModuleDef = def. into ( ) ;
126+ def. canonical_path ( sema. db )
127+ } ) ;
128+ let test_id = canonical_path. map ( TestId :: Path ) . unwrap_or ( TestId :: Name ( name_string) ) ;
157129
158130 if test_related_attribute ( & func) . is_some ( ) {
159131 let attr = TestAttr :: from_fn ( & func) ;
160132 RunnableKind :: Test { test_id, attr }
161133 } else if func. has_atom_attr ( "bench" ) {
162134 RunnableKind :: Bench { test_id }
163- } else if has_runnable_doc_test ( & attrs) {
164- RunnableKind :: DocTest { test_id }
165135 } else {
166136 return None ;
167137 }
168138 } ;
169139
170- let nav = if let RunnableKind :: DocTest { .. } = kind {
171- NavigationTarget :: from_doc_commented (
172- sema. db ,
173- InFile :: new ( file_id. into ( ) , & func) ,
174- InFile :: new ( file_id. into ( ) , & func) ,
175- )
176- } else {
177- NavigationTarget :: from_named ( sema. db , InFile :: new ( file_id. into ( ) , & func) )
178- } ;
179- Some ( Runnable { nav, kind, cfg : attrs. cfg ( ) } )
140+ let nav = NavigationTarget :: from_named ( sema. db , InFile :: new ( file_id. into ( ) , & func) ) ;
141+ let cfg = def. attrs ( sema. db ) . cfg ( ) ;
142+ Some ( Runnable { nav, kind, cfg } )
180143}
181144
182- fn runnable_struct (
183- sema : & Semantics < RootDatabase > ,
184- strukt : ast:: Struct ,
185- file_id : FileId ,
186- ) -> Option < Runnable > {
187- let def = sema. to_def ( & strukt) ?;
188- let name_string = strukt. name ( ) ?. text ( ) . to_string ( ) ;
145+ fn runnable_doctest ( sema : & Semantics < RootDatabase > , item : SyntaxNode ) -> Option < Runnable > {
146+ match_ast ! {
147+ match item {
148+ ast:: Fn ( it) => module_def_doctest( sema, sema. to_def( & it) ?. into( ) ) ,
149+ ast:: Struct ( it) => module_def_doctest( sema, sema. to_def( & it) ?. into( ) ) ,
150+ ast:: Enum ( it) => module_def_doctest( sema, sema. to_def( & it) ?. into( ) ) ,
151+ ast:: Union ( it) => module_def_doctest( sema, sema. to_def( & it) ?. into( ) ) ,
152+ ast:: Trait ( it) => module_def_doctest( sema, sema. to_def( & it) ?. into( ) ) ,
153+ ast:: Const ( it) => module_def_doctest( sema, sema. to_def( & it) ?. into( ) ) ,
154+ ast:: Static ( it) => module_def_doctest( sema, sema. to_def( & it) ?. into( ) ) ,
155+ ast:: TypeAlias ( it) => module_def_doctest( sema, sema. to_def( & it) ?. into( ) ) ,
156+ _ => None ,
157+ }
158+ }
159+ }
189160
190- let attrs = def. attrs ( sema. db ) ;
161+ fn module_def_doctest ( sema : & Semantics < RootDatabase > , def : hir:: ModuleDef ) -> Option < Runnable > {
162+ let attrs = match def {
163+ hir:: ModuleDef :: Module ( it) => it. attrs ( sema. db ) ,
164+ hir:: ModuleDef :: Function ( it) => it. attrs ( sema. db ) ,
165+ hir:: ModuleDef :: Adt ( it) => it. attrs ( sema. db ) ,
166+ hir:: ModuleDef :: EnumVariant ( it) => it. attrs ( sema. db ) ,
167+ hir:: ModuleDef :: Const ( it) => it. attrs ( sema. db ) ,
168+ hir:: ModuleDef :: Static ( it) => it. attrs ( sema. db ) ,
169+ hir:: ModuleDef :: Trait ( it) => it. attrs ( sema. db ) ,
170+ hir:: ModuleDef :: TypeAlias ( it) => it. attrs ( sema. db ) ,
171+ hir:: ModuleDef :: BuiltinType ( _) => return None ,
172+ } ;
191173 if !has_runnable_doc_test ( & attrs) {
192174 return None ;
193175 }
194- let test_id = match sema. to_def ( & strukt) . map ( |def| def. module ( sema. db ) ) {
195- Some ( module) => {
196- let path_iter = module
197- . path_to_root ( sema. db )
198- . into_iter ( )
199- . rev ( )
200- . filter_map ( |it| it. name ( sema. db ) )
201- . map ( |name| name. to_string ( ) ) ;
202- let path = path_iter. chain ( std:: iter:: once ( name_string) ) . join ( "::" ) ;
203-
204- TestId :: Path ( path)
205- }
206- None => TestId :: Name ( name_string) ,
207- } ;
208-
209- let nav = NavigationTarget :: from_doc_commented (
210- sema. db ,
211- InFile :: new ( file_id. into ( ) , & strukt) ,
212- InFile :: new ( file_id. into ( ) , & strukt) ,
213- ) ;
214- Some ( Runnable { nav, kind : RunnableKind :: DocTest { test_id } , cfg : attrs. cfg ( ) } )
176+ let def_name = def. name ( sema. db ) . map ( |it| it. to_string ( ) ) ;
177+ let test_id = def
178+ . canonical_path ( sema. db )
179+ // This probably belongs to canonical path?
180+ . map ( |path| {
181+ let assoc_def = match def {
182+ hir:: ModuleDef :: Function ( it) => it. as_assoc_item ( sema. db ) ,
183+ hir:: ModuleDef :: Const ( it) => it. as_assoc_item ( sema. db ) ,
184+ hir:: ModuleDef :: TypeAlias ( it) => it. as_assoc_item ( sema. db ) ,
185+ _ => None ,
186+ } ;
187+ // FIXME: this also looks very wrong
188+ if let Some ( assoc_def) = assoc_def {
189+ if let hir:: AssocItemContainer :: Impl ( imp) = assoc_def. container ( sema. db ) {
190+ if let Some ( adt) = imp. target_ty ( sema. db ) . as_adt ( ) {
191+ let name = adt. name ( sema. db ) . to_string ( ) ;
192+ let idx = path. rfind ( ':' ) . unwrap_or ( 0 ) ;
193+ let ( prefix, suffix) = path. split_at ( idx) ;
194+ return format ! ( "{}{}::{}" , prefix, name, suffix) ;
195+ }
196+ }
197+ }
198+ path
199+ } )
200+ . map ( TestId :: Path )
201+ . or_else ( || def_name. clone ( ) . map ( TestId :: Name ) ) ?;
202+
203+ let mut nav = def. try_to_nav ( sema. db ) ?;
204+ nav. focus_range = None ;
205+ nav. description = None ;
206+ nav. docs = None ;
207+ nav. kind = syntax:: SyntaxKind :: COMMENT ;
208+ let res = Runnable { nav, kind : RunnableKind :: DocTest { test_id } , cfg : attrs. cfg ( ) } ;
209+ Some ( res)
215210}
216211
217212#[ derive( Debug , Copy , Clone ) ]
@@ -309,7 +304,7 @@ mod tests {
309304
310305 use crate :: fixture;
311306
312- use super :: { RunnableAction , BENCH , BIN , DOCTEST , TEST } ;
307+ use super :: * ;
313308
314309 fn check (
315310 ra_fixture : & str ,
@@ -538,7 +533,7 @@ struct StructWithRunnable(String);
538533 full_range: 15..74,
539534 focus_range: None,
540535 name: "should_have_runnable",
541- kind: FN ,
536+ kind: COMMENT ,
542537 container_name: None,
543538 description: None,
544539 docs: None,
@@ -558,7 +553,7 @@ struct StructWithRunnable(String);
558553 full_range: 76..148,
559554 focus_range: None,
560555 name: "should_have_runnable_1",
561- kind: FN ,
556+ kind: COMMENT ,
562557 container_name: None,
563558 description: None,
564559 docs: None,
@@ -578,7 +573,7 @@ struct StructWithRunnable(String);
578573 full_range: 150..254,
579574 focus_range: None,
580575 name: "should_have_runnable_2",
581- kind: FN ,
576+ kind: COMMENT ,
582577 container_name: None,
583578 description: None,
584579 docs: None,
@@ -598,7 +593,7 @@ struct StructWithRunnable(String);
598593 full_range: 756..821,
599594 focus_range: None,
600595 name: "StructWithRunnable",
601- kind: STRUCT ,
596+ kind: COMMENT ,
602597 container_name: None,
603598 description: None,
604599 docs: None,
@@ -660,7 +655,7 @@ impl Data {
660655 full_range: 44..98,
661656 focus_range: None,
662657 name: "foo",
663- kind: FN ,
658+ kind: COMMENT ,
664659 container_name: None,
665660 description: None,
666661 docs: None,
0 commit comments