Skip to content

Commit 73c7873

Browse files
committed
Auto merge of #52800 - QuietMisdreavus:do-not-pass-go, r=GuillaumeGomez
rustdoc: refactor how passes are structured, and turn intra-doc-link collection into a pass This builds on #52751 and should not be merged until that finally finishes the bors queue Part 2 of my passes refactor. This introduces the concept of an "early pass", which is run right before exiting the compiler context. This is important for passes that may want to ask the compiler about things. For example, i took out the intra-doc-link collection and turned it into a early pass. I also made the `strip-hidden`, `strip-private` and `strip-priv-imports` passes occur as early passes, so that intra-doc-link collection wouldn't run on docs that weren't getting printed. Fixes #51684, technically #51468 too but that version of `h2` hits a legit intra-link error after that `>_>` r? @rust-lang/rustdoc
2 parents 93a4cab + e332985 commit 73c7873

15 files changed

+899
-672
lines changed

Diff for: src/librustdoc/clean/mod.rs

+13-551
Large diffs are not rendered by default.

Diff for: src/librustdoc/core.rs

+74-9
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use rustc_metadata::creader::CrateLoader;
2626
use rustc_metadata::cstore::CStore;
2727
use rustc_target::spec::TargetTriple;
2828

29-
use syntax::ast::{self, Ident, Name, NodeId};
29+
use syntax::ast::{self, Ident};
3030
use syntax::codemap;
3131
use syntax::edition::Edition;
3232
use syntax::feature_gate::UnstableFeatures;
@@ -45,8 +45,9 @@ use std::path::PathBuf;
4545

4646
use visit_ast::RustdocVisitor;
4747
use clean;
48-
use clean::{get_path_for_type, Clean, MAX_DEF_ID};
48+
use clean::{get_path_for_type, Clean, MAX_DEF_ID, AttributesExt};
4949
use html::render::RenderInfo;
50+
use passes;
5051

5152
pub use rustc::session::config::{Input, Options, CodegenOptions};
5253
pub use rustc::session::search_paths::SearchPaths;
@@ -57,7 +58,6 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> {
5758
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
5859
pub resolver: &'a RefCell<resolve::Resolver<'rcx, 'cstore>>,
5960
/// The stack of module NodeIds up till this point
60-
pub mod_ids: RefCell<Vec<NodeId>>,
6161
pub crate_name: Option<String>,
6262
pub cstore: Rc<CStore>,
6363
pub populated_all_crate_impls: Cell<bool>,
@@ -87,7 +87,6 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> {
8787
pub all_fake_def_ids: RefCell<FxHashSet<DefId>>,
8888
/// Maps (type_id, trait_id) -> auto trait impl
8989
pub generated_synthetics: RefCell<FxHashSet<(DefId, DefId)>>,
90-
pub current_item_name: RefCell<Option<Name>>,
9190
pub all_traits: Vec<DefId>,
9291
}
9392

@@ -322,7 +321,10 @@ pub fn run_core(search_paths: SearchPaths,
322321
error_format: ErrorOutputType,
323322
cmd_lints: Vec<(String, lint::Level)>,
324323
lint_cap: Option<lint::Level>,
325-
describe_lints: bool) -> (clean::Crate, RenderInfo)
324+
describe_lints: bool,
325+
mut manual_passes: Vec<String>,
326+
mut default_passes: passes::DefaultPassOption)
327+
-> (clean::Crate, RenderInfo, Vec<String>)
326328
{
327329
// Parse, resolve, and typecheck the given crate.
328330

@@ -517,23 +519,86 @@ pub fn run_core(search_paths: SearchPaths,
517519
ty_substs: Default::default(),
518520
lt_substs: Default::default(),
519521
impl_trait_bounds: Default::default(),
520-
mod_ids: Default::default(),
521522
send_trait: send_trait,
522523
fake_def_ids: RefCell::new(FxHashMap()),
523524
all_fake_def_ids: RefCell::new(FxHashSet()),
524525
generated_synthetics: RefCell::new(FxHashSet()),
525-
current_item_name: RefCell::new(None),
526526
all_traits: tcx.all_traits(LOCAL_CRATE).to_vec(),
527527
};
528528
debug!("crate: {:?}", tcx.hir.krate());
529529

530-
let krate = {
530+
let mut krate = {
531531
let mut v = RustdocVisitor::new(&ctxt);
532532
v.visit(tcx.hir.krate());
533533
v.clean(&ctxt)
534534
};
535535

536-
(krate, ctxt.renderinfo.into_inner())
536+
fn report_deprecated_attr(name: &str, diag: &errors::Handler) {
537+
let mut msg = diag.struct_warn(&format!("the `#![doc({})]` attribute is \
538+
considered deprecated", name));
539+
msg.warn("please see https://github.com/rust-lang/rust/issues/44136");
540+
541+
if name == "no_default_passes" {
542+
msg.help("you may want to use `#![doc(document_private_items)]`");
543+
}
544+
545+
msg.emit();
546+
}
547+
548+
// Process all of the crate attributes, extracting plugin metadata along
549+
// with the passes which we are supposed to run.
550+
for attr in krate.module.as_ref().unwrap().attrs.lists("doc") {
551+
let diag = ctxt.sess().diagnostic();
552+
553+
let name = attr.name().map(|s| s.as_str());
554+
let name = name.as_ref().map(|s| &s[..]);
555+
if attr.is_word() {
556+
if name == Some("no_default_passes") {
557+
report_deprecated_attr("no_default_passes", diag);
558+
if default_passes == passes::DefaultPassOption::Default {
559+
default_passes = passes::DefaultPassOption::None;
560+
}
561+
}
562+
} else if let Some(value) = attr.value_str() {
563+
let sink = match name {
564+
Some("passes") => {
565+
report_deprecated_attr("passes = \"...\"", diag);
566+
&mut manual_passes
567+
},
568+
Some("plugins") => {
569+
report_deprecated_attr("plugins = \"...\"", diag);
570+
eprintln!("WARNING: #![doc(plugins = \"...\")] no longer functions; \
571+
see CVE-2018-1000622");
572+
continue
573+
},
574+
_ => continue,
575+
};
576+
for p in value.as_str().split_whitespace() {
577+
sink.push(p.to_string());
578+
}
579+
}
580+
581+
if attr.is_word() && name == Some("document_private_items") {
582+
if default_passes == passes::DefaultPassOption::Default {
583+
default_passes = passes::DefaultPassOption::Private;
584+
}
585+
}
586+
}
587+
588+
let mut passes: Vec<String> =
589+
passes::defaults(default_passes).iter().map(|p| p.to_string()).collect();
590+
passes.extend(manual_passes);
591+
592+
for pass in &passes {
593+
// the "unknown pass" error will be reported when late passes are run
594+
if let Some(pass) = passes::find_pass(pass).and_then(|p| p.early_fn()) {
595+
krate = pass(krate, &ctxt);
596+
}
597+
}
598+
599+
ctxt.sess().abort_if_errors();
600+
601+
(krate, ctxt.renderinfo.into_inner(), passes)
537602
}), &sess)
538603
})
539604
}

Diff for: src/librustdoc/lib.rs

+15-63
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#![feature(entry_and_modify)]
2727
#![feature(ptr_offset_from)]
2828
#![feature(crate_visibility_modifier)]
29+
#![feature(const_fn)]
2930

3031
#![recursion_limit="256"]
3132

@@ -96,8 +97,6 @@ mod visit_lib;
9697
mod test;
9798
mod theme;
9899

99-
use clean::AttributesExt;
100-
101100
struct Output {
102101
krate: clean::Crate,
103102
renderinfo: html::render::RenderInfo,
@@ -367,8 +366,8 @@ fn main_args(args: &[String]) -> isize {
367366

368367
if matches.opt_strs("passes") == ["list"] {
369368
println!("Available passes for running rustdoc:");
370-
for &(name, _, description) in passes::PASSES {
371-
println!("{:>20} - {}", name, description);
369+
for pass in passes::PASSES {
370+
println!("{:>20} - {}", pass.name(), pass.description());
372371
}
373372
println!("\nDefault passes for rustdoc:");
374373
for &name in passes::DEFAULT_PASSES {
@@ -630,16 +629,16 @@ fn rust_input<R, F>(cratefile: PathBuf,
630629
where R: 'static + Send,
631630
F: 'static + Send + FnOnce(Output) -> R
632631
{
633-
let mut default_passes = if matches.opt_present("no-defaults") {
632+
let default_passes = if matches.opt_present("no-defaults") {
634633
passes::DefaultPassOption::None
635634
} else if matches.opt_present("document-private-items") {
636635
passes::DefaultPassOption::Private
637636
} else {
638637
passes::DefaultPassOption::Default
639638
};
640639

641-
let mut manual_passes = matches.opt_strs("passes");
642-
let mut plugins = matches.opt_strs("plugins");
640+
let manual_passes = matches.opt_strs("passes");
641+
let plugins = matches.opt_strs("plugins");
643642

644643
// First, parse the crate and extract all relevant information.
645644
let mut paths = SearchPaths::new();
@@ -673,11 +672,11 @@ where R: 'static + Send,
673672
let result = rustc_driver::monitor(move || syntax::with_globals(move || {
674673
use rustc::session::config::Input;
675674

676-
let (mut krate, renderinfo) =
675+
let (mut krate, renderinfo, passes) =
677676
core::run_core(paths, cfgs, externs, Input::File(cratefile), triple, maybe_sysroot,
678677
display_warnings, crate_name.clone(),
679678
force_unstable_if_unmarked, edition, cg, error_format,
680-
lint_opts, lint_cap, describe_lints);
679+
lint_opts, lint_cap, describe_lints, manual_passes, default_passes);
681680

682681
info!("finished with rustc");
683682

@@ -687,58 +686,6 @@ where R: 'static + Send,
687686

688687
krate.version = crate_version;
689688

690-
let diag = core::new_handler(error_format, None);
691-
692-
fn report_deprecated_attr(name: &str, diag: &errors::Handler) {
693-
let mut msg = diag.struct_warn(&format!("the `#![doc({})]` attribute is \
694-
considered deprecated", name));
695-
msg.warn("please see https://github.com/rust-lang/rust/issues/44136");
696-
697-
if name == "no_default_passes" {
698-
msg.help("you may want to use `#![doc(document_private_items)]`");
699-
}
700-
701-
msg.emit();
702-
}
703-
704-
// Process all of the crate attributes, extracting plugin metadata along
705-
// with the passes which we are supposed to run.
706-
for attr in krate.module.as_ref().unwrap().attrs.lists("doc") {
707-
let name = attr.name().map(|s| s.as_str());
708-
let name = name.as_ref().map(|s| &s[..]);
709-
if attr.is_word() {
710-
if name == Some("no_default_passes") {
711-
report_deprecated_attr("no_default_passes", &diag);
712-
if default_passes == passes::DefaultPassOption::Default {
713-
default_passes = passes::DefaultPassOption::None;
714-
}
715-
}
716-
} else if let Some(value) = attr.value_str() {
717-
let sink = match name {
718-
Some("passes") => {
719-
report_deprecated_attr("passes = \"...\"", &diag);
720-
&mut manual_passes
721-
},
722-
Some("plugins") => {
723-
report_deprecated_attr("plugins = \"...\"", &diag);
724-
&mut plugins
725-
},
726-
_ => continue,
727-
};
728-
sink.extend(value.as_str().split_whitespace().map(|p| p.to_string()));
729-
}
730-
731-
if attr.is_word() && name == Some("document_private_items") {
732-
if default_passes == passes::DefaultPassOption::Default {
733-
default_passes = passes::DefaultPassOption::Private;
734-
}
735-
}
736-
}
737-
738-
let mut passes: Vec<String> =
739-
passes::defaults(default_passes).iter().map(|p| p.to_string()).collect();
740-
passes.extend(manual_passes);
741-
742689
if !plugins.is_empty() {
743690
eprintln!("WARNING: --plugins no longer functions; see CVE-2018-1000622");
744691
}
@@ -751,8 +698,13 @@ where R: 'static + Send,
751698

752699
for pass in &passes {
753700
// determine if we know about this pass
754-
let pass = match passes::PASSES.iter().find(|(p, ..)| p == pass) {
755-
Some(pass) => pass.1,
701+
let pass = match passes::find_pass(pass) {
702+
Some(pass) => if let Some(pass) = pass.late_fn() {
703+
pass
704+
} else {
705+
// not a late pass, but still valid so don't report the error
706+
continue
707+
}
756708
None => {
757709
error!("unknown pass {}, skipping", *pass);
758710

Diff for: src/librustdoc/passes/collapse_docs.rs

+5
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@
1111
use clean::{self, DocFragment, Item};
1212
use fold;
1313
use fold::DocFolder;
14+
use passes::Pass;
1415
use std::mem::replace;
1516

17+
pub const COLLAPSE_DOCS: Pass =
18+
Pass::late("collapse-docs", collapse_docs,
19+
"concatenates all document attributes into one document attribute");
20+
1621
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1722
enum DocFragmentKind {
1823
Sugared,

0 commit comments

Comments
 (0)