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)]
19#![warn(rustc::symbol_intern_string_literal)]
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_ast::ast;
76use rustc_errors::DiagCtxtHandle;
77use rustc_hir::def_id::LOCAL_CRATE;
78use rustc_interface::interface;
79use rustc_middle::ty::TyCtxt;
80use rustc_session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option};
81use rustc_session::{EarlyDiagCtxt, getopts};
82use rustc_span::{BytePos, Span, SyntaxContext};
83use tracing::info;
84
85use crate::clean::utils::DOC_RUST_LANG_ORG_VERSION;
86use crate::config::EmitType;
87use crate::error::Error;
88use crate::formats::cache::Cache;
89
90macro_rules! map {
101 ($( $key: expr => $val: expr ),* $(,)*) => {{
102 let mut map = ::rustc_data_structures::fx::FxIndexMap::default();
103 $( map.insert($key, $val); )*
104 map
105 }}
106}
107
108mod clean;
109mod config;
110mod core;
111mod display;
112mod docfs;
113mod doctest;
114mod error;
115mod externalfiles;
116mod fold;
117mod formats;
118pub mod html;
120mod json;
121pub(crate) mod lint;
122mod markdown;
123mod passes;
124mod scrape_examples;
125mod theme;
126mod visit;
127mod visit_ast;
128mod visit_lib;
129
130pub fn main() -> ExitCode {
131 let mut early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
132
133 rustc_driver::install_ice_hook(
134 "https://github.com/rust-lang/rust/issues/new\
135 ?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md",
136 |_| (),
137 );
138
139 crate::init_logging(&early_dcx);
147 match rustc_log::init_logger(rustc_log::LoggerConfig::from_env("RUSTDOC_LOG")) {
148 Ok(()) => {}
149 Err(rustc_log::Error::AlreadyInit(_)) => {}
165 Err(error) => early_dcx.early_fatal(error.to_string()),
166 }
167
168 rustc_driver::catch_with_exit_code(|| {
169 let at_args = rustc_driver::args::raw_args(&early_dcx);
170 main_args(&mut early_dcx, &at_args);
171 })
172}
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(
463 Stable,
464 Multi,
465 "",
466 "remap-path-prefix",
467 "Remap source names in compiler messages",
468 "FROM=TO",
469 ),
470 opt(Unstable, Opt, "", "index-page", "Markdown file to be used as index page", "PATH"),
471 opt(
472 Unstable,
473 FlagMulti,
474 "",
475 "enable-index-page",
476 "To enable generation of the index page",
477 "",
478 ),
479 opt(
480 Unstable,
481 Opt,
482 "",
483 "static-root-path",
484 "Path string to force loading static files from in output pages. \
485 If not set, uses combinations of '../' to reach the documentation root.",
486 "PATH",
487 ),
488 opt(
489 Unstable,
490 Opt,
491 "",
492 "persist-doctests",
493 "Directory to persist doctest executables into",
494 "PATH",
495 ),
496 opt(
497 Unstable,
498 FlagMulti,
499 "",
500 "show-coverage",
501 "calculate percentage of public items with documentation",
502 "",
503 ),
504 opt(
505 Stable,
506 Opt,
507 "",
508 "test-runtool",
509 "",
510 "The tool to run tests with when building for a different target than host",
511 ),
512 opt(
513 Stable,
514 Multi,
515 "",
516 "test-runtool-arg",
517 "",
518 "One argument (of possibly many) to pass to the runtool",
519 ),
520 opt(
521 Unstable,
522 Opt,
523 "",
524 "test-builder",
525 "The rustc-like binary to use as the test builder",
526 "PATH",
527 ),
528 opt(
529 Unstable,
530 Multi,
531 "",
532 "test-builder-wrapper",
533 "Wrapper program to pass test-builder and arguments",
534 "PATH",
535 ),
536 opt(Unstable, FlagMulti, "", "check", "Run rustdoc checks", ""),
537 opt(
538 Unstable,
539 FlagMulti,
540 "",
541 "generate-redirect-map",
542 "Generate JSON file at the top level instead of generating HTML redirection files",
543 "",
544 ),
545 opt(
546 Stable,
547 Multi,
548 "",
549 "emit",
550 "Comma separated list of types of output for rustdoc to emit",
551 "[html-static-files,html-non-static-files,dep-info]",
552 ),
553 opt(Unstable, FlagMulti, "", "no-run", "Compile doctests without running them", ""),
554 opt(
555 Unstable,
556 Opt,
557 "",
558 "merge-doctests",
559 "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.",
560 "yes|no|auto",
561 ),
562 opt(
563 Unstable,
564 Opt,
565 "",
566 "remap-path-scope",
567 "Defines which scopes of paths should be remapped by `--remap-path-prefix`",
568 "[macro,diagnostics,debuginfo,coverage,object,all]",
569 ),
570 opt(
571 Unstable,
572 FlagMulti,
573 "",
574 "show-type-layout",
575 "Include the memory layout of types in the docs",
576 "",
577 ),
578 opt(Unstable, Flag, "", "no-capture", "Don't capture stdout and stderr of tests", ""),
579 opt(
580 Unstable,
581 Flag,
582 "",
583 "generate-link-to-definition",
584 "Make the identifiers in the HTML source code pages navigable",
585 "",
586 ),
587 opt(
588 Unstable,
589 Opt,
590 "",
591 "scrape-examples-output-path",
592 "",
593 "collect function call information and output at the given path",
594 ),
595 opt(
596 Unstable,
597 Multi,
598 "",
599 "scrape-examples-target-crate",
600 "",
601 "collect function call information for functions from the target crate",
602 ),
603 opt(Unstable, Flag, "", "scrape-tests", "Include test code when scraping examples", ""),
604 opt(
605 Unstable,
606 Multi,
607 "",
608 "with-examples",
609 "",
610 "path to function call information (for displaying examples in the documentation)",
611 ),
612 opt(
613 Unstable,
614 Opt,
615 "",
616 "merge",
617 "Controls how rustdoc handles files from previously documented crates in the doc root\n\
618 none = Do not write cross-crate information to the --out-dir\n\
619 shared = Append current crate's info to files found in the --out-dir\n\
620 finalize = Write current crate's info and --include-parts-dir info to the --out-dir, overwriting conflicting files",
621 "none|shared|finalize",
622 ),
623 opt(
624 Unstable,
625 Opt,
626 "",
627 "parts-out-dir",
628 "Writes trait implementations and other info for the current crate to provided path. Only use with --merge=none",
629 "path/to/doc.parts/<crate-name>",
630 ),
631 opt(
632 Unstable,
633 Multi,
634 "",
635 "include-parts-dir",
636 "Includes trait implementations and other crate info from provided path. Only use with --merge=finalize",
637 "path/to/doc.parts/<crate-name>",
638 ),
639 opt(Unstable, Flag, "", "html-no-source", "Disable HTML source code pages generation", ""),
640 opt(
641 Unstable,
642 Multi,
643 "",
644 "doctest-build-arg",
645 "One argument (of possibly many) to be used when compiling doctests",
646 "ARG",
647 ),
648 opt(
649 Unstable,
650 FlagMulti,
651 "",
652 "disable-minification",
653 "disable the minification of CSS/JS files (perma-unstable, do not use with cached files)",
654 "",
655 ),
656 opt(
657 Unstable,
658 Flag,
659 "",
660 "generate-macro-expansion",
661 "Add possibility to expand macros in the HTML source code pages",
662 "",
663 ),
664 opt(
666 Stable,
667 Multi,
668 "",
669 "plugin-path",
670 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
671 "DIR",
672 ),
673 opt(
674 Stable,
675 Multi,
676 "",
677 "passes",
678 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
679 "PASSES",
680 ),
681 opt(
682 Stable,
683 Multi,
684 "",
685 "plugins",
686 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
687 "PLUGINS",
688 ),
689 opt(
690 Stable,
691 FlagMulti,
692 "",
693 "no-defaults",
694 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
695 "",
696 ),
697 opt(
698 Stable,
699 Opt,
700 "r",
701 "input-format",
702 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
703 "[rust]",
704 ),
705 ]
706}
707
708fn usage(argv0: &str) {
709 let mut options = getopts::Options::new();
710 for option in opts() {
711 option.apply(&mut options);
712 }
713 println!("{}", options.usage(&format!("{argv0} [options] <input>")));
714 println!(" @path Read newline separated options from `path`\n");
715 println!(
716 "More information available at {DOC_RUST_LANG_ORG_VERSION}/rustdoc/what-is-rustdoc.html",
717 );
718}
719
720pub(crate) fn wrap_return(dcx: DiagCtxtHandle<'_>, res: Result<(), String>) {
721 match res {
722 Ok(()) => dcx.abort_if_errors(),
723 Err(err) => dcx.fatal(err),
724 }
725}
726
727fn run_renderer<
728 'tcx,
729 T: formats::FormatRenderer<'tcx>,
730 F: FnOnce(
731 clean::Crate,
732 config::RenderOptions,
733 Cache,
734 TyCtxt<'tcx>,
735 ) -> Result<(T, clean::Crate), Error>,
736>(
737 krate: clean::Crate,
738 renderopts: config::RenderOptions,
739 cache: formats::cache::Cache,
740 tcx: TyCtxt<'tcx>,
741 init: F,
742) {
743 match formats::run_format::<T, F>(krate, renderopts, cache, tcx, init) {
744 Ok(_) => tcx.dcx().abort_if_errors(),
745 Err(e) => {
746 let mut msg =
747 tcx.dcx().struct_fatal(format!("couldn't generate documentation: {}", e.error));
748 let file = e.file.display().to_string();
749 if !file.is_empty() {
750 msg.note(format!("failed to create or modify {e}"));
751 } else {
752 msg.note(format!("failed to create or modify file: {e}"));
753 }
754 msg.emit();
755 }
756 }
757}
758
759fn run_merge_finalize(opt: config::RenderOptions) -> Result<(), error::Error> {
763 assert!(
764 opt.should_merge.write_rendered_cci,
765 "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
766 );
767 assert!(
768 !opt.should_merge.read_rendered_cci,
769 "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
770 );
771 let crates = html::render::CrateInfo::read_many(&opt.include_parts_dir)?;
772 let include_sources = !opt.html_no_source;
773 html::render::write_not_crate_specific(
774 &crates,
775 &opt.output,
776 &opt,
777 &opt.themes,
778 opt.extension_css.as_deref(),
779 &opt.resource_suffix,
780 include_sources,
781 )?;
782 Ok(())
783}
784
785fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
786 let at_args = at_args.get(1..).unwrap_or_default();
795
796 let args = rustc_driver::args::arg_expand_all(early_dcx, at_args);
797
798 let mut options = getopts::Options::new();
799 for option in opts() {
800 option.apply(&mut options);
801 }
802 let matches = match options.parse(&args) {
803 Ok(m) => m,
804 Err(err) => {
805 early_dcx.early_fatal(err.to_string());
806 }
807 };
808
809 let (input, options, render_options, loaded_paths) =
812 match config::Options::from_matches(early_dcx, &matches, args) {
813 Some(opts) => opts,
814 None => return,
815 };
816
817 let dcx =
818 core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts);
819 let dcx = dcx.handle();
820
821 let input = match input {
822 config::InputMode::HasFile(input) => input,
823 config::InputMode::NoInputMergeFinalize => {
824 return wrap_return(
825 dcx,
826 rustc_span::create_session_globals_then(options.edition, &[], None, || {
827 run_merge_finalize(render_options)
828 .map_err(|e| format!("could not write merged cross-crate info: {e}"))
829 }),
830 );
831 }
832 };
833
834 let output_format = options.output_format;
835
836 match (
837 options.should_test || output_format == config::OutputFormat::Doctest,
838 config::markdown_input(&input),
839 ) {
840 (true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(&input, options, dcx)),
841 (true, None) => return doctest::run(dcx, input, options),
842 (false, Some(md_input)) => {
843 let md_input = md_input.to_owned();
844 let edition = options.edition;
845 let config = core::create_config(input, options, &render_options);
846
847 return wrap_return(
851 dcx,
852 interface::run_compiler(config, |compiler| {
853 let file =
856 compiler.sess.source_map().load_file(&md_input).map_err(|e| {
857 format!("{md_input}: {e}", md_input = md_input.display())
858 })?;
859 let inner_span = Span::new(
860 file.start_pos,
861 BytePos(file.start_pos.0 + file.normalized_source_len.0),
862 SyntaxContext::root(),
863 None,
864 );
865 let krate = ast::Crate {
866 attrs: Default::default(),
867 items: Default::default(),
868 spans: ast::ModSpans { inner_span, ..Default::default() },
869 id: ast::DUMMY_NODE_ID,
870 is_placeholder: false,
871 };
872 rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
873 let has_dep_info = render_options.dep_info().is_some();
874 if render_options.emit.contains(&EmitType::HtmlNonStaticFiles) {
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}