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