Skip to content

Commit e68ad42

Browse files
committed
rustdoc: sidestep the main pipeline for test collection.
1 parent 12c5f8c commit e68ad42

File tree

1 file changed

+93
-80
lines changed

1 file changed

+93
-80
lines changed

src/librustdoc/test.rs

Lines changed: 93 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use std::cell::Cell;
1211
use std::env;
1312
use std::ffi::OsString;
1413
use std::io::prelude::*;
@@ -23,7 +22,8 @@ use std::sync::{Arc, Mutex};
2322
use testing;
2423
use rustc_lint;
2524
use rustc::dep_graph::DepGraph;
26-
use rustc::hir::map as hir_map;
25+
use rustc::hir;
26+
use rustc::hir::intravisit;
2727
use rustc::session::{self, config};
2828
use rustc::session::config::{OutputType, OutputTypes, Externs};
2929
use rustc::session::search_paths::{SearchPaths, PathKind};
@@ -33,18 +33,15 @@ use rustc_driver::{driver, Compilation};
3333
use rustc_driver::driver::phase_2_configure_and_expand;
3434
use rustc_metadata::cstore::CStore;
3535
use rustc_resolve::MakeGlobMap;
36+
use rustc_trans::back::link;
37+
use syntax::ast;
3638
use syntax::codemap::CodeMap;
3739
use syntax::feature_gate::UnstableFeatures;
3840
use errors;
3941
use errors::emitter::ColorConfig;
4042

41-
use core;
42-
use clean;
43-
use clean::Clean;
44-
use fold::DocFolder;
43+
use clean::Attributes;
4544
use html::markdown;
46-
use passes;
47-
use visit_ast::RustdocVisitor;
4845

4946
#[derive(Clone, Default)]
5047
pub 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("&amp;") {
500-
s = s.replace("&amp;", "&");
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("&gt;") {
510-
s.replace("&gt;", ">")
511-
.replace("&lt;", "<")
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

Comments
 (0)