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