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 "write-doc-meta-dir",
617 "Writes trait implementations and other info for the current crate to provided path",
618 "path/to/doc.meta",
619 ),
620 opt(
621 Unstable,
622 Multi,
623 "",
624 "read-doc-meta-dir",
625 "Includes trait implementations and other crate info from provided path",
626 "path/to/doc.meta",
627 ),
628 opt(
629 Unstable,
630 Opt,
631 "",
632 "parts-out-dir",
633 "Deprecated synonym of write-doc-meta-dir",
634 "path/to/doc.meta",
635 ),
636 opt(
637 Unstable,
638 Multi,
639 "",
640 "include-parts-dir",
641 "Deprecated synonym of read-doc-meta-dir",
642 "path/to/doc.meta",
643 ),
644 opt(
645 Unstable,
646 Opt,
647 "",
648 "merge",
649 "Deprecated option to specify read/write-doc-meta-dir mode",
650 "none, shared, finalize",
651 ),
652 opt(Unstable, Flag, "", "html-no-source", "Disable HTML source code pages generation", ""),
653 opt(
654 Unstable,
655 Multi,
656 "",
657 "doctest-build-arg",
658 "One argument (of possibly many) to be used when compiling doctests",
659 "ARG",
660 ),
661 opt(
662 Unstable,
663 FlagMulti,
664 "",
665 "disable-minification",
666 "disable the minification of CSS/JS files (perma-unstable, do not use with cached files)",
667 "",
668 ),
669 opt(
670 Unstable,
671 Flag,
672 "",
673 "generate-macro-expansion",
674 "Add possibility to expand macros in the HTML source code pages",
675 "",
676 ),
677 opt(
679 Stable,
680 Multi,
681 "",
682 "plugin-path",
683 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
684 "DIR",
685 ),
686 opt(
687 Stable,
688 Multi,
689 "",
690 "passes",
691 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
692 "PASSES",
693 ),
694 opt(
695 Stable,
696 Multi,
697 "",
698 "plugins",
699 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
700 "PLUGINS",
701 ),
702 opt(
703 Stable,
704 FlagMulti,
705 "",
706 "no-defaults",
707 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
708 "",
709 ),
710 opt(
711 Stable,
712 Opt,
713 "r",
714 "input-format",
715 "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
716 "[rust]",
717 ),
718 ]
719}
720
721fn usage(argv0: &str) {
722 let mut options = getopts::Options::new();
723 for option in opts() {
724 option.apply(&mut options);
725 }
726 println!("{}", options.usage(&format!("{argv0} [options] <input>")));
727 println!(" @path Read newline separated options from `path`\n");
728 println!(
729 "More information available at {DOC_RUST_LANG_ORG_VERSION}/rustdoc/what-is-rustdoc.html",
730 );
731}
732
733pub(crate) fn wrap_return(dcx: DiagCtxtHandle<'_>, res: Result<(), String>) {
734 match res {
735 Ok(()) => dcx.abort_if_errors(),
736 Err(err) => dcx.fatal(err),
737 }
738}
739
740fn run_renderer<
741 'tcx,
742 T: formats::FormatRenderer<'tcx>,
743 F: FnOnce(
744 clean::Crate,
745 config::RenderOptions,
746 Cache,
747 TyCtxt<'tcx>,
748 ) -> Result<(T, clean::Crate), Error>,
749>(
750 krate: clean::Crate,
751 renderopts: config::RenderOptions,
752 cache: formats::cache::Cache,
753 tcx: TyCtxt<'tcx>,
754 init: F,
755) {
756 match formats::run_format::<T, F>(krate, renderopts, cache, tcx, init) {
757 Ok(_) => tcx.dcx().abort_if_errors(),
758 Err(e) => {
759 let mut msg =
760 tcx.dcx().struct_fatal(format!("couldn't generate documentation: {}", e.error));
761 let file = e.file.display().to_string();
762 if !file.is_empty() {
763 msg.note(format!("failed to create or modify {e}"));
764 } else {
765 msg.note(format!("failed to create or modify file: {e}"));
766 }
767 msg.emit();
768 }
769 }
770}
771
772fn run_merge_finalize(opt: config::RenderOptions) -> Result<(), error::Error> {
776 assert!(
777 opt.should_merge.write_rendered_cci,
778 "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
779 );
780 assert!(
781 !opt.should_merge.read_rendered_cci,
782 "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
783 );
784 let crates = html::render::CrateInfo::read_many(&opt.include_parts_dir)?;
785 let include_sources = !opt.html_no_source;
786 html::render::write_not_crate_specific(
787 &crates,
788 &opt.output,
789 &opt,
790 &opt.themes,
791 opt.extension_css.as_deref(),
792 &opt.resource_suffix,
793 include_sources,
794 )?;
795 Ok(())
796}
797
798fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
799 let at_args = at_args.get(1..).unwrap_or_default();
808
809 let args = rustc_driver::args::arg_expand_all(early_dcx, at_args);
810
811 let mut options = getopts::Options::new();
812 for option in opts() {
813 option.apply(&mut options);
814 }
815 let matches = match options.parse(&args) {
816 Ok(m) => m,
817 Err(err) => {
818 early_dcx.early_fatal(err.to_string());
819 }
820 };
821
822 let (input, options, render_options, loaded_paths) =
825 match config::Options::from_matches(early_dcx, &matches, args) {
826 Some(opts) => opts,
827 None => return,
828 };
829
830 let dcx =
831 core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts);
832 let dcx = dcx.handle();
833
834 let input = match input {
835 config::InputMode::HasFile(input) => input,
836 config::InputMode::NoInputMergeFinalize => {
837 return wrap_return(
838 dcx,
839 rustc_span::create_session_globals_then(options.edition, &[], None, || {
840 run_merge_finalize(render_options)
841 .map_err(|e| format!("could not write merged cross-crate info: {e}"))
842 }),
843 );
844 }
845 };
846
847 let output_format = options.output_format;
848
849 match (
850 options.should_test || output_format == config::OutputFormat::Doctest,
851 config::markdown_input(&input),
852 ) {
853 (true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(&input, options, dcx)),
854 (true, None) => return doctest::run(dcx, input, options),
855 (false, Some(md_input)) => {
856 let md_input = md_input.to_owned();
857 let edition = options.edition;
858 let config = core::create_config(input, options, &render_options);
859
860 return wrap_return(
864 dcx,
865 interface::run_compiler(config, |compiler| {
866 let file =
869 compiler.sess.source_map().load_file(&md_input).map_err(|e| {
870 format!("{md_input}: {e}", md_input = md_input.display())
871 })?;
872 let inner_span = Span::new(
873 file.start_pos,
874 BytePos(file.start_pos.0 + file.normalized_source_len.0),
875 SyntaxContext::root(),
876 None,
877 );
878 let krate = ast::Crate {
879 attrs: Default::default(),
880 items: Default::default(),
881 spans: ast::ModSpans { inner_span, ..Default::default() },
882 id: ast::DUMMY_NODE_ID,
883 is_placeholder: false,
884 };
885 rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
886 let has_dep_info = render_options.dep_info().is_some();
887 if render_options.emit.contains(&EmitType::HtmlNonStaticFiles) {
888 markdown::render_and_write(file, render_options, edition)?;
889 }
890 if has_dep_info {
891 for external_path in &loaded_paths {
894 let _ = compiler.sess.source_map().load_binary_file(external_path);
895 }
896 rustc_interface::passes::write_dep_info(tcx);
897 }
898 Ok(())
899 })
900 }),
901 );
902 }
903 (false, None) => {}
904 }
905
906 let show_coverage = options.show_coverage;
909 let run_check = options.run_check;
910
911 info!("starting to run rustc");
913
914 let crate_version = options.crate_version.clone();
919
920 let scrape_examples_options = options.scrape_examples_options.clone();
921 let bin_crate = options.bin_crate;
922
923 let output_format = options.output_format;
924 let config = core::create_config(input, options, &render_options);
925
926 let registered_lints = config.register_lints.is_some();
927
928 interface::run_compiler(config, |compiler| {
929 let sess = &compiler.sess;
930
931 for external_path in &loaded_paths {
934 let _ = sess.source_map().load_binary_file(external_path);
935 }
936
937 if sess.opts.describe_lints {
938 rustc_driver::describe_lints(sess, registered_lints);
939 return;
940 }
941
942 let krate = rustc_interface::passes::parse(sess);
943 rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
944 if sess.dcx().has_errors().is_some() {
945 sess.dcx().fatal("Compilation failed, aborting rustdoc");
946 }
947
948 let (krate, render_opts, mut cache, expanded_macros) = sess
949 .time("run_global_ctxt", || {
950 core::run_global_ctxt(tcx, show_coverage, render_options, output_format)
951 });
952 info!("finished with rustc");
953
954 if let Some(options) = scrape_examples_options {
955 return scrape_examples::run(krate, render_opts, cache, tcx, options, bin_crate);
956 }
957
958 cache.crate_version = crate_version;
959
960 if show_coverage {
961 return;
964 }
965
966 rustc_interface::passes::emit_delayed_lints(tcx);
967
968 if render_opts.dep_info().is_some() {
969 rustc_interface::passes::write_dep_info(tcx);
970 }
971
972 if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
973 dump_feature_usage_metrics(tcx, metrics_dir);
974 }
975
976 if run_check {
977 return;
979 }
980
981 info!("going to format");
982 match output_format {
983 config::OutputFormat::Html => sess.time("render_html", || {
984 run_renderer(
985 krate,
986 render_opts,
987 cache,
988 tcx,
989 |krate, render_opts, cache, tcx| {
990 html::render::Context::init(
991 krate,
992 render_opts,
993 cache,
994 tcx,
995 expanded_macros,
996 )
997 },
998 )
999 }),
1000 config::OutputFormat::IrJson => sess.time("render_json", || {
1001 run_renderer(krate, render_opts, cache, tcx, json::JsonRenderer::init)
1002 }),
1003 config::OutputFormat::Doctest | config::OutputFormat::CoverageJson => {
1005 unreachable!()
1006 }
1007 }
1008 })
1009 })
1010}
1011
1012fn dump_feature_usage_metrics(tcx: TyCtxt<'_>, metrics_dir: &Path) {
1013 let hash = tcx.crate_hash(LOCAL_CRATE);
1014 let crate_name = tcx.crate_name(LOCAL_CRATE);
1015 let metrics_file_name = format!("unstable_feature_usage_metrics-{crate_name}-{hash}.json");
1016 let metrics_path = metrics_dir.join(metrics_file_name);
1017 if let Err(error) = tcx.features().dump_feature_usage_metrics(metrics_path) {
1018 tcx.dcx().err(format!("cannot emit feature usage metrics: {error}"));
1022 }
1023}