1#![doc(
3 html_root_url = "https://doc.rust-lang.org/nightly/",
4 html_playground_url = "https://play.rust-lang.org/"
5)]
6#![feature(ascii_char)]
7#![feature(ascii_char_variants)]
8#![feature(box_patterns)]
9#![feature(file_buffered)]
10#![feature(formatting_options)]
11#![feature(iter_intersperse)]
12#![feature(iter_order_by)]
13#![feature(rustc_private)]
14#![feature(test)]
15#![feature(trim_prefix_suffix)]
16#![recursion_limit = "256"]
17#![warn(rustc::internal)]
18extern crate rustc_abi;
29extern crate rustc_ast;
30extern crate rustc_ast_pretty;
31extern crate rustc_attr_parsing;
32extern crate rustc_data_structures;
33extern crate rustc_driver;
34extern crate rustc_errors;
35extern crate rustc_feature;
36extern crate rustc_hir;
37extern crate rustc_hir_analysis;
38extern crate rustc_hir_pretty;
39extern crate rustc_index;
40extern crate rustc_infer;
41extern crate rustc_interface;
42extern crate rustc_lexer;
43extern crate rustc_lint;
44extern crate rustc_lint_defs;
45extern crate rustc_log;
46extern crate rustc_macros;
47extern crate rustc_metadata;
48extern crate rustc_middle;
49extern crate rustc_parse;
50extern crate rustc_passes;
51extern crate rustc_resolve;
52extern crate rustc_serialize;
53extern crate rustc_session;
54extern crate rustc_span;
55extern crate rustc_target;
56extern crate rustc_trait_selection;
57extern crate test;
58
59#[cfg(feature = "jemalloc")]
66extern crate tikv_jemalloc_sys as _;
67
68use std::env::{self, VarError};
69use std::io::{self, IsTerminal};
70use std::path::Path;
71use std::process::ExitCode;
72
73use rustc_ast::ast;
74use rustc_errors::DiagCtxtHandle;
75use rustc_hir::def_id::LOCAL_CRATE;
76use rustc_interface::interface;
77use rustc_middle::ty::TyCtxt;
78use rustc_session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option};
79use rustc_session::{EarlyDiagCtxt, getopts};
80use rustc_span::{BytePos, Span, SyntaxContext};
81use tracing::info;
82
83use crate::clean::utils::DOC_RUST_LANG_ORG_VERSION;
84use crate::error::Error;
85use crate::formats::cache::Cache;
86
87macro_rules! map {
98 ($( $key: expr => $val: expr ),* $(,)*) => {{
99 let mut map = ::rustc_data_structures::fx::FxIndexMap::default();
100 $( map.insert($key, $val); )*
101 map
102 }}
103}
104
105mod clean;
106mod config;
107mod core;
108mod display;
109mod docfs;
110mod doctest;
111mod error;
112mod externalfiles;
113mod fold;
114mod formats;
115pub mod html;
117mod json;
118pub(crate) mod lint;
119mod markdown;
120mod passes;
121mod scrape_examples;
122mod theme;
123mod visit;
124mod visit_ast;
125mod visit_lib;
126
127pub fn main() -> ExitCode {
128 let mut early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
129
130 rustc_driver::install_ice_hook(
131 "https://github.com/rust-lang/rust/issues/new\
132 ?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md",
133 |_| (),
134 );
135
136 crate::init_logging(&early_dcx);
144 match rustc_log::init_logger(rustc_log::LoggerConfig::from_env("RUSTDOC_LOG")) {
145 Ok(()) => {}
146 Err(rustc_log::Error::AlreadyInit(_)) => {}
162 Err(error) => early_dcx.early_fatal(error.to_string()),
163 }
164
165 rustc_driver::catch_with_exit_code(|| {
166 let at_args = rustc_driver::args::raw_args(&early_dcx);
167 main_args(&mut early_dcx, &at_args);
168 })
169}
170
171fn init_logging(early_dcx: &EarlyDiagCtxt) {
172 let color_logs = match env::var("RUSTDOC_LOG_COLOR").as_deref() {
173 Ok("always") => true,
174 Ok("never") => false,
175 Ok("auto") | Err(VarError::NotPresent) => io::stdout().is_terminal(),
176 Ok(value) => early_dcx.early_fatal(format!(
177 "invalid log color value '{value}': expected one of always, never, or auto",
178 )),
179 Err(VarError::NotUnicode(value)) => early_dcx.early_fatal(format!(
180 "invalid log color value '{}': expected one of always, never, or auto",
181 value.to_string_lossy()
182 )),
183 };
184 let filter = tracing_subscriber::EnvFilter::from_env("RUSTDOC_LOG");
185 let layer = tracing_tree::HierarchicalLayer::default()
186 .with_writer(io::stderr)
187 .with_ansi(color_logs)
188 .with_targets(true)
189 .with_wraparound(10)
190 .with_verbose_exit(true)
191 .with_verbose_entry(true)
192 .with_indent_amount(2);
193 #[cfg(debug_assertions)]
194 let layer = layer.with_thread_ids(true).with_thread_names(true);
195
196 use tracing_subscriber::layer::SubscriberExt;
197 let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
198 tracing::subscriber::set_global_default(subscriber).unwrap();
199}
200
201fn opts() -> Vec<RustcOptGroup> {
202 use rustc_session::config::OptionKind::{Flag, FlagMulti, Multi, Opt};
203 use rustc_session::config::OptionStability::{Stable, Unstable};
204 use rustc_session::config::make_opt as opt;
205
206 vec![
207 opt(Stable, FlagMulti, "h", "help", "show this help message", ""),
208 opt(Stable, FlagMulti, "V", "version", "print rustdoc's version", ""),
209 opt(Stable, FlagMulti, "v", "verbose", "use verbose output", ""),
210 opt(Stable, Opt, "w", "output-format", "the output type to write", "[html]"),
211 opt(
212 Stable,
213 Opt,
214 "",
215 "output",
216 "Which directory to place the output. This option is deprecated, use --out-dir instead.",
217 "PATH",
218 ),
219 opt(Stable, Opt, "o", "out-dir", "which directory to place the output", "PATH"),
220 opt(Stable, Opt, "", "crate-name", "specify the name of this crate", "NAME"),
221 make_crate_type_option(),
222 opt(Stable, Multi, "L", "library-path", "directory to add to crate search path", "DIR"),
223 opt(Stable, Multi, "", "cfg", "pass a --cfg to rustc", ""),
224 opt(Stable, Multi, "", "check-cfg", "pass a --check-cfg to rustc", ""),
225 opt(Stable, Multi, "", "extern", "pass an --extern to rustc", "NAME[=PATH]"),
226 opt(
227 Unstable,
228 Multi,
229 "",
230 "extern-html-root-url",
231 "base URL to use for dependencies; for example, \
232 \"std=/doc\" links std::vec::Vec to /doc/std/vec/struct.Vec.html",
233 "NAME=URL",
234 ),
235 opt(
236 Unstable,
237 FlagMulti,
238 "",
239 "extern-html-root-takes-precedence",
240 "give precedence to `--extern-html-root-url`, not `html_root_url`",
241 "",
242 ),
243 opt(Stable, Multi, "C", "codegen", "pass a codegen option to rustc", "OPT[=VALUE]"),
244 opt(Stable, FlagMulti, "", "document-private-items", "document private items", ""),
245 opt(
246 Unstable,
247 FlagMulti,
248 "",
249 "document-hidden-items",
250 "document items that have doc(hidden)",
251 "",
252 ),
253 opt(Stable, FlagMulti, "", "test", "run code examples as tests", ""),
254 opt(Stable, Multi, "", "test-args", "arguments to pass to the test runner", "ARGS"),
255 opt(
256 Stable,
257 Opt,
258 "",
259 "test-run-directory",
260 "The working directory in which to run tests",
261 "PATH",
262 ),
263 opt(Stable, Opt, "", "target", "target triple to document", "TRIPLE"),
264 opt(
265 Stable,
266 Multi,
267 "",
268 "markdown-css",
269 "CSS files to include via <link> in a rendered Markdown file",
270 "FILES",
271 ),
272 opt(
273 Stable,
274 Multi,
275 "",
276 "html-in-header",
277 "files to include inline in the <head> section of a rendered Markdown file \
278 or generated documentation",
279 "FILES",
280 ),
281 opt(
282 Stable,
283 Multi,
284 "",
285 "html-before-content",
286 "files to include inline between <body> and the content of a rendered \
287 Markdown file or generated documentation",
288 "FILES",
289 ),
290 opt(
291 Stable,
292 Multi,
293 "",
294 "html-after-content",
295 "files to include inline between the content and </body> of a rendered \
296 Markdown file or generated documentation",
297 "FILES",
298 ),
299 opt(
300 Unstable,
301 Multi,
302 "",
303 "markdown-before-content",
304 "files to include inline between <body> and the content of a rendered \
305 Markdown file or generated documentation",
306 "FILES",
307 ),
308 opt(
309 Unstable,
310 Multi,
311 "",
312 "markdown-after-content",
313 "files to include inline between the content and </body> of a rendered \
314 Markdown file or generated documentation",
315 "FILES",
316 ),
317 opt(Stable, Opt, "", "markdown-playground-url", "URL to send code snippets to", "URL"),
318 opt(Stable, FlagMulti, "", "markdown-no-toc", "don't include table of contents", ""),
319 opt(
320 Stable,
321 Opt,
322 "e",
323 "extend-css",
324 "To add some CSS rules with a given file to generate doc with your own theme. \
325 However, your theme might break if the rustdoc's generated HTML changes, so be careful!",
326 "PATH",
327 ),
328 opt(
329 Unstable,
330 Multi,
331 "Z",
332 "",
333 "unstable / perma-unstable options (only on nightly build)",
334 "FLAG",
335 ),
336 opt(Stable, Opt, "", "sysroot", "Override the system root", "PATH"),
337 opt(
338 Unstable,
339 Opt,
340 "",
341 "playground-url",
342 "URL to send code snippets to, may be reset by --markdown-playground-url \
343 or `#![doc(html_playground_url=...)]`",
344 "URL",
345 ),
346 opt(
347 Unstable,
348 FlagMulti,
349 "",
350 "display-doctest-warnings",
351 "show warnings that originate in doctests",
352 "",
353 ),
354 opt(
355 Stable,
356 Opt,
357 "",
358 "crate-version",
359 "crate version to print into documentation",
360 "VERSION",
361 ),
362 opt(
363 Unstable,
364 FlagMulti,
365 "",
366 "sort-modules-by-appearance",
367 "sort modules by where they appear in the program, rather than alphabetically",
368 "",
369 ),
370 opt(
371 Stable,
372 Opt,
373 "",
374 "default-theme",
375 "Set the default theme. THEME should be the theme name, generally lowercase. \
376 If an unknown default theme is specified, the builtin default is used. \
377 The set of themes, and the rustdoc built-in default, are not stable.",
378 "THEME",
379 ),
380 opt(
381 Unstable,
382 Multi,
383 "",
384 "default-setting",
385 "Default value for a rustdoc setting (used when \"rustdoc-SETTING\" is absent \
386 from web browser Local Storage). If VALUE is not supplied, \"true\" is used. \
387 Supported SETTINGs and VALUEs are not documented and not stable.",
388 "SETTING[=VALUE]",
389 ),
390 opt(
391 Stable,
392 Multi,
393 "",
394 "theme",
395 "additional themes which will be added to the generated docs",
396 "FILES",
397 ),
398 opt(Stable, Multi, "", "check-theme", "check if given theme is valid", "FILES"),
399 opt(
400 Unstable,
401 Opt,
402 "",
403 "resource-suffix",
404 "suffix to add to CSS and JavaScript files, \
405 e.g., \"search-index.js\" will become \"search-index-suffix.js\"",
406 "PATH",
407 ),
408 opt(
409 Stable,
410 Opt,
411 "",
412 "edition",
413 "edition to use when compiling rust code (default: 2015)",
414 "EDITION",
415 ),
416 opt(
417 Stable,
418 Opt,
419 "",
420 "color",
421 "Configure coloring of output:
422 auto = colorize, if output goes to a tty (default);
423 always = always colorize output;
424 never = never colorize output",
425 "auto|always|never",
426 ),
427 opt(
428 Stable,
429 Opt,
430 "",
431 "error-format",
432 "How errors and other messages are produced",
433 "human|json|short",
434 ),
435 opt(
436 Stable,
437 Opt,
438 "",
439 "diagnostic-width",
440 "Provide width of the output for truncated error messages",
441 "WIDTH",
442 ),
443 opt(Stable, Opt, "", "json", "Configure the structure of JSON diagnostics", "CONFIG"),
444 opt(Stable, Multi, "A", "allow", "Set lint allowed", "LINT"),
445 opt(Stable, Multi, "W", "warn", "Set lint warnings", "LINT"),
446 opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "LINT"),
447 opt(Stable, Multi, "D", "deny", "Set lint denied", "LINT"),
448 opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "LINT"),
449 opt(
450 Stable,
451 Multi,
452 "",
453 "cap-lints",
454 "Set the most restrictive lint level. \
455 More restrictive lints are capped at this level. \
456 By default, it is at `forbid` level.",
457 "LEVEL",
458 ),
459 opt(Unstable, Opt, "", "index-page", "Markdown file to be used as index page", "PATH"),
460 opt(
461 Unstable,
462 FlagMulti,
463 "",
464 "enable-index-page",
465 "To enable generation of the index page",
466 "",
467 ),
468 opt(
469 Unstable,
470 Opt,
471 "",
472 "static-root-path",
473 "Path string to force loading static files from in output pages. \
474 If not set, uses combinations of '../' to reach the documentation root.",
475 "PATH",
476 ),
477 opt(
478 Unstable,
479 Opt,
480 "",
481 "persist-doctests",
482 "Directory to persist doctest executables into",
483 "PATH",
484 ),
485 opt(
486 Unstable,
487 FlagMulti,
488 "",
489 "show-coverage",
490 "calculate percentage of public items with documentation",
491 "",
492 ),
493 opt(
494 Stable,
495 Opt,
496 "",
497 "test-runtool",
498 "",
499 "The tool to run tests with when building for a different target than host",
500 ),
501 opt(
502 Stable,
503 Multi,
504 "",
505 "test-runtool-arg",
506 "",
507 "One argument (of possibly many) to pass to the runtool",
508 ),
509 opt(
510 Unstable,
511 Opt,
512 "",
513 "test-builder",
514 "The rustc-like binary to use as the test builder",
515 "PATH",
516 ),
517 opt(
518 Unstable,
519 Multi,
520 "",
521 "test-builder-wrapper",
522 "Wrapper program to pass test-builder and arguments",
523 "PATH",
524 ),
525 opt(Unstable, FlagMulti, "", "check", "Run rustdoc checks", ""),
526 opt(
527 Unstable,
528 FlagMulti,
529 "",
530 "generate-redirect-map",
531 "Generate JSON file at the top level instead of generating HTML redirection files",
532 "",
533 ),
534 opt(
535 Unstable,
536 Multi,
537 "",
538 "emit",
539 "Comma separated list of types of output for rustdoc to emit",
540 "[html-static-files,html-non-static-files,dep-info]",
541 ),
542 opt(Unstable, FlagMulti, "", "no-run", "Compile doctests without running them", ""),
543 opt(
544 Unstable,
545 Opt,
546 "",
547 "merge-doctests",
548 "Force all doctests to be compiled as a single binary, instead of one binary per test. If merging fails, rustdoc will emit a hard error.",
549 "yes|no|auto",
550 ),
551 opt(
552 Unstable,
553 Multi,
554 "",
555 "remap-path-prefix",
556 "Remap source names in compiler messages",
557 "FROM=TO",
558 ),
559 opt(
560 Unstable,
561 Opt,
562 "",
563 "remap-path-scope",
564 "Defines which scopes of paths should be remapped by `--remap-path-prefix`",
565 "[macro,diagnostics,debuginfo,coverage,object,all]",
566 ),
567 opt(
568 Unstable,
569 FlagMulti,
570 "",
571 "show-type-layout",
572 "Include the memory layout of types in the docs",
573 "",
574 ),
575 opt(Unstable, Flag, "", "no-capture", "Don't capture stdout and stderr of tests", ""),
576 opt(
577 Unstable,
578 Flag,
579 "",
580 "generate-link-to-definition",
581 "Make the identifiers in the HTML source code pages navigable",
582 "",
583 ),
584 opt(
585 Unstable,
586 Opt,
587 "",
588 "scrape-examples-output-path",
589 "",
590 "collect function call information and output at the given path",
591 ),
592 opt(
593 Unstable,
594 Multi,
595 "",
596 "scrape-examples-target-crate",
597 "",
598 "collect function call information for functions from the target crate",
599 ),
600 opt(Unstable, Flag, "", "scrape-tests", "Include test code when scraping examples", ""),
601 opt(
602 Unstable,
603 Multi,
604 "",
605 "with-examples",
606 "",
607 "path to function call information (for displaying examples in the documentation)",
608 ),
609 opt(
610 Unstable,
611 Opt,
612 "",
613 "merge",
614 "Controls how rustdoc handles files from previously documented crates in the doc root\n\
615 none = Do not write cross-crate information to the --out-dir\n\
616 shared = Append current crate's info to files found in the --out-dir\n\
617 finalize = Write current crate's info and --include-parts-dir info to the --out-dir, overwriting conflicting files",
618 "none|shared|finalize",
619 ),
620 opt(
621 Unstable,
622 Opt,
623 "",
624 "parts-out-dir",
625 "Writes trait implementations and other info for the current crate to provided path. Only use with --merge=none",
626 "path/to/doc.parts/<crate-name>",
627 ),
628 opt(
629 Unstable,
630 Multi,
631 "",
632 "include-parts-dir",
633 "Includes trait implementations and other crate info from provided path. Only use with --merge=finalize",
634 "path/to/doc.parts/<crate-name>",
635 ),
636 opt(Unstable, Flag, "", "html-no-source", "Disable HTML source code pages generation", ""),
637 opt(
638 Unstable,
639 Multi,
640 "",
641 "doctest-build-arg",
642 "One argument (of possibly many) to be used when compiling doctests",
643 "ARG",
644 ),
645 opt(
646 Unstable,
647 FlagMulti,
648 "",
649 "disable-minification",
650 "disable the minification of CSS/JS files (perma-unstable, do not use with cached files)",
651 "",
652 ),
653 opt(
654 Unstable,
655 Flag,
656 "",
657 "generate-macro-expansion",
658 "Add possibility to expand macros in the HTML source code pages",
659 "",
660 ),
661 opt(
663 Stable,
664 Multi,
665 "",
666 "plugin-path",
667 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
668 "DIR",
669 ),
670 opt(
671 Stable,
672 Multi,
673 "",
674 "passes",
675 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
676 "PASSES",
677 ),
678 opt(
679 Stable,
680 Multi,
681 "",
682 "plugins",
683 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
684 "PLUGINS",
685 ),
686 opt(
687 Stable,
688 FlagMulti,
689 "",
690 "no-defaults",
691 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
692 "",
693 ),
694 opt(
695 Stable,
696 Opt,
697 "r",
698 "input-format",
699 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
700 "[rust]",
701 ),
702 ]
703}
704
705fn usage(argv0: &str) {
706 let mut options = getopts::Options::new();
707 for option in opts() {
708 option.apply(&mut options);
709 }
710 println!("{}", options.usage(&format!("{argv0} [options] <input>")));
711 println!(" @path Read newline separated options from `path`\n");
712 println!(
713 "More information available at {DOC_RUST_LANG_ORG_VERSION}/rustdoc/what-is-rustdoc.html",
714 );
715}
716
717pub(crate) fn wrap_return(dcx: DiagCtxtHandle<'_>, res: Result<(), String>) {
718 match res {
719 Ok(()) => dcx.abort_if_errors(),
720 Err(err) => dcx.fatal(err),
721 }
722}
723
724fn run_renderer<
725 'tcx,
726 T: formats::FormatRenderer<'tcx>,
727 F: FnOnce(
728 clean::Crate,
729 config::RenderOptions,
730 Cache,
731 TyCtxt<'tcx>,
732 ) -> Result<(T, clean::Crate), Error>,
733>(
734 krate: clean::Crate,
735 renderopts: config::RenderOptions,
736 cache: formats::cache::Cache,
737 tcx: TyCtxt<'tcx>,
738 init: F,
739) {
740 match formats::run_format::<T, F>(krate, renderopts, cache, tcx, init) {
741 Ok(_) => tcx.dcx().abort_if_errors(),
742 Err(e) => {
743 let mut msg =
744 tcx.dcx().struct_fatal(format!("couldn't generate documentation: {}", e.error));
745 let file = e.file.display().to_string();
746 if !file.is_empty() {
747 msg.note(format!("failed to create or modify {e}"));
748 } else {
749 msg.note(format!("failed to create or modify file: {e}"));
750 }
751 msg.emit();
752 }
753 }
754}
755
756fn run_merge_finalize(opt: config::RenderOptions) -> Result<(), error::Error> {
760 assert!(
761 opt.should_merge.write_rendered_cci,
762 "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
763 );
764 assert!(
765 !opt.should_merge.read_rendered_cci,
766 "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
767 );
768 let crates = html::render::CrateInfo::read_many(&opt.include_parts_dir)?;
769 let include_sources = !opt.html_no_source;
770 html::render::write_not_crate_specific(
771 &crates,
772 &opt.output,
773 &opt,
774 &opt.themes,
775 opt.extension_css.as_deref(),
776 &opt.resource_suffix,
777 include_sources,
778 )?;
779 Ok(())
780}
781
782fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
783 let at_args = at_args.get(1..).unwrap_or_default();
792
793 let args = rustc_driver::args::arg_expand_all(early_dcx, at_args);
794
795 let mut options = getopts::Options::new();
796 for option in opts() {
797 option.apply(&mut options);
798 }
799 let matches = match options.parse(&args) {
800 Ok(m) => m,
801 Err(err) => {
802 early_dcx.early_fatal(err.to_string());
803 }
804 };
805
806 let (input, options, render_options, loaded_paths) =
809 match config::Options::from_matches(early_dcx, &matches, args) {
810 Some(opts) => opts,
811 None => return,
812 };
813
814 let dcx =
815 core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts);
816 let dcx = dcx.handle();
817
818 let input = match input {
819 config::InputMode::HasFile(input) => input,
820 config::InputMode::NoInputMergeFinalize => {
821 return wrap_return(
822 dcx,
823 rustc_span::create_session_globals_then(options.edition, &[], None, || {
824 run_merge_finalize(render_options)
825 .map_err(|e| format!("could not write merged cross-crate info: {e}"))
826 }),
827 );
828 }
829 };
830
831 let output_format = options.output_format;
832
833 match (
834 options.should_test || output_format == config::OutputFormat::Doctest,
835 config::markdown_input(&input),
836 ) {
837 (true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(&input, options, dcx)),
838 (true, None) => return doctest::run(dcx, input, options),
839 (false, Some(md_input)) => {
840 let md_input = md_input.to_owned();
841 let edition = options.edition;
842 let config = core::create_config(input, options, &render_options);
843
844 return wrap_return(
848 dcx,
849 interface::run_compiler(config, |compiler| {
850 let file =
853 compiler.sess.source_map().load_file(&md_input).map_err(|e| {
854 format!("{md_input}: {e}", md_input = md_input.display())
855 })?;
856 let inner_span = Span::new(
857 file.start_pos,
858 BytePos(file.start_pos.0 + file.normalized_source_len.0),
859 SyntaxContext::root(),
860 None,
861 );
862 let krate = ast::Crate {
863 attrs: Default::default(),
864 items: Default::default(),
865 spans: ast::ModSpans { inner_span, ..Default::default() },
866 id: ast::DUMMY_NODE_ID,
867 is_placeholder: false,
868 };
869 rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
870 let has_dep_info = render_options.dep_info().is_some();
871 markdown::render_and_write(file, render_options, edition)?;
872 if has_dep_info {
873 for external_path in &loaded_paths {
876 let _ = compiler.sess.source_map().load_binary_file(external_path);
877 }
878 rustc_interface::passes::write_dep_info(tcx);
879 }
880 Ok(())
881 })
882 }),
883 );
884 }
885 (false, None) => {}
886 }
887
888 let show_coverage = options.show_coverage;
891 let run_check = options.run_check;
892
893 info!("starting to run rustc");
895
896 let crate_version = options.crate_version.clone();
901
902 let scrape_examples_options = options.scrape_examples_options.clone();
903 let bin_crate = options.bin_crate;
904
905 let output_format = options.output_format;
906 let config = core::create_config(input, options, &render_options);
907
908 let registered_lints = config.register_lints.is_some();
909
910 interface::run_compiler(config, |compiler| {
911 let sess = &compiler.sess;
912
913 for external_path in &loaded_paths {
916 let _ = sess.source_map().load_binary_file(external_path);
917 }
918
919 if sess.opts.describe_lints {
920 rustc_driver::describe_lints(sess, registered_lints);
921 return;
922 }
923
924 let krate = rustc_interface::passes::parse(sess);
925 rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
926 if sess.dcx().has_errors().is_some() {
927 sess.dcx().fatal("Compilation failed, aborting rustdoc");
928 }
929
930 let (krate, render_opts, mut cache, expanded_macros) = sess
931 .time("run_global_ctxt", || {
932 core::run_global_ctxt(tcx, show_coverage, render_options, output_format)
933 });
934 info!("finished with rustc");
935
936 if let Some(options) = scrape_examples_options {
937 return scrape_examples::run(krate, render_opts, cache, tcx, options, bin_crate);
938 }
939
940 cache.crate_version = crate_version;
941
942 if show_coverage {
943 return;
946 }
947
948 rustc_interface::passes::emit_delayed_lints(tcx);
949
950 if render_opts.dep_info().is_some() {
951 rustc_interface::passes::write_dep_info(tcx);
952 }
953
954 if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
955 dump_feature_usage_metrics(tcx, metrics_dir);
956 }
957
958 if run_check {
959 return;
961 }
962
963 info!("going to format");
964 match output_format {
965 config::OutputFormat::Html => sess.time("render_html", || {
966 run_renderer(
967 krate,
968 render_opts,
969 cache,
970 tcx,
971 |krate, render_opts, cache, tcx| {
972 html::render::Context::init(
973 krate,
974 render_opts,
975 cache,
976 tcx,
977 expanded_macros,
978 )
979 },
980 )
981 }),
982 config::OutputFormat::Json => sess.time("render_json", || {
983 run_renderer(krate, render_opts, cache, tcx, json::JsonRenderer::init)
984 }),
985 config::OutputFormat::Doctest => unreachable!(),
987 }
988 })
989 })
990}
991
992fn dump_feature_usage_metrics(tcx: TyCtxt<'_>, metrics_dir: &Path) {
993 let hash = tcx.crate_hash(LOCAL_CRATE);
994 let crate_name = tcx.crate_name(LOCAL_CRATE);
995 let metrics_file_name = format!("unstable_feature_usage_metrics-{crate_name}-{hash}.json");
996 let metrics_path = metrics_dir.join(metrics_file_name);
997 if let Err(error) = tcx.features().dump_feature_usage_metrics(metrics_path) {
998 tcx.dcx().err(format!("cannot emit feature usage metrics: {error}"));
1002 }
1003}