]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/core.rs
Auto merge of #31715 - mitaa:rdoc-index-crate, r=alexcrichton
[rust.git] / src / librustdoc / core.rs
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.
4 //
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::*;
11
12 use rustc_lint;
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::middle::def_id::DefId;
17 use rustc::middle::privacy::AccessLevels;
18 use rustc::middle::ty;
19 use rustc::front::map as hir_map;
20 use rustc::lint;
21 use rustc_trans::back::link;
22 use rustc_resolve as resolve;
23 use rustc_front::lowering::{lower_crate, LoweringContext};
24 use rustc_metadata::cstore::CStore;
25
26 use syntax::{ast, codemap, errors};
27 use syntax::errors::emitter::ColorConfig;
28 use syntax::feature_gate::UnstableFeatures;
29 use syntax::parse::token;
30
31 use std::cell::{RefCell, Cell};
32 use std::collections::{HashMap, HashSet};
33 use std::rc::Rc;
34
35 use visit_ast::RustdocVisitor;
36 use clean;
37 use clean::Clean;
38
39 pub use rustc::session::config::Input;
40 pub use rustc::session::search_paths::SearchPaths;
41
42 /// Are we generating documentation (`Typed`) or tests (`NotTyped`)?
43 pub enum MaybeTyped<'a, 'tcx: 'a> {
44     Typed(&'a ty::ctxt<'tcx>),
45     NotTyped(&'a session::Session)
46 }
47
48 pub type ExternalPaths = RefCell<Option<HashMap<DefId,
49                                                 (Vec<String>, clean::TypeKind)>>>;
50
51 pub struct DocContext<'a, 'tcx: 'a> {
52     pub map: &'a hir_map::Map<'tcx>,
53     pub maybe_typed: MaybeTyped<'a, 'tcx>,
54     pub input: Input,
55     pub external_paths: ExternalPaths,
56     pub external_traits: RefCell<Option<HashMap<DefId, clean::Trait>>>,
57     pub external_typarams: RefCell<Option<HashMap<DefId, String>>>,
58     pub inlined: RefCell<Option<HashSet<DefId>>>,
59     pub populated_crate_impls: RefCell<HashSet<ast::CrateNum>>,
60     pub deref_trait_did: Cell<Option<DefId>>,
61 }
62
63 impl<'b, 'tcx> DocContext<'b, 'tcx> {
64     pub fn sess<'a>(&'a self) -> &'a session::Session {
65         match self.maybe_typed {
66             Typed(tcx) => &tcx.sess,
67             NotTyped(ref sess) => sess
68         }
69     }
70
71     pub fn tcx_opt<'a>(&'a self) -> Option<&'a ty::ctxt<'tcx>> {
72         match self.maybe_typed {
73             Typed(tcx) => Some(tcx),
74             NotTyped(_) => None
75         }
76     }
77
78     pub fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
79         let tcx_opt = self.tcx_opt();
80         tcx_opt.expect("tcx not present")
81     }
82 }
83
84 pub struct CrateAnalysis {
85     pub access_levels: AccessLevels<DefId>,
86     pub external_paths: ExternalPaths,
87     pub external_typarams: RefCell<Option<HashMap<DefId, String>>>,
88     pub inlined: RefCell<Option<HashSet<DefId>>>,
89     pub deref_trait_did: Option<DefId>,
90 }
91
92 pub type Externs = HashMap<String, Vec<String>>;
93
94 pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
95                 input: Input, triple: Option<String>)
96                 -> (clean::Crate, CrateAnalysis) {
97
98     // Parse, resolve, and typecheck the given crate.
99
100     let cpath = match input {
101         Input::File(ref p) => Some(p.clone()),
102         _ => None
103     };
104
105     let warning_lint = lint::builtin::WARNINGS.name_lower();
106
107     let sessopts = config::Options {
108         maybe_sysroot: None,
109         search_paths: search_paths,
110         crate_types: vec!(config::CrateTypeRlib),
111         lint_opts: vec!((warning_lint, lint::Allow)),
112         lint_cap: Some(lint::Allow),
113         externs: externs,
114         target_triple: triple.unwrap_or(config::host_triple().to_string()),
115         cfg: config::parse_cfgspecs(cfgs),
116         // Ensure that rustdoc works even if rustc is feature-staged
117         unstable_features: UnstableFeatures::Allow,
118         ..config::basic_options().clone()
119     };
120
121     let codemap = Rc::new(codemap::CodeMap::new());
122     let diagnostic_handler = errors::Handler::with_tty_emitter(ColorConfig::Auto,
123                                                                None,
124                                                                true,
125                                                                false,
126                                                                codemap.clone());
127
128     let cstore = Rc::new(CStore::new(token::get_ident_interner()));
129     let sess = session::build_session_(sessopts, cpath, diagnostic_handler,
130                                        codemap, cstore.clone());
131     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
132
133     let mut cfg = config::build_configuration(&sess);
134     target_features::add_configuration(&mut cfg, &sess);
135
136     let krate = driver::phase_1_parse_input(&sess, cfg, &input);
137
138     let name = link::find_crate_name(Some(&sess), &krate.attrs,
139                                      &input);
140
141     let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, &name, None)
142                     .expect("phase_2_configure_and_expand aborted in rustdoc!");
143
144     let krate = driver::assign_node_ids(&sess, krate);
145     // Lower ast -> hir.
146     let lcx = LoweringContext::new(&sess, Some(&krate));
147     let mut hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate), DepGraph::new(false));
148     let arenas = ty::CtxtArenas::new();
149     let hir_map = driver::make_map(&sess, &mut hir_forest);
150
151     let krate_and_analysis = abort_on_err(driver::phase_3_run_analysis_passes(&sess,
152                                                      &cstore,
153                                                      hir_map,
154                                                      &arenas,
155                                                      &name,
156                                                      resolve::MakeGlobMap::No,
157                                                      |tcx, _, analysis, result| {
158         // Return if the driver hit an err (in `result`)
159         if let Err(_) = result {
160             return None
161         }
162
163         let _ignore = tcx.dep_graph.in_ignore();
164         let ty::CrateAnalysis { access_levels, .. } = analysis;
165
166         // Convert from a NodeId set to a DefId set since we don't always have easy access
167         // to the map from defid -> nodeid
168         let access_levels = AccessLevels {
169             map: access_levels.map.into_iter()
170                                   .map(|(k, v)| (tcx.map.local_def_id(k), v))
171                                   .collect()
172         };
173
174         let ctxt = DocContext {
175             map: &tcx.map,
176             maybe_typed: Typed(tcx),
177             input: input,
178             external_traits: RefCell::new(Some(HashMap::new())),
179             external_typarams: RefCell::new(Some(HashMap::new())),
180             external_paths: RefCell::new(Some(HashMap::new())),
181             inlined: RefCell::new(Some(HashSet::new())),
182             populated_crate_impls: RefCell::new(HashSet::new()),
183             deref_trait_did: Cell::new(None),
184         };
185         debug!("crate: {:?}", ctxt.map.krate());
186
187         let mut analysis = CrateAnalysis {
188             access_levels: access_levels,
189             external_paths: RefCell::new(None),
190             external_typarams: RefCell::new(None),
191             inlined: RefCell::new(None),
192             deref_trait_did: None,
193         };
194
195         let krate = {
196             let mut v = RustdocVisitor::new(&ctxt, Some(&analysis));
197             v.visit(ctxt.map.krate());
198             v.clean(&ctxt)
199         };
200
201         let external_paths = ctxt.external_paths.borrow_mut().take();
202         *analysis.external_paths.borrow_mut() = external_paths;
203
204         let map = ctxt.external_typarams.borrow_mut().take();
205         *analysis.external_typarams.borrow_mut() = map;
206
207         let map = ctxt.inlined.borrow_mut().take();
208         *analysis.inlined.borrow_mut() = map;
209
210         analysis.deref_trait_did = ctxt.deref_trait_did.get();
211
212         Some((krate, analysis))
213     }), &sess);
214
215     krate_and_analysis.unwrap()
216 }