1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10 pub use self::MaybeTyped::*;
13 use rustc_driver::{driver, target_features, abort_on_err};
14 use rustc::dep_graph::DepGraph;
15 use rustc::session::{self, config};
16 use rustc::hir::def_id::DefId;
17 use rustc::middle::privacy::AccessLevels;
18 use rustc::ty::{self, TyCtxt};
19 use rustc::hir::map as hir_map;
21 use rustc_trans::back::link;
22 use rustc_resolve as resolve;
23 use rustc::hir::lowering::{lower_crate, LoweringContext};
24 use rustc_metadata::cstore::CStore;
25 use rustc_metadata::creader::LocalCrateReader;
27 use syntax::{ast, codemap, errors};
28 use syntax::errors::emitter::ColorConfig;
29 use syntax::feature_gate::UnstableFeatures;
30 use syntax::parse::token;
32 use std::cell::{RefCell, Cell};
33 use std::collections::{HashMap, HashSet};
36 use visit_ast::RustdocVisitor;
39 use html::render::RenderInfo;
41 pub use rustc::session::config::Input;
42 pub use rustc::session::search_paths::SearchPaths;
44 /// Are we generating documentation (`Typed`) or tests (`NotTyped`)?
45 pub enum MaybeTyped<'a, 'tcx: 'a> {
46 Typed(&'a TyCtxt<'tcx>),
47 NotTyped(&'a session::Session)
50 pub type Externs = HashMap<String, Vec<String>>;
51 pub type ExternalPaths = HashMap<DefId, (Vec<String>, clean::TypeKind)>;
53 pub struct DocContext<'a, 'tcx: 'a> {
54 pub map: &'a hir_map::Map<'tcx>,
55 pub maybe_typed: MaybeTyped<'a, 'tcx>,
57 pub populated_crate_impls: RefCell<HashSet<ast::CrateNum>>,
58 pub deref_trait_did: Cell<Option<DefId>>,
59 // Note that external items for which `doc(hidden)` applies to are shown as
60 // non-reachable while local items aren't. This is because we're reusing
61 // the access levels from crateanalysis.
62 /// Later on moved into `clean::Crate`
63 pub access_levels: RefCell<AccessLevels<DefId>>,
64 /// Later on moved into `html::render::CACHE_KEY`
65 pub renderinfo: RefCell<RenderInfo>,
66 /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY`
67 pub external_traits: RefCell<HashMap<DefId, clean::Trait>>,
70 impl<'b, 'tcx> DocContext<'b, 'tcx> {
71 pub fn sess<'a>(&'a self) -> &'a session::Session {
72 match self.maybe_typed {
73 Typed(tcx) => &tcx.sess,
74 NotTyped(ref sess) => sess
78 pub fn tcx_opt<'a>(&'a self) -> Option<&'a TyCtxt<'tcx>> {
79 match self.maybe_typed {
80 Typed(tcx) => Some(tcx),
85 pub fn tcx<'a>(&'a self) -> &'a TyCtxt<'tcx> {
86 let tcx_opt = self.tcx_opt();
87 tcx_opt.expect("tcx not present")
91 pub trait DocAccessLevels {
92 fn is_doc_reachable(&self, DefId) -> bool;
95 impl DocAccessLevels for AccessLevels<DefId> {
96 fn is_doc_reachable(&self, did: DefId) -> bool {
102 pub fn run_core(search_paths: SearchPaths,
106 triple: Option<String>) -> (clean::Crate, RenderInfo)
108 // Parse, resolve, and typecheck the given crate.
110 let cpath = match input {
111 Input::File(ref p) => Some(p.clone()),
115 let warning_lint = lint::builtin::WARNINGS.name_lower();
117 let sessopts = config::Options {
119 search_paths: search_paths,
120 crate_types: vec!(config::CrateTypeRlib),
121 lint_opts: vec!((warning_lint, lint::Allow)),
122 lint_cap: Some(lint::Allow),
124 target_triple: triple.unwrap_or(config::host_triple().to_string()),
125 cfg: config::parse_cfgspecs(cfgs),
126 // Ensure that rustdoc works even if rustc is feature-staged
127 unstable_features: UnstableFeatures::Allow,
128 ..config::basic_options().clone()
131 let codemap = Rc::new(codemap::CodeMap::new());
132 let diagnostic_handler = errors::Handler::with_tty_emitter(ColorConfig::Auto,
138 let cstore = Rc::new(CStore::new(token::get_ident_interner()));
139 let sess = session::build_session_(sessopts, cpath, diagnostic_handler,
140 codemap, cstore.clone());
141 rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
143 let mut cfg = config::build_configuration(&sess);
144 target_features::add_configuration(&mut cfg, &sess);
146 let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, &input));
148 let name = link::find_crate_name(Some(&sess), &krate.attrs,
151 let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, &name, None)
152 .expect("phase_2_configure_and_expand aborted in rustdoc!");
154 let krate = driver::assign_node_ids(&sess, krate);
155 let dep_graph = DepGraph::new(false);
157 let defs = &RefCell::new(hir_map::collect_definitions(&krate));
158 LocalCrateReader::new(&sess, &cstore, &defs, &krate, &name).read_crates(&dep_graph);
159 let lcx = LoweringContext::new(&sess, Some(&krate), defs);
162 let mut hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate), dep_graph);
163 let arenas = ty::CtxtArenas::new();
164 let hir_map = hir_map::map_crate(&mut hir_forest, defs);
166 abort_on_err(driver::phase_3_run_analysis_passes(&sess,
170 resolve::MakeGlobMap::No,
171 |tcx, _, analysis, result| {
172 // Return if the driver hit an err (in `result`)
173 if let Err(_) = result {
177 let _ignore = tcx.dep_graph.in_ignore();
178 let ty::CrateAnalysis { access_levels, .. } = analysis;
180 // Convert from a NodeId set to a DefId set since we don't always have easy access
181 // to the map from defid -> nodeid
182 let access_levels = AccessLevels {
183 map: access_levels.map.into_iter()
184 .map(|(k, v)| (tcx.map.local_def_id(k), v))
188 let ctxt = DocContext {
190 maybe_typed: Typed(tcx),
192 populated_crate_impls: RefCell::new(HashSet::new()),
193 deref_trait_did: Cell::new(None),
194 access_levels: RefCell::new(access_levels),
195 external_traits: RefCell::new(HashMap::new()),
196 renderinfo: RefCell::new(Default::default()),
198 debug!("crate: {:?}", ctxt.map.krate());
201 let mut v = RustdocVisitor::new(&ctxt);
202 v.visit(ctxt.map.krate());
206 Some((krate, ctxt.renderinfo.into_inner()))