]> git.proxmox.com Git - rustc.git/blame - src/librustdoc/lib.rs
New upstream version 1.28.0+dfsg1
[rustc.git] / src / librustdoc / lib.rs
CommitLineData
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
30extern crate arena;
31extern crate getopts;
cc61c64b 32extern crate env_logger;
1a4d82fc 33extern crate rustc;
9e0c209e 34extern crate rustc_data_structures;
94b46f34 35extern crate rustc_codegen_utils;
1a4d82fc 36extern crate rustc_driver;
85aaf69f 37extern crate rustc_resolve;
c34b1796 38extern crate rustc_lint;
92a42be0 39extern crate rustc_metadata;
83c7162d 40extern crate rustc_target;
7cac9316 41extern crate rustc_typeck;
1a4d82fc 42extern crate serialize;
54a0048b 43#[macro_use] extern crate syntax;
3157f602 44extern crate syntax_pos;
c34b1796 45extern crate test as testing;
1a4d82fc 46#[macro_use] extern crate log;
3157f602 47extern crate rustc_errors as errors;
cc61c64b 48extern crate pulldown_cmark;
ff7c6d11 49extern crate tempdir;
94b46f34 50extern crate minifier;
1a4d82fc 51
c34b1796 52extern crate serialize as rustc_serialize; // used by deriving
1a4d82fc 53
83c7162d
XL
54use errors::ColorConfig;
55
5bcae85e 56use std::collections::{BTreeMap, BTreeSet};
9cc50fc6 57use std::default::Default;
85aaf69f 58use std::env;
ff7c6d11 59use std::path::{Path, PathBuf};
62682a34 60use std::process;
85aaf69f 61use std::sync::mpsc::channel;
c34b1796 62
0531ce1d 63use syntax::edition::Edition;
1a4d82fc 64use externalfiles::ExternalHtml;
94b46f34 65use rustc::session::{early_warn, early_error};
1a4d82fc 66use rustc::session::search_paths::SearchPaths;
83c7162d
XL
67use rustc::session::config::{ErrorOutputType, RustcOptGroup, Externs, CodegenOptions};
68use rustc::session::config::{nightly_options, build_codegen_options};
69use rustc_target::spec::TargetTriple;
1a4d82fc
JJ
70
71#[macro_use]
72pub mod externalfiles;
73
74pub mod clean;
75pub mod core;
76pub mod doctree;
77pub mod fold;
78pub 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}
88pub mod markdown;
89pub mod passes;
90pub mod plugins;
1a4d82fc 91pub mod visit_ast;
a7813a04 92pub mod visit_lib;
1a4d82fc 93pub mod test;
2c00a5a8 94pub mod theme;
1a4d82fc 95
476ff2be 96use clean::AttributesExt;
54a0048b 97
1a4d82fc
JJ
98struct Output {
99 krate: clean::Crate,
a7813a04 100 renderinfo: html::render::RenderInfo,
1a4d82fc
JJ
101 passes: Vec<String>,
102}
103
104pub 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
116fn 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
125fn 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
131fn 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
137pub 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
309pub 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 317pub 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 550fn 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>
558where 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
569fn 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
588fn 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
595where 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 747fn 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}