88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11- use std:: cell:: Cell ;
1211use std:: env;
1312use std:: ffi:: OsString ;
1413use std:: io:: prelude:: * ;
@@ -23,7 +22,8 @@ use std::sync::{Arc, Mutex};
2322use testing;
2423use rustc_lint;
2524use rustc:: dep_graph:: DepGraph ;
26- use rustc:: hir:: map as hir_map;
25+ use rustc:: hir;
26+ use rustc:: hir:: intravisit;
2727use rustc:: session:: { self , config} ;
2828use rustc:: session:: config:: { OutputType , OutputTypes , Externs } ;
2929use rustc:: session:: search_paths:: { SearchPaths , PathKind } ;
@@ -33,18 +33,15 @@ use rustc_driver::{driver, Compilation};
3333use rustc_driver:: driver:: phase_2_configure_and_expand;
3434use rustc_metadata:: cstore:: CStore ;
3535use rustc_resolve:: MakeGlobMap ;
36+ use rustc_trans:: back:: link;
37+ use syntax:: ast;
3638use syntax:: codemap:: CodeMap ;
3739use syntax:: feature_gate:: UnstableFeatures ;
3840use errors;
3941use errors:: emitter:: ColorConfig ;
4042
41- use core;
42- use clean;
43- use clean:: Clean ;
44- use fold:: DocFolder ;
43+ use clean:: Attributes ;
4544use html:: markdown;
46- use passes;
47- use visit_ast:: RustdocVisitor ;
4845
4946#[ derive( Clone , Default ) ]
5047pub struct TestOptions {
@@ -87,48 +84,36 @@ pub fn run(input: &str,
8784 config:: build_configuration ( & sess, config:: parse_cfgspecs ( cfgs. clone ( ) ) ) ;
8885
8986 let krate = panictry ! ( driver:: phase_1_parse_input( & sess, & input) ) ;
90- let driver:: ExpansionResult { defs, mut hir_forest, analysis , .. } = {
87+ let driver:: ExpansionResult { defs, mut hir_forest, .. } = {
9188 phase_2_configure_and_expand (
9289 & sess, & cstore, krate, None , "rustdoc-test" , None , MakeGlobMap :: No , |_| Ok ( ( ) )
9390 ) . expect ( "phase_2_configure_and_expand aborted in rustdoc!" )
9491 } ;
9592
96- let dep_graph = DepGraph :: new ( false ) ;
93+ let crate_name = crate_name. unwrap_or_else ( || {
94+ link:: find_crate_name ( None , & hir_forest. krate ( ) . attrs , & input)
95+ } ) ;
9796 let opts = scrape_test_config ( hir_forest. krate ( ) ) ;
98- let _ignore = dep_graph. in_ignore ( ) ;
99- let map = hir_map:: map_crate ( & mut hir_forest, defs) ;
100-
101- let ctx = core:: DocContext {
102- map : & map,
103- maybe_typed : core:: NotTyped ( & sess) ,
104- input : input,
105- populated_all_crate_impls : Cell :: new ( false ) ,
106- external_traits : Default :: default ( ) ,
107- deref_trait_did : Cell :: new ( None ) ,
108- deref_mut_trait_did : Cell :: new ( None ) ,
109- access_levels : Default :: default ( ) ,
110- renderinfo : Default :: default ( ) ,
111- ty_substs : Default :: default ( ) ,
112- lt_substs : Default :: default ( ) ,
113- export_map : analysis. export_map ,
114- } ;
115-
116- let mut v = RustdocVisitor :: new ( & ctx) ;
117- v. visit ( ctx. map . krate ( ) ) ;
118- let mut krate = v. clean ( & ctx) ;
119- if let Some ( name) = crate_name {
120- krate. name = name;
121- }
122- let krate = passes:: collapse_docs ( krate) ;
123- let krate = passes:: unindent_comments ( krate) ;
124-
125- let mut collector = Collector :: new ( krate. name . to_string ( ) ,
97+ let mut collector = Collector :: new ( crate_name,
12698 cfgs,
12799 libs,
128100 externs,
129101 false ,
130102 opts) ;
131- collector. fold_crate ( krate) ;
103+
104+ {
105+ let dep_graph = DepGraph :: new ( false ) ;
106+ let _ignore = dep_graph. in_ignore ( ) ;
107+ let map = hir:: map:: map_crate ( & mut hir_forest, defs) ;
108+ let krate = map. krate ( ) ;
109+ let mut hir_collector = HirCollector {
110+ collector : & mut collector,
111+ map : & map
112+ } ;
113+ hir_collector. visit_testable ( "" . to_string ( ) , & krate. attrs , |this| {
114+ intravisit:: walk_crate ( this, krate) ;
115+ } ) ;
116+ }
132117
133118 test_args. insert ( 0 , "rustdoctest" . to_string ( ) ) ;
134119
@@ -472,56 +457,84 @@ impl Collector {
472457 }
473458}
474459
475- impl DocFolder for Collector {
476- fn fold_item ( & mut self , item : clean:: Item ) -> Option < clean:: Item > {
477- let current_name = match item. name {
478- Some ( ref name) if !name. is_empty ( ) => Some ( name. clone ( ) ) ,
479- _ => typename_if_impl ( & item)
480- } ;
460+ struct HirCollector < ' a , ' hir : ' a > {
461+ collector : & ' a mut Collector ,
462+ map : & ' a hir:: map:: Map < ' hir >
463+ }
481464
482- let pushed = current_name. map ( |name| self . names . push ( name) ) . is_some ( ) ;
465+ impl < ' a , ' hir > HirCollector < ' a , ' hir > {
466+ fn visit_testable < F : FnOnce ( & mut Self ) > ( & mut self ,
467+ name : String ,
468+ attrs : & [ ast:: Attribute ] ,
469+ nested : F ) {
470+ let has_name = !name. is_empty ( ) ;
471+ if has_name {
472+ self . collector . names . push ( name) ;
473+ }
483474
484- if let Some ( doc) = item. doc_value ( ) {
485- self . cnt = 0 ;
486- markdown:: find_testable_code ( doc, & mut * self ) ;
475+ let mut attrs = Attributes :: from_ast ( attrs) ;
476+ attrs. collapse_doc_comments ( ) ;
477+ attrs. unindent_doc_comments ( ) ;
478+ if let Some ( doc) = attrs. doc_value ( ) {
479+ self . collector . cnt = 0 ;
480+ markdown:: find_testable_code ( doc, self . collector ) ;
487481 }
488482
489- let ret = self . fold_item_recur ( item) ;
490- if pushed {
491- self . names . pop ( ) ;
483+ nested ( self ) ;
484+
485+ if has_name {
486+ self . collector . names . pop ( ) ;
492487 }
488+ }
489+ }
490+
491+ impl < ' a , ' hir > intravisit:: Visitor < ' hir > for HirCollector < ' a , ' hir > {
492+ fn nested_visit_map ( & mut self ) -> Option < & hir:: map:: Map < ' hir > > {
493+ Some ( self . map )
494+ }
495+
496+ fn visit_item ( & mut self , item : & ' hir hir:: Item ) {
497+ let name = if let hir:: ItemImpl ( .., ref ty, _) = item. node {
498+ hir:: print:: ty_to_string ( ty)
499+ } else {
500+ item. name . to_string ( )
501+ } ;
493502
494- return ret;
503+ self . visit_testable ( name, & item. attrs , |this| {
504+ intravisit:: walk_item ( this, item) ;
505+ } ) ;
506+ }
495507
496- // FIXME: it would be better to not have the escaped version in the first place
497- fn unescape_for_testname ( mut s : String ) -> String {
498- // for refs `&foo`
499- if s . contains ( "&" ) {
500- s = s . replace ( "&" , "&" ) ;
508+ fn visit_trait_item ( & mut self , item : & ' hir hir :: TraitItem ) {
509+ self . visit_testable ( item . name . to_string ( ) , & item . attrs , |this| {
510+ intravisit :: walk_trait_item ( this , item ) ;
511+ } ) ;
512+ }
501513
502- // `::&'a mut Foo::` looks weird, let's make it `::<&'a mut Foo>`::
503- if let Some ( '&' ) = s . chars ( ) . nth ( 0 ) {
504- s = format ! ( "<{}>" , s ) ;
505- }
506- }
514+ fn visit_impl_item ( & mut self , item : & ' hir hir :: ImplItem ) {
515+ self . visit_testable ( item . name . to_string ( ) , & item . attrs , |this| {
516+ intravisit :: walk_impl_item ( this , item ) ;
517+ } ) ;
518+ }
507519
508- // either `<..>` or `->`
509- if s. contains ( ">" ) {
510- s. replace ( ">" , ">" )
511- . replace ( "<" , "<" )
512- } else {
513- s
514- }
515- }
520+ fn visit_foreign_item ( & mut self , item : & ' hir hir:: ForeignItem ) {
521+ self . visit_testable ( item. name . to_string ( ) , & item. attrs , |this| {
522+ intravisit:: walk_foreign_item ( this, item) ;
523+ } ) ;
524+ }
516525
517- fn typename_if_impl ( item : & clean:: Item ) -> Option < String > {
518- if let clean:: ItemEnum :: ImplItem ( ref impl_) = item. inner {
519- let path = impl_. for_ . to_string ( ) ;
520- let unescaped_path = unescape_for_testname ( path) ;
521- Some ( unescaped_path)
522- } else {
523- None
524- }
525- }
526+ fn visit_variant ( & mut self ,
527+ v : & ' hir hir:: Variant ,
528+ g : & ' hir hir:: Generics ,
529+ item_id : ast:: NodeId ) {
530+ self . visit_testable ( v. node . name . to_string ( ) , & v. node . attrs , |this| {
531+ intravisit:: walk_variant ( this, v, g, item_id) ;
532+ } ) ;
533+ }
534+
535+ fn visit_struct_field ( & mut self , f : & ' hir hir:: StructField ) {
536+ self . visit_testable ( f. name . to_string ( ) , & f. attrs , |this| {
537+ intravisit:: walk_struct_field ( this, f) ;
538+ } ) ;
526539 }
527540}
0 commit comments