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