]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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 | ||
e9174d1e | 11 | #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", |
9cc50fc6 SL |
12 | html_favicon_url = "https://doc.rust-lang.org/favicon.ico", |
13 | html_root_url = "https://doc.rust-lang.org/nightly/", | |
14 | html_playground_url = "https://play.rust-lang.org/")] | |
83c7162d | 15 | |
abe05a73 | 16 | #![feature(ascii_ctype)] |
3b2f2976 | 17 | #![feature(rustc_private)] |
85aaf69f | 18 | #![feature(box_patterns)] |
1a4d82fc | 19 | #![feature(box_syntax)] |
2c00a5a8 | 20 | #![feature(fs_read_write)] |
62682a34 | 21 | #![feature(set_stdio)] |
83c7162d | 22 | #![feature(slice_sort_by_cached_key)] |
85aaf69f | 23 | #![feature(test)] |
cc61c64b | 24 | #![feature(vec_remove_item)] |
0531ce1d | 25 | #![feature(entry_and_modify)] |
94b46f34 XL |
26 | #![feature(ptr_offset_from)] |
27 | ||
28 | #![recursion_limit="256"] | |
1a4d82fc JJ |
29 | |
30 | extern crate arena; | |
31 | extern crate getopts; | |
cc61c64b | 32 | extern crate env_logger; |
1a4d82fc | 33 | extern crate rustc; |
9e0c209e | 34 | extern crate rustc_data_structures; |
94b46f34 | 35 | extern crate rustc_codegen_utils; |
1a4d82fc | 36 | extern crate rustc_driver; |
85aaf69f | 37 | extern crate rustc_resolve; |
c34b1796 | 38 | extern crate rustc_lint; |
92a42be0 | 39 | extern crate rustc_metadata; |
83c7162d | 40 | extern crate rustc_target; |
7cac9316 | 41 | extern crate rustc_typeck; |
1a4d82fc | 42 | extern crate serialize; |
54a0048b | 43 | #[macro_use] extern crate syntax; |
3157f602 | 44 | extern crate syntax_pos; |
c34b1796 | 45 | extern crate test as testing; |
1a4d82fc | 46 | #[macro_use] extern crate log; |
3157f602 | 47 | extern crate rustc_errors as errors; |
cc61c64b | 48 | extern crate pulldown_cmark; |
ff7c6d11 | 49 | extern crate tempdir; |
94b46f34 | 50 | extern crate minifier; |
1a4d82fc | 51 | |
c34b1796 | 52 | extern crate serialize as rustc_serialize; // used by deriving |
1a4d82fc | 53 | |
83c7162d XL |
54 | use errors::ColorConfig; |
55 | ||
5bcae85e | 56 | use std::collections::{BTreeMap, BTreeSet}; |
9cc50fc6 | 57 | use std::default::Default; |
85aaf69f | 58 | use std::env; |
ff7c6d11 | 59 | use std::path::{Path, PathBuf}; |
62682a34 | 60 | use std::process; |
85aaf69f | 61 | use std::sync::mpsc::channel; |
c34b1796 | 62 | |
0531ce1d | 63 | use syntax::edition::Edition; |
1a4d82fc | 64 | use externalfiles::ExternalHtml; |
94b46f34 | 65 | use rustc::session::{early_warn, early_error}; |
1a4d82fc | 66 | use rustc::session::search_paths::SearchPaths; |
83c7162d XL |
67 | use rustc::session::config::{ErrorOutputType, RustcOptGroup, Externs, CodegenOptions}; |
68 | use rustc::session::config::{nightly_options, build_codegen_options}; | |
69 | use rustc_target::spec::TargetTriple; | |
1a4d82fc JJ |
70 | |
71 | #[macro_use] | |
72 | pub mod externalfiles; | |
73 | ||
74 | pub mod clean; | |
75 | pub mod core; | |
76 | pub mod doctree; | |
77 | pub mod fold; | |
78 | pub mod html { | |
79 | pub mod highlight; | |
80 | pub mod escape; | |
81 | pub mod item_type; | |
82 | pub mod format; | |
83 | pub mod layout; | |
84 | pub mod markdown; | |
85 | pub mod render; | |
86 | pub mod toc; | |
87 | } | |
88 | pub mod markdown; | |
89 | pub mod passes; | |
90 | pub mod plugins; | |
1a4d82fc | 91 | pub mod visit_ast; |
a7813a04 | 92 | pub mod visit_lib; |
1a4d82fc | 93 | pub mod test; |
2c00a5a8 | 94 | pub mod theme; |
1a4d82fc | 95 | |
476ff2be | 96 | use clean::AttributesExt; |
54a0048b | 97 | |
1a4d82fc JJ |
98 | struct Output { |
99 | krate: clean::Crate, | |
a7813a04 | 100 | renderinfo: html::render::RenderInfo, |
1a4d82fc JJ |
101 | passes: Vec<String>, |
102 | } | |
103 | ||
104 | pub fn main() { | |
9e0c209e | 105 | const STACK_SIZE: usize = 32_000_000; // 32MB |
83c7162d | 106 | rustc_driver::set_sigpipe_handler(); |
0531ce1d | 107 | env_logger::init(); |
9346a6ac | 108 | let res = std::thread::Builder::new().stack_size(STACK_SIZE).spawn(move || { |
0531ce1d XL |
109 | syntax::with_globals(move || { |
110 | get_args().map(|args| main_args(&args)).unwrap_or(1) | |
111 | }) | |
c1a9b12d | 112 | }).unwrap().join().unwrap_or(101); |
62682a34 | 113 | process::exit(res as i32); |
1a4d82fc JJ |
114 | } |
115 | ||
7cac9316 XL |
116 | fn get_args() -> Option<Vec<String>> { |
117 | env::args_os().enumerate() | |
118 | .map(|(i, arg)| arg.into_string().map_err(|arg| { | |
94b46f34 XL |
119 | early_warn(ErrorOutputType::default(), |
120 | &format!("Argument {} is not valid Unicode: {:?}", i, arg)); | |
7cac9316 XL |
121 | }).ok()) |
122 | .collect() | |
123 | } | |
124 | ||
041b39d2 XL |
125 | fn stable<F>(name: &'static str, f: F) -> RustcOptGroup |
126 | where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static | |
127 | { | |
128 | RustcOptGroup::stable(name, f) | |
129 | } | |
130 | ||
131 | fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup | |
132 | where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static | |
133 | { | |
134 | RustcOptGroup::unstable(name, f) | |
135 | } | |
54a0048b SL |
136 | |
137 | pub fn opts() -> Vec<RustcOptGroup> { | |
c30ab7b3 | 138 | vec![ |
041b39d2 XL |
139 | stable("h", |o| o.optflag("h", "help", "show this help message")), |
140 | stable("V", |o| o.optflag("V", "version", "print rustdoc's version")), | |
141 | stable("v", |o| o.optflag("v", "verbose", "use verbose output")), | |
142 | stable("r", |o| { | |
143 | o.optopt("r", "input-format", "the input type of the specified file", | |
144 | "[rust]") | |
145 | }), | |
146 | stable("w", |o| { | |
147 | o.optopt("w", "output-format", "the output type to write", "[html]") | |
148 | }), | |
149 | stable("o", |o| o.optopt("o", "output", "where to place the output", "PATH")), | |
150 | stable("crate-name", |o| { | |
151 | o.optopt("", "crate-name", "specify the name of this crate", "NAME") | |
152 | }), | |
153 | stable("L", |o| { | |
154 | o.optmulti("L", "library-path", "directory to add to crate search path", | |
155 | "DIR") | |
156 | }), | |
157 | stable("cfg", |o| o.optmulti("", "cfg", "pass a --cfg to rustc", "")), | |
158 | stable("extern", |o| { | |
159 | o.optmulti("", "extern", "pass an --extern to rustc", "NAME=PATH") | |
160 | }), | |
161 | stable("plugin-path", |o| { | |
94b46f34 | 162 | o.optmulti("", "plugin-path", "removed", "DIR") |
041b39d2 | 163 | }), |
83c7162d XL |
164 | stable("C", |o| { |
165 | o.optmulti("C", "codegen", "pass a codegen option to rustc", "OPT[=VALUE]") | |
166 | }), | |
041b39d2 XL |
167 | stable("passes", |o| { |
168 | o.optmulti("", "passes", | |
169 | "list of passes to also run, you might want \ | |
170 | to pass it multiple times; a value of `list` \ | |
171 | will print available passes", | |
172 | "PASSES") | |
173 | }), | |
174 | stable("plugins", |o| { | |
94b46f34 | 175 | o.optmulti("", "plugins", "removed", |
041b39d2 XL |
176 | "PLUGINS") |
177 | }), | |
178 | stable("no-default", |o| { | |
179 | o.optflag("", "no-defaults", "don't run the default passes") | |
180 | }), | |
abe05a73 XL |
181 | stable("document-private-items", |o| { |
182 | o.optflag("", "document-private-items", "document private items") | |
183 | }), | |
041b39d2 XL |
184 | stable("test", |o| o.optflag("", "test", "run code examples as tests")), |
185 | stable("test-args", |o| { | |
186 | o.optmulti("", "test-args", "arguments to pass to the test runner", | |
187 | "ARGS") | |
188 | }), | |
189 | stable("target", |o| o.optopt("", "target", "target triple to document", "TRIPLE")), | |
190 | stable("markdown-css", |o| { | |
191 | o.optmulti("", "markdown-css", | |
192 | "CSS files to include via <link> in a rendered Markdown file", | |
193 | "FILES") | |
194 | }), | |
195 | stable("html-in-header", |o| { | |
196 | o.optmulti("", "html-in-header", | |
197 | "files to include inline in the <head> section of a rendered Markdown file \ | |
198 | or generated documentation", | |
199 | "FILES") | |
200 | }), | |
201 | stable("html-before-content", |o| { | |
202 | o.optmulti("", "html-before-content", | |
203 | "files to include inline between <body> and the content of a rendered \ | |
204 | Markdown file or generated documentation", | |
205 | "FILES") | |
206 | }), | |
207 | stable("html-after-content", |o| { | |
208 | o.optmulti("", "html-after-content", | |
209 | "files to include inline between the content and </body> of a rendered \ | |
210 | Markdown file or generated documentation", | |
211 | "FILES") | |
212 | }), | |
213 | unstable("markdown-before-content", |o| { | |
214 | o.optmulti("", "markdown-before-content", | |
215 | "files to include inline between <body> and the content of a rendered \ | |
216 | Markdown file or generated documentation", | |
217 | "FILES") | |
218 | }), | |
219 | unstable("markdown-after-content", |o| { | |
220 | o.optmulti("", "markdown-after-content", | |
221 | "files to include inline between the content and </body> of a rendered \ | |
222 | Markdown file or generated documentation", | |
223 | "FILES") | |
224 | }), | |
225 | stable("markdown-playground-url", |o| { | |
226 | o.optopt("", "markdown-playground-url", | |
227 | "URL to send code snippets to", "URL") | |
228 | }), | |
229 | stable("markdown-no-toc", |o| { | |
230 | o.optflag("", "markdown-no-toc", "don't include table of contents") | |
231 | }), | |
232 | stable("e", |o| { | |
233 | o.optopt("e", "extend-css", | |
234 | "To add some CSS rules with a given file to generate doc with your \ | |
235 | own theme. However, your theme might break if the rustdoc's generated HTML \ | |
236 | changes, so be careful!", "PATH") | |
237 | }), | |
238 | unstable("Z", |o| { | |
239 | o.optmulti("Z", "", | |
240 | "internal and debugging options (only on nightly build)", "FLAG") | |
241 | }), | |
242 | stable("sysroot", |o| { | |
243 | o.optopt("", "sysroot", "Override the system root", "PATH") | |
244 | }), | |
245 | unstable("playground-url", |o| { | |
246 | o.optopt("", "playground-url", | |
247 | "URL to send code snippets to, may be reset by --markdown-playground-url \ | |
248 | or `#![doc(html_playground_url=...)]`", | |
249 | "URL") | |
250 | }), | |
041b39d2 XL |
251 | unstable("display-warnings", |o| { |
252 | o.optflag("", "display-warnings", "to print code warnings when testing doc") | |
253 | }), | |
abe05a73 XL |
254 | unstable("crate-version", |o| { |
255 | o.optopt("", "crate-version", "crate version to print into documentation", "VERSION") | |
256 | }), | |
257 | unstable("linker", |o| { | |
258 | o.optopt("", "linker", "linker used for building executable test code", "PATH") | |
259 | }), | |
ff7c6d11 XL |
260 | unstable("sort-modules-by-appearance", |o| { |
261 | o.optflag("", "sort-modules-by-appearance", "sort modules by where they appear in the \ | |
262 | program, rather than alphabetically") | |
263 | }), | |
2c00a5a8 XL |
264 | unstable("themes", |o| { |
265 | o.optmulti("", "themes", | |
266 | "additional themes which will be added to the generated docs", | |
267 | "FILES") | |
268 | }), | |
269 | unstable("theme-checker", |o| { | |
270 | o.optmulti("", "theme-checker", | |
271 | "check if given theme is valid", | |
272 | "FILES") | |
273 | }), | |
0531ce1d XL |
274 | unstable("resource-suffix", |o| { |
275 | o.optopt("", | |
276 | "resource-suffix", | |
277 | "suffix to add to CSS and JavaScript files, e.g. \"light.css\" will become \ | |
278 | \"light-suffix.css\"", | |
279 | "PATH") | |
280 | }), | |
281 | unstable("edition", |o| { | |
282 | o.optopt("", "edition", | |
283 | "edition to use when compiling rust code (default: 2015)", | |
284 | "EDITION") | |
285 | }), | |
83c7162d XL |
286 | unstable("color", |o| { |
287 | o.optopt("", | |
288 | "color", | |
289 | "Configure coloring of output: | |
290 | auto = colorize, if output goes to a tty (default); | |
291 | always = always colorize output; | |
292 | never = never colorize output", | |
293 | "auto|always|never") | |
294 | }), | |
295 | unstable("error-format", |o| { | |
296 | o.optopt("", | |
297 | "error-format", | |
298 | "How errors and other messages are produced", | |
299 | "human|json|short") | |
300 | }), | |
94b46f34 XL |
301 | unstable("disable-minification", |o| { |
302 | o.optflag("", | |
303 | "disable-minification", | |
304 | "Disable minification applied on JS files") | |
305 | }), | |
c30ab7b3 | 306 | ] |
1a4d82fc JJ |
307 | } |
308 | ||
309 | pub fn usage(argv0: &str) { | |
041b39d2 XL |
310 | let mut options = getopts::Options::new(); |
311 | for option in opts() { | |
312 | (option.apply)(&mut options); | |
313 | } | |
314 | println!("{}", options.usage(&format!("{} [options] <input>", argv0))); | |
1a4d82fc JJ |
315 | } |
316 | ||
c34b1796 | 317 | pub fn main_args(args: &[String]) -> isize { |
041b39d2 XL |
318 | let mut options = getopts::Options::new(); |
319 | for option in opts() { | |
320 | (option.apply)(&mut options); | |
321 | } | |
322 | let matches = match options.parse(&args[1..]) { | |
1a4d82fc JJ |
323 | Ok(m) => m, |
324 | Err(err) => { | |
94b46f34 | 325 | early_error(ErrorOutputType::default(), &err.to_string()); |
1a4d82fc JJ |
326 | } |
327 | }; | |
54a0048b SL |
328 | // Check for unstable options. |
329 | nightly_options::check_nightly_options(&matches, &opts()); | |
330 | ||
1a4d82fc | 331 | if matches.opt_present("h") || matches.opt_present("help") { |
8bb4bdeb | 332 | usage("rustdoc"); |
1a4d82fc JJ |
333 | return 0; |
334 | } else if matches.opt_present("version") { | |
335 | rustc_driver::version("rustdoc", &matches); | |
336 | return 0; | |
337 | } | |
338 | ||
339 | if matches.opt_strs("passes") == ["list"] { | |
340 | println!("Available passes for running rustdoc:"); | |
9e0c209e | 341 | for &(name, _, description) in passes::PASSES { |
1a4d82fc JJ |
342 | println!("{:>20} - {}", name, description); |
343 | } | |
b039eaaf | 344 | println!("\nDefault passes for rustdoc:"); |
9e0c209e | 345 | for &name in passes::DEFAULT_PASSES { |
1a4d82fc JJ |
346 | println!("{:>20}", name); |
347 | } | |
348 | return 0; | |
349 | } | |
350 | ||
94b46f34 XL |
351 | let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) { |
352 | Some("auto") => ColorConfig::Auto, | |
353 | Some("always") => ColorConfig::Always, | |
354 | Some("never") => ColorConfig::Never, | |
355 | None => ColorConfig::Auto, | |
356 | Some(arg) => { | |
357 | early_error(ErrorOutputType::default(), | |
358 | &format!("argument for --color must be `auto`, `always` or `never` \ | |
359 | (instead was `{}`)", arg)); | |
360 | } | |
361 | }; | |
362 | let error_format = match matches.opt_str("error-format").as_ref().map(|s| &s[..]) { | |
363 | Some("human") => ErrorOutputType::HumanReadable(color), | |
364 | Some("json") => ErrorOutputType::Json(false), | |
365 | Some("pretty-json") => ErrorOutputType::Json(true), | |
366 | Some("short") => ErrorOutputType::Short(color), | |
367 | None => ErrorOutputType::HumanReadable(color), | |
368 | Some(arg) => { | |
369 | early_error(ErrorOutputType::default(), | |
370 | &format!("argument for --error-format must be `human`, `json` or \ | |
371 | `short` (instead was `{}`)", arg)); | |
372 | } | |
373 | }; | |
374 | ||
375 | let diag = core::new_handler(error_format, None); | |
376 | ||
377 | // check for deprecated options | |
378 | check_deprecated_options(&matches, &diag); | |
379 | ||
2c00a5a8 XL |
380 | let to_check = matches.opt_strs("theme-checker"); |
381 | if !to_check.is_empty() { | |
0531ce1d | 382 | let paths = theme::load_css_paths(include_bytes!("html/static/themes/light.css")); |
2c00a5a8 XL |
383 | let mut errors = 0; |
384 | ||
385 | println!("rustdoc: [theme-checker] Starting tests!"); | |
386 | for theme_file in to_check.iter() { | |
387 | print!(" - Checking \"{}\"...", theme_file); | |
94b46f34 | 388 | let (success, differences) = theme::test_theme_against(theme_file, &paths, &diag); |
2c00a5a8 XL |
389 | if !differences.is_empty() || !success { |
390 | println!(" FAILED"); | |
391 | errors += 1; | |
392 | if !differences.is_empty() { | |
393 | println!("{}", differences.join("\n")); | |
394 | } | |
395 | } else { | |
396 | println!(" OK"); | |
397 | } | |
398 | } | |
399 | if errors != 0 { | |
400 | return 1; | |
401 | } | |
402 | return 0; | |
403 | } | |
404 | ||
9346a6ac | 405 | if matches.free.is_empty() { |
94b46f34 | 406 | diag.struct_err("missing file operand").emit(); |
1a4d82fc | 407 | return 1; |
9e0c209e SL |
408 | } |
409 | if matches.free.len() > 1 { | |
94b46f34 | 410 | diag.struct_err("too many file operands").emit(); |
1a4d82fc JJ |
411 | return 1; |
412 | } | |
85aaf69f | 413 | let input = &matches.free[0]; |
1a4d82fc JJ |
414 | |
415 | let mut libs = SearchPaths::new(); | |
85aaf69f | 416 | for s in &matches.opt_strs("L") { |
83c7162d | 417 | libs.add_path(s, error_format); |
1a4d82fc JJ |
418 | } |
419 | let externs = match parse_externs(&matches) { | |
420 | Ok(ex) => ex, | |
421 | Err(err) => { | |
94b46f34 | 422 | diag.struct_err(&err.to_string()).emit(); |
1a4d82fc JJ |
423 | return 1; |
424 | } | |
425 | }; | |
426 | ||
427 | let test_args = matches.opt_strs("test-args"); | |
428 | let test_args: Vec<String> = test_args.iter() | |
d9579d0f | 429 | .flat_map(|s| s.split_whitespace()) |
1a4d82fc JJ |
430 | .map(|s| s.to_string()) |
431 | .collect(); | |
432 | ||
433 | let should_test = matches.opt_present("test"); | |
ff7c6d11 XL |
434 | let markdown_input = Path::new(input).extension() |
435 | .map_or(false, |e| e == "md" || e == "markdown"); | |
1a4d82fc | 436 | |
c34b1796 | 437 | let output = matches.opt_str("o").map(|s| PathBuf::from(&s)); |
54a0048b | 438 | let css_file_extension = matches.opt_str("e").map(|s| PathBuf::from(&s)); |
1a4d82fc JJ |
439 | let cfgs = matches.opt_strs("cfg"); |
440 | ||
54a0048b SL |
441 | if let Some(ref p) = css_file_extension { |
442 | if !p.is_file() { | |
94b46f34 | 443 | diag.struct_err("option --extend-css argument must be a file").emit(); |
54a0048b SL |
444 | return 1; |
445 | } | |
446 | } | |
447 | ||
2c00a5a8 XL |
448 | let mut themes = Vec::new(); |
449 | if matches.opt_present("themes") { | |
0531ce1d | 450 | let paths = theme::load_css_paths(include_bytes!("html/static/themes/light.css")); |
2c00a5a8 XL |
451 | |
452 | for (theme_file, theme_s) in matches.opt_strs("themes") | |
453 | .iter() | |
454 | .map(|s| (PathBuf::from(&s), s.to_owned())) { | |
455 | if !theme_file.is_file() { | |
94b46f34 | 456 | diag.struct_err("option --themes arguments must all be files").emit(); |
2c00a5a8 XL |
457 | return 1; |
458 | } | |
94b46f34 | 459 | let (success, ret) = theme::test_theme_against(&theme_file, &paths, &diag); |
2c00a5a8 | 460 | if !success || !ret.is_empty() { |
94b46f34 XL |
461 | diag.struct_err(&format!("invalid theme: \"{}\"", theme_s)) |
462 | .help("check what's wrong with the --theme-checker option") | |
463 | .emit(); | |
2c00a5a8 XL |
464 | return 1; |
465 | } | |
466 | themes.push(theme_file); | |
467 | } | |
468 | } | |
469 | ||
1a4d82fc | 470 | let external_html = match ExternalHtml::load( |
32a655c1 SL |
471 | &matches.opt_strs("html-in-header"), |
472 | &matches.opt_strs("html-before-content"), | |
7cac9316 XL |
473 | &matches.opt_strs("html-after-content"), |
474 | &matches.opt_strs("markdown-before-content"), | |
94b46f34 | 475 | &matches.opt_strs("markdown-after-content"), &diag) { |
1a4d82fc | 476 | Some(eh) => eh, |
32a655c1 | 477 | None => return 3, |
1a4d82fc JJ |
478 | }; |
479 | let crate_name = matches.opt_str("crate-name"); | |
476ff2be | 480 | let playground_url = matches.opt_str("playground-url"); |
32a655c1 | 481 | let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from); |
7cac9316 | 482 | let display_warnings = matches.opt_present("display-warnings"); |
ff7c6d11 XL |
483 | let linker = matches.opt_str("linker").map(PathBuf::from); |
484 | let sort_modules_alphabetically = !matches.opt_present("sort-modules-by-appearance"); | |
0531ce1d | 485 | let resource_suffix = matches.opt_str("resource-suffix"); |
94b46f34 | 486 | let enable_minification = !matches.opt_present("disable-minification"); |
0531ce1d XL |
487 | |
488 | let edition = matches.opt_str("edition").unwrap_or("2015".to_string()); | |
489 | let edition = match edition.parse() { | |
490 | Ok(e) => e, | |
491 | Err(_) => { | |
94b46f34 | 492 | diag.struct_err("could not parse edition").emit(); |
0531ce1d XL |
493 | return 1; |
494 | } | |
495 | }; | |
1a4d82fc | 496 | |
83c7162d XL |
497 | let cg = build_codegen_options(&matches, ErrorOutputType::default()); |
498 | ||
1a4d82fc JJ |
499 | match (should_test, markdown_input) { |
500 | (true, true) => { | |
ff7c6d11 | 501 | return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot, |
94b46f34 | 502 | display_warnings, linker, edition, cg, &diag) |
1a4d82fc JJ |
503 | } |
504 | (true, false) => { | |
ff7c6d11 | 505 | return test::run(Path::new(input), cfgs, libs, externs, test_args, crate_name, |
83c7162d | 506 | maybe_sysroot, display_warnings, linker, edition, cg) |
1a4d82fc | 507 | } |
ff7c6d11 | 508 | (false, true) => return markdown::render(Path::new(input), |
c34b1796 | 509 | output.unwrap_or(PathBuf::from("doc")), |
1a4d82fc | 510 | &matches, &external_html, |
94b46f34 | 511 | !matches.opt_present("markdown-no-toc"), &diag), |
1a4d82fc JJ |
512 | (false, false) => {} |
513 | } | |
476ff2be SL |
514 | |
515 | let output_format = matches.opt_str("w"); | |
83c7162d XL |
516 | |
517 | let res = acquire_input(PathBuf::from(input), externs, edition, cg, &matches, error_format, | |
518 | move |out| { | |
476ff2be | 519 | let Output { krate, passes, renderinfo } = out; |
94b46f34 | 520 | let diag = core::new_handler(error_format, None); |
476ff2be SL |
521 | info!("going to format"); |
522 | match output_format.as_ref().map(|s| &**s) { | |
523 | Some("html") | None => { | |
524 | html::render::run(krate, &external_html, playground_url, | |
525 | output.unwrap_or(PathBuf::from("doc")), | |
0531ce1d | 526 | resource_suffix.unwrap_or(String::new()), |
476ff2be SL |
527 | passes.into_iter().collect(), |
528 | css_file_extension, | |
cc61c64b | 529 | renderinfo, |
ff7c6d11 | 530 | sort_modules_alphabetically, |
94b46f34 XL |
531 | themes, |
532 | enable_minification) | |
476ff2be SL |
533 | .expect("failed to generate documentation"); |
534 | 0 | |
535 | } | |
536 | Some(s) => { | |
94b46f34 | 537 | diag.struct_err(&format!("unknown output format: {}", s)).emit(); |
476ff2be SL |
538 | 1 |
539 | } | |
1a4d82fc | 540 | } |
476ff2be SL |
541 | }); |
542 | res.unwrap_or_else(|s| { | |
94b46f34 | 543 | diag.struct_err(&format!("input error: {}", s)).emit(); |
476ff2be SL |
544 | 1 |
545 | }) | |
546 | } | |
547 | ||
1a4d82fc JJ |
548 | /// Looks inside the command line arguments to extract the relevant input format |
549 | /// and files and then generates the necessary rustdoc output for formatting. | |
ff7c6d11 | 550 | fn acquire_input<R, F>(input: PathBuf, |
476ff2be | 551 | externs: Externs, |
0531ce1d | 552 | edition: Edition, |
83c7162d | 553 | cg: CodegenOptions, |
476ff2be | 554 | matches: &getopts::Matches, |
83c7162d | 555 | error_format: ErrorOutputType, |
476ff2be SL |
556 | f: F) |
557 | -> Result<R, String> | |
558 | where R: 'static + Send, F: 'static + Send + FnOnce(Output) -> R { | |
85aaf69f | 559 | match matches.opt_str("r").as_ref().map(|s| &**s) { |
83c7162d | 560 | Some("rust") => Ok(rust_input(input, externs, edition, cg, matches, error_format, f)), |
1a4d82fc | 561 | Some(s) => Err(format!("unknown input format: {}", s)), |
83c7162d | 562 | None => Ok(rust_input(input, externs, edition, cg, matches, error_format, f)) |
1a4d82fc JJ |
563 | } |
564 | } | |
565 | ||
566 | /// Extracts `--extern CRATE=PATH` arguments from `matches` and | |
5bcae85e | 567 | /// returns a map mapping crate names to their paths or else an |
1a4d82fc | 568 | /// error message. |
5bcae85e SL |
569 | fn parse_externs(matches: &getopts::Matches) -> Result<Externs, String> { |
570 | let mut externs = BTreeMap::new(); | |
85aaf69f | 571 | for arg in &matches.opt_strs("extern") { |
c34b1796 | 572 | let mut parts = arg.splitn(2, '='); |
54a0048b SL |
573 | let name = parts.next().ok_or("--extern value must not be empty".to_string())?; |
574 | let location = parts.next() | |
575 | .ok_or("--extern value must be of the format `foo=bar`" | |
576 | .to_string())?; | |
1a4d82fc | 577 | let name = name.to_string(); |
5bcae85e | 578 | externs.entry(name).or_insert_with(BTreeSet::new).insert(location.to_string()); |
1a4d82fc | 579 | } |
5bcae85e | 580 | Ok(Externs::new(externs)) |
1a4d82fc JJ |
581 | } |
582 | ||
583 | /// Interprets the input file as a rust source file, passing it through the | |
584 | /// compiler all the way through the analysis passes. The rustdoc output is then | |
585 | /// generated from the cleaned AST of the crate. | |
586 | /// | |
587 | /// This form of input will run all of the plug/cleaning passes | |
0531ce1d XL |
588 | fn rust_input<R, F>(cratefile: PathBuf, |
589 | externs: Externs, | |
590 | edition: Edition, | |
83c7162d | 591 | cg: CodegenOptions, |
0531ce1d | 592 | matches: &getopts::Matches, |
83c7162d | 593 | error_format: ErrorOutputType, |
0531ce1d XL |
594 | f: F) -> R |
595 | where R: 'static + Send, | |
596 | F: 'static + Send + FnOnce(Output) -> R | |
597 | { | |
1a4d82fc JJ |
598 | let mut default_passes = !matches.opt_present("no-defaults"); |
599 | let mut passes = matches.opt_strs("passes"); | |
600 | let mut plugins = matches.opt_strs("plugins"); | |
601 | ||
abe05a73 XL |
602 | // We hardcode in the passes here, as this is a new flag and we |
603 | // are generally deprecating passes. | |
604 | if matches.opt_present("document-private-items") { | |
605 | default_passes = false; | |
606 | ||
607 | passes = vec![ | |
abe05a73 XL |
608 | String::from("collapse-docs"), |
609 | String::from("unindent-comments"), | |
610 | ]; | |
611 | } | |
612 | ||
1a4d82fc JJ |
613 | // First, parse the crate and extract all relevant information. |
614 | let mut paths = SearchPaths::new(); | |
85aaf69f | 615 | for s in &matches.opt_strs("L") { |
9cc50fc6 | 616 | paths.add_path(s, ErrorOutputType::default()); |
1a4d82fc JJ |
617 | } |
618 | let cfgs = matches.opt_strs("cfg"); | |
0531ce1d XL |
619 | let triple = matches.opt_str("target").map(|target| { |
620 | if target.ends_with(".json") { | |
621 | TargetTriple::TargetPath(PathBuf::from(target)) | |
622 | } else { | |
623 | TargetTriple::TargetTriple(target) | |
624 | } | |
625 | }); | |
9e0c209e | 626 | let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from); |
476ff2be | 627 | let crate_name = matches.opt_str("crate-name"); |
abe05a73 | 628 | let crate_version = matches.opt_str("crate-version"); |
476ff2be | 629 | let plugin_path = matches.opt_str("plugin-path"); |
1a4d82fc | 630 | |
1a4d82fc | 631 | info!("starting to run rustc"); |
7cac9316 | 632 | let display_warnings = matches.opt_present("display-warnings"); |
1a4d82fc | 633 | |
041b39d2 XL |
634 | let force_unstable_if_unmarked = matches.opt_strs("Z").iter().any(|x| { |
635 | *x == "force-unstable-if-unmarked" | |
636 | }); | |
637 | ||
85aaf69f | 638 | let (tx, rx) = channel(); |
0531ce1d XL |
639 | |
640 | rustc_driver::monitor(move || syntax::with_globals(move || { | |
85aaf69f SL |
641 | use rustc::session::config::Input; |
642 | ||
476ff2be | 643 | let (mut krate, renderinfo) = |
ff7c6d11 | 644 | core::run_core(paths, cfgs, externs, Input::File(cratefile), triple, maybe_sysroot, |
0531ce1d | 645 | display_warnings, crate_name.clone(), |
83c7162d | 646 | force_unstable_if_unmarked, edition, cg, error_format); |
1a4d82fc | 647 | |
476ff2be SL |
648 | info!("finished with rustc"); |
649 | ||
650 | if let Some(name) = crate_name { | |
651 | krate.name = name | |
652 | } | |
1a4d82fc | 653 | |
abe05a73 XL |
654 | krate.version = crate_version; |
655 | ||
94b46f34 XL |
656 | let diag = core::new_handler(error_format, None); |
657 | ||
658 | fn report_deprecated_attr(name: &str, diag: &errors::Handler) { | |
659 | let mut msg = diag.struct_warn(&format!("the `#![doc({})]` attribute is \ | |
660 | considered deprecated", name)); | |
661 | msg.warn("please see https://github.com/rust-lang/rust/issues/44136"); | |
662 | ||
663 | if name == "no_default_passes" { | |
664 | msg.help("you may want to use `#![doc(document_private_items)]`"); | |
665 | } | |
666 | ||
667 | msg.emit(); | |
668 | } | |
669 | ||
476ff2be SL |
670 | // Process all of the crate attributes, extracting plugin metadata along |
671 | // with the passes which we are supposed to run. | |
672 | for attr in krate.module.as_ref().unwrap().attrs.lists("doc") { | |
673 | let name = attr.name().map(|s| s.as_str()); | |
674 | let name = name.as_ref().map(|s| &s[..]); | |
675 | if attr.is_word() { | |
676 | if name == Some("no_default_passes") { | |
94b46f34 | 677 | report_deprecated_attr("no_default_passes", &diag); |
476ff2be SL |
678 | default_passes = false; |
679 | } | |
680 | } else if let Some(value) = attr.value_str() { | |
681 | let sink = match name { | |
94b46f34 XL |
682 | Some("passes") => { |
683 | report_deprecated_attr("passes = \"...\"", &diag); | |
684 | &mut passes | |
685 | }, | |
686 | Some("plugins") => { | |
687 | report_deprecated_attr("plugins = \"...\"", &diag); | |
688 | &mut plugins | |
689 | }, | |
54a0048b SL |
690 | _ => continue, |
691 | }; | |
476ff2be | 692 | for p in value.as_str().split_whitespace() { |
54a0048b | 693 | sink.push(p.to_string()); |
1a4d82fc JJ |
694 | } |
695 | } | |
94b46f34 XL |
696 | |
697 | if attr.is_word() && name == Some("document_private_items") { | |
698 | default_passes = false; | |
699 | ||
700 | passes = vec![ | |
701 | String::from("collapse-docs"), | |
702 | String::from("unindent-comments"), | |
703 | ]; | |
704 | } | |
1a4d82fc | 705 | } |
54a0048b | 706 | |
476ff2be SL |
707 | if default_passes { |
708 | for name in passes::DEFAULT_PASSES.iter().rev() { | |
709 | passes.insert(0, name.to_string()); | |
710 | } | |
1a4d82fc | 711 | } |
1a4d82fc | 712 | |
94b46f34 XL |
713 | if !plugins.is_empty() { |
714 | eprintln!("WARNING: --plugins no longer functions; see CVE-2018-1000622"); | |
83c7162d XL |
715 | } |
716 | ||
94b46f34 XL |
717 | if !plugin_path.is_none() { |
718 | eprintln!("WARNING: --plugin-path no longer functions; see CVE-2018-1000622"); | |
719 | } | |
83c7162d | 720 | |
476ff2be | 721 | // Load all plugins/passes into a PluginManager |
94b46f34 | 722 | let mut pm = plugins::PluginManager::new(); |
476ff2be SL |
723 | for pass in &passes { |
724 | let plugin = match passes::PASSES.iter() | |
725 | .position(|&(p, ..)| { | |
726 | p == *pass | |
727 | }) { | |
728 | Some(i) => passes::PASSES[i].1, | |
729 | None => { | |
730 | error!("unknown pass {}, skipping", *pass); | |
731 | continue | |
732 | }, | |
733 | }; | |
734 | pm.add_plugin(plugin); | |
735 | } | |
476ff2be SL |
736 | |
737 | // Run everything! | |
738 | info!("Executing passes/plugins"); | |
739 | let krate = pm.run_plugins(krate); | |
1a4d82fc | 740 | |
476ff2be | 741 | tx.send(f(Output { krate: krate, renderinfo: renderinfo, passes: passes })).unwrap(); |
0531ce1d | 742 | })); |
476ff2be | 743 | rx.recv().unwrap() |
1a4d82fc | 744 | } |
abe05a73 XL |
745 | |
746 | /// Prints deprecation warnings for deprecated options | |
94b46f34 | 747 | fn check_deprecated_options(matches: &getopts::Matches, diag: &errors::Handler) { |
abe05a73 XL |
748 | let deprecated_flags = [ |
749 | "input-format", | |
750 | "output-format", | |
abe05a73 XL |
751 | "no-defaults", |
752 | "passes", | |
753 | ]; | |
754 | ||
755 | for flag in deprecated_flags.into_iter() { | |
756 | if matches.opt_present(flag) { | |
94b46f34 XL |
757 | let mut err = diag.struct_warn(&format!("the '{}' flag is considered deprecated", |
758 | flag)); | |
759 | err.warn("please see https://github.com/rust-lang/rust/issues/44136"); | |
760 | ||
761 | if *flag == "no-defaults" { | |
762 | err.help("you may want to use --document-private-items"); | |
763 | } | |
abe05a73 | 764 | |
94b46f34 XL |
765 | err.emit(); |
766 | } | |
abe05a73 XL |
767 | } |
768 | } |