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