1#![cfg_attr(bootstrap, feature(assert_matches))]
3#![cfg_attr(bootstrap, feature(if_let_guard))]
4#![doc(
5 html_root_url = "https://doc.rust-lang.org/nightly/",
6 html_playground_url = "https://play.rust-lang.org/"
7)]
8#![feature(ascii_char)]
9#![feature(ascii_char_variants)]
10#![feature(box_patterns)]
11#![feature(file_buffered)]
12#![feature(formatting_options)]
13#![feature(iter_intersperse)]
14#![feature(iter_order_by)]
15#![feature(rustc_private)]
16#![feature(test)]
17#![feature(trim_prefix_suffix)]
18#![recursion_limit = "256"]
19#![warn(rustc::internal)]
20extern crate rustc_abi;
31extern crate rustc_ast;
32extern crate rustc_ast_pretty;
33extern crate rustc_attr_parsing;
34extern crate rustc_data_structures;
35extern crate rustc_driver;
36extern crate rustc_errors;
37extern crate rustc_feature;
38extern crate rustc_hir;
39extern crate rustc_hir_analysis;
40extern crate rustc_hir_pretty;
41extern crate rustc_index;
42extern crate rustc_infer;
43extern crate rustc_interface;
44extern crate rustc_lexer;
45extern crate rustc_lint;
46extern crate rustc_lint_defs;
47extern crate rustc_log;
48extern crate rustc_macros;
49extern crate rustc_metadata;
50extern crate rustc_middle;
51extern crate rustc_parse;
52extern crate rustc_passes;
53extern crate rustc_resolve;
54extern crate rustc_serialize;
55extern crate rustc_session;
56extern crate rustc_span;
57extern crate rustc_target;
58extern crate rustc_trait_selection;
59extern crate test;
60
61#[cfg(feature = "jemalloc")]
68extern crate tikv_jemalloc_sys as _;
69
70use std::env::{self, VarError};
71use std::io::{self, IsTerminal};
72use std::path::Path;
73use std::process::ExitCode;
74
75use rustc_errors::DiagCtxtHandle;
76use rustc_hir::def_id::LOCAL_CRATE;
77use rustc_interface::interface;
78use rustc_middle::ty::TyCtxt;
79use rustc_session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option};
80use rustc_session::{EarlyDiagCtxt, getopts};
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 "[toolchain-shared-resources,invocation-specific,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 FlagMulti,
562 "",
563 "show-type-layout",
564 "Include the memory layout of types in the docs",
565 "",
566 ),
567 opt(Unstable, Flag, "", "no-capture", "Don't capture stdout and stderr of tests", ""),
568 opt(
569 Unstable,
570 Flag,
571 "",
572 "generate-link-to-definition",
573 "Make the identifiers in the HTML source code pages navigable",
574 "",
575 ),
576 opt(
577 Unstable,
578 Opt,
579 "",
580 "scrape-examples-output-path",
581 "",
582 "collect function call information and output at the given path",
583 ),
584 opt(
585 Unstable,
586 Multi,
587 "",
588 "scrape-examples-target-crate",
589 "",
590 "collect function call information for functions from the target crate",
591 ),
592 opt(Unstable, Flag, "", "scrape-tests", "Include test code when scraping examples", ""),
593 opt(
594 Unstable,
595 Multi,
596 "",
597 "with-examples",
598 "",
599 "path to function call information (for displaying examples in the documentation)",
600 ),
601 opt(
602 Unstable,
603 Opt,
604 "",
605 "merge",
606 "Controls how rustdoc handles files from previously documented crates in the doc root\n\
607 none = Do not write cross-crate information to the --out-dir\n\
608 shared = Append current crate's info to files found in the --out-dir\n\
609 finalize = Write current crate's info and --include-parts-dir info to the --out-dir, overwriting conflicting files",
610 "none|shared|finalize",
611 ),
612 opt(
613 Unstable,
614 Opt,
615 "",
616 "parts-out-dir",
617 "Writes trait implementations and other info for the current crate to provided path. Only use with --merge=none",
618 "path/to/doc.parts/<crate-name>",
619 ),
620 opt(
621 Unstable,
622 Multi,
623 "",
624 "include-parts-dir",
625 "Includes trait implementations and other crate info from provided path. Only use with --merge=finalize",
626 "path/to/doc.parts/<crate-name>",
627 ),
628 opt(Unstable, Flag, "", "html-no-source", "Disable HTML source code pages generation", ""),
629 opt(
630 Unstable,
631 Multi,
632 "",
633 "doctest-build-arg",
634 "One argument (of possibly many) to be used when compiling doctests",
635 "ARG",
636 ),
637 opt(
638 Unstable,
639 FlagMulti,
640 "",
641 "disable-minification",
642 "disable the minification of CSS/JS files (perma-unstable, do not use with cached files)",
643 "",
644 ),
645 opt(
646 Unstable,
647 Flag,
648 "",
649 "generate-macro-expansion",
650 "Add possibility to expand macros in the HTML source code pages",
651 "",
652 ),
653 opt(
655 Stable,
656 Multi,
657 "",
658 "plugin-path",
659 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
660 "DIR",
661 ),
662 opt(
663 Stable,
664 Multi,
665 "",
666 "passes",
667 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
668 "PASSES",
669 ),
670 opt(
671 Stable,
672 Multi,
673 "",
674 "plugins",
675 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
676 "PLUGINS",
677 ),
678 opt(
679 Stable,
680 FlagMulti,
681 "",
682 "no-defaults",
683 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
684 "",
685 ),
686 opt(
687 Stable,
688 Opt,
689 "r",
690 "input-format",
691 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
692 "[rust]",
693 ),
694 ]
695}
696
697fn usage(argv0: &str) {
698 let mut options = getopts::Options::new();
699 for option in opts() {
700 option.apply(&mut options);
701 }
702 println!("{}", options.usage(&format!("{argv0} [options] <input>")));
703 println!(" @path Read newline separated options from `path`\n");
704 println!(
705 "More information available at {DOC_RUST_LANG_ORG_VERSION}/rustdoc/what-is-rustdoc.html",
706 );
707}
708
709pub(crate) fn wrap_return(dcx: DiagCtxtHandle<'_>, res: Result<(), String>) {
710 match res {
711 Ok(()) => dcx.abort_if_errors(),
712 Err(err) => dcx.fatal(err),
713 }
714}
715
716fn run_renderer<
717 'tcx,
718 T: formats::FormatRenderer<'tcx>,
719 F: FnOnce(
720 clean::Crate,
721 config::RenderOptions,
722 Cache,
723 TyCtxt<'tcx>,
724 ) -> Result<(T, clean::Crate), Error>,
725>(
726 krate: clean::Crate,
727 renderopts: config::RenderOptions,
728 cache: formats::cache::Cache,
729 tcx: TyCtxt<'tcx>,
730 init: F,
731) {
732 match formats::run_format::<T, F>(krate, renderopts, cache, tcx, init) {
733 Ok(_) => tcx.dcx().abort_if_errors(),
734 Err(e) => {
735 let mut msg =
736 tcx.dcx().struct_fatal(format!("couldn't generate documentation: {}", e.error));
737 let file = e.file.display().to_string();
738 if !file.is_empty() {
739 msg.note(format!("failed to create or modify {e}"));
740 } else {
741 msg.note(format!("failed to create or modify file: {e}"));
742 }
743 msg.emit();
744 }
745 }
746}
747
748fn run_merge_finalize(opt: config::RenderOptions) -> Result<(), error::Error> {
752 assert!(
753 opt.should_merge.write_rendered_cci,
754 "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
755 );
756 assert!(
757 !opt.should_merge.read_rendered_cci,
758 "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
759 );
760 let crates = html::render::CrateInfo::read_many(&opt.include_parts_dir)?;
761 let include_sources = !opt.html_no_source;
762 html::render::write_not_crate_specific(
763 &crates,
764 &opt.output,
765 &opt,
766 &opt.themes,
767 opt.extension_css.as_deref(),
768 &opt.resource_suffix,
769 include_sources,
770 )?;
771 Ok(())
772}
773
774fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
775 let at_args = at_args.get(1..).unwrap_or_default();
784
785 let args = rustc_driver::args::arg_expand_all(early_dcx, at_args);
786
787 let mut options = getopts::Options::new();
788 for option in opts() {
789 option.apply(&mut options);
790 }
791 let matches = match options.parse(&args) {
792 Ok(m) => m,
793 Err(err) => {
794 early_dcx.early_fatal(err.to_string());
795 }
796 };
797
798 let (input, options, render_options, loaded_paths) =
801 match config::Options::from_matches(early_dcx, &matches, args) {
802 Some(opts) => opts,
803 None => return,
804 };
805
806 let dcx =
807 core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts);
808 let dcx = dcx.handle();
809
810 let input = match input {
811 config::InputMode::HasFile(input) => input,
812 config::InputMode::NoInputMergeFinalize => {
813 return wrap_return(
814 dcx,
815 rustc_span::create_session_globals_then(options.edition, &[], None, || {
816 run_merge_finalize(render_options)
817 .map_err(|e| format!("could not write merged cross-crate info: {e}"))
818 }),
819 );
820 }
821 };
822
823 let output_format = options.output_format;
824
825 match (
826 options.should_test || output_format == config::OutputFormat::Doctest,
827 config::markdown_input(&input),
828 ) {
829 (true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(&input, options, dcx)),
830 (true, None) => return doctest::run(dcx, input, options),
831 (false, Some(md_input)) => {
832 let md_input = md_input.to_owned();
833 let edition = options.edition;
834 let config = core::create_config(input, options, &render_options);
835
836 return wrap_return(
840 dcx,
841 interface::run_compiler(config, |_compiler| {
842 markdown::render_and_write(&md_input, render_options, edition)
843 }),
844 );
845 }
846 (false, None) => {}
847 }
848
849 let show_coverage = options.show_coverage;
852 let run_check = options.run_check;
853
854 info!("starting to run rustc");
856
857 let crate_version = options.crate_version.clone();
862
863 let scrape_examples_options = options.scrape_examples_options.clone();
864 let bin_crate = options.bin_crate;
865
866 let output_format = options.output_format;
867 let config = core::create_config(input, options, &render_options);
868
869 let registered_lints = config.register_lints.is_some();
870
871 interface::run_compiler(config, |compiler| {
872 let sess = &compiler.sess;
873
874 for external_path in &loaded_paths {
877 let _ = sess.source_map().load_binary_file(external_path);
878 }
879
880 if sess.opts.describe_lints {
881 rustc_driver::describe_lints(sess, registered_lints);
882 return;
883 }
884
885 let krate = rustc_interface::passes::parse(sess);
886 rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
887 if sess.dcx().has_errors().is_some() {
888 sess.dcx().fatal("Compilation failed, aborting rustdoc");
889 }
890
891 let (krate, render_opts, mut cache, expanded_macros) = sess
892 .time("run_global_ctxt", || {
893 core::run_global_ctxt(tcx, show_coverage, render_options, output_format)
894 });
895 info!("finished with rustc");
896
897 if let Some(options) = scrape_examples_options {
898 return scrape_examples::run(krate, render_opts, cache, tcx, options, bin_crate);
899 }
900
901 cache.crate_version = crate_version;
902
903 if show_coverage {
904 return;
907 }
908
909 for owner_id in tcx.hir_crate_items(()).delayed_lint_items() {
910 if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) {
911 for lint in &delayed_lints.lints {
912 rustc_hir_analysis::emit_delayed_lint(lint, tcx);
913 }
914 }
915 }
916
917 if render_opts.dep_info().is_some() {
918 rustc_interface::passes::write_dep_info(tcx);
919 }
920
921 if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
922 dump_feature_usage_metrics(tcx, metrics_dir);
923 }
924
925 if run_check {
926 return;
928 }
929
930 info!("going to format");
931 match output_format {
932 config::OutputFormat::Html => sess.time("render_html", || {
933 run_renderer(
934 krate,
935 render_opts,
936 cache,
937 tcx,
938 |krate, render_opts, cache, tcx| {
939 html::render::Context::init(
940 krate,
941 render_opts,
942 cache,
943 tcx,
944 expanded_macros,
945 )
946 },
947 )
948 }),
949 config::OutputFormat::Json => sess.time("render_json", || {
950 run_renderer(krate, render_opts, cache, tcx, json::JsonRenderer::init)
951 }),
952 config::OutputFormat::Doctest => unreachable!(),
954 }
955 })
956 })
957}
958
959fn dump_feature_usage_metrics(tcxt: TyCtxt<'_>, metrics_dir: &Path) {
960 let hash = tcxt.crate_hash(LOCAL_CRATE);
961 let crate_name = tcxt.crate_name(LOCAL_CRATE);
962 let metrics_file_name = format!("unstable_feature_usage_metrics-{crate_name}-{hash}.json");
963 let metrics_path = metrics_dir.join(metrics_file_name);
964 if let Err(error) = tcxt.features().dump_feature_usage_metrics(metrics_path) {
965 tcxt.dcx().err(format!("cannot emit feature usage metrics: {error}"));
969 }
970}