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