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