Skip to content

Commit d3d6f76

Browse files
introduce "early passes" an convert a few over
1 parent aaec101 commit d3d6f76

File tree

6 files changed

+150
-74
lines changed

6 files changed

+150
-74
lines changed

src/librustdoc/core.rs

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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;
@@ -322,7 +323,9 @@ pub fn run_core(search_paths: SearchPaths,
322323
error_format: ErrorOutputType,
323324
cmd_lints: Vec<(String, lint::Level)>,
324325
lint_cap: Option<lint::Level>,
325-
describe_lints: bool) -> (clean::Crate, RenderInfo)
326+
describe_lints: bool,
327+
mut manual_passes: Vec<String>,
328+
mut default_passes: passes::DefaultPassOption) -> (clean::Crate, RenderInfo, Vec<String>)
326329
{
327330
// Parse, resolve, and typecheck the given crate.
328331

@@ -527,13 +530,76 @@ pub fn run_core(search_paths: SearchPaths,
527530
};
528531
debug!("crate: {:?}", tcx.hir.krate());
529532

530-
let krate = {
533+
let mut krate = {
531534
let mut v = RustdocVisitor::new(&ctxt);
532535
v.visit(tcx.hir.krate());
533536
v.clean(&ctxt)
534537
};
535538

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

src/librustdoc/lib.rs

Lines changed: 6 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,6 @@ mod visit_lib;
9797
mod test;
9898
mod theme;
9999

100-
use clean::AttributesExt;
101-
102100
struct Output {
103101
krate: clean::Crate,
104102
renderinfo: html::render::RenderInfo,
@@ -631,16 +629,16 @@ fn rust_input<R, F>(cratefile: PathBuf,
631629
where R: 'static + Send,
632630
F: 'static + Send + FnOnce(Output) -> R
633631
{
634-
let mut default_passes = if matches.opt_present("no-defaults") {
632+
let default_passes = if matches.opt_present("no-defaults") {
635633
passes::DefaultPassOption::None
636634
} else if matches.opt_present("document-private-items") {
637635
passes::DefaultPassOption::Private
638636
} else {
639637
passes::DefaultPassOption::Default
640638
};
641639

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

645643
// First, parse the crate and extract all relevant information.
646644
let mut paths = SearchPaths::new();
@@ -674,11 +672,11 @@ where R: 'static + Send,
674672
let result = rustc_driver::monitor(move || syntax::with_globals(move || {
675673
use rustc::session::config::Input;
676674

677-
let (mut krate, renderinfo) =
675+
let (mut krate, renderinfo, passes) =
678676
core::run_core(paths, cfgs, externs, Input::File(cratefile), triple, maybe_sysroot,
679677
display_warnings, crate_name.clone(),
680678
force_unstable_if_unmarked, edition, cg, error_format,
681-
lint_opts, lint_cap, describe_lints);
679+
lint_opts, lint_cap, describe_lints, manual_passes, default_passes);
682680

683681
info!("finished with rustc");
684682

@@ -688,58 +686,6 @@ where R: 'static + Send,
688686

689687
krate.version = crate_version;
690688

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

753699
for pass in &passes {
754700
// determine if we know about this pass
755-
let pass = match passes::PASSES.iter().find(|p| p.name() == pass) {
701+
let pass = match passes::find_pass(pass) {
756702
Some(pass) => if let Some(pass) = pass.late_fn() {
757703
pass
758704
} else {

src/librustdoc/passes/mod.rs

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,17 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
//! Contains information about "passes", used to modify crate information during the documentation
12+
//! process.
13+
1114
use rustc::hir::def_id::DefId;
1215
use rustc::middle::privacy::AccessLevels;
1316
use rustc::util::nodemap::DefIdSet;
1417
use std::mem;
18+
use std::fmt;
1519

1620
use clean::{self, GetDefId, Item};
21+
use core::DocContext;
1722
use fold;
1823
use fold::StripItem;
1924

@@ -35,41 +40,87 @@ pub use self::unindent_comments::UNINDENT_COMMENTS;
3540
mod propagate_doc_cfg;
3641
pub use self::propagate_doc_cfg::PROPAGATE_DOC_CFG;
3742

38-
#[derive(Copy, Clone, Debug)]
43+
/// Represents a single pass.
44+
#[derive(Copy, Clone)]
3945
pub enum Pass {
46+
/// An "early pass" is run in the compiler context, and can gather information about types and
47+
/// traits and the like.
48+
EarlyPass {
49+
name: &'static str,
50+
pass: fn(clean::Crate, &DocContext) -> clean::Crate,
51+
description: &'static str,
52+
},
53+
/// A "late pass" is run between crate cleaning and page generation.
4054
LatePass {
4155
name: &'static str,
4256
pass: fn(clean::Crate) -> clean::Crate,
4357
description: &'static str,
58+
},
59+
}
60+
61+
impl fmt::Debug for Pass {
62+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63+
let mut dbg = match *self {
64+
Pass::EarlyPass { .. } => f.debug_struct("EarlyPass"),
65+
Pass::LatePass { .. } => f.debug_struct("LatePass"),
66+
};
67+
68+
dbg.field("name", &self.name())
69+
.field("pass", &"...")
70+
.field("description", &self.description())
71+
.finish()
4472
}
4573
}
4674

4775
impl Pass {
76+
/// Constructs a new early pass.
77+
pub const fn early(name: &'static str,
78+
pass: fn(clean::Crate, &DocContext) -> clean::Crate,
79+
description: &'static str) -> Pass {
80+
Pass::EarlyPass { name, pass, description }
81+
}
82+
83+
/// Constructs a new late pass.
4884
pub const fn late(name: &'static str,
4985
pass: fn(clean::Crate) -> clean::Crate,
5086
description: &'static str) -> Pass {
5187
Pass::LatePass { name, pass, description }
5288
}
5389

90+
/// Returns the name of this pass.
5491
pub fn name(self) -> &'static str {
5592
match self {
56-
Pass::LatePass { name, .. } => name,
93+
Pass::EarlyPass { name, .. } |
94+
Pass::LatePass { name, .. } => name,
5795
}
5896
}
5997

98+
/// Returns the description of this pass.
6099
pub fn description(self) -> &'static str {
61100
match self {
62-
Pass::LatePass { description, .. } => description,
101+
Pass::EarlyPass { description, .. } |
102+
Pass::LatePass { description, .. } => description,
63103
}
64104
}
65105

106+
/// If this pass is an early pass, returns the pointer to its function.
107+
pub fn early_fn(self) -> Option<fn(clean::Crate, &DocContext) -> clean::Crate> {
108+
match self {
109+
Pass::EarlyPass { pass, .. } => Some(pass),
110+
_ => None,
111+
}
112+
}
113+
114+
/// If this pass is a late pass, returns the pointer to its function.
66115
pub fn late_fn(self) -> Option<fn(clean::Crate) -> clean::Crate> {
67116
match self {
68117
Pass::LatePass { pass, .. } => Some(pass),
118+
_ => None,
69119
}
70120
}
71121
}
72122

123+
/// The full list of passes.
73124
pub const PASSES: &'static [Pass] = &[
74125
STRIP_HIDDEN,
75126
UNINDENT_COMMENTS,
@@ -79,6 +130,7 @@ pub const PASSES: &'static [Pass] = &[
79130
PROPAGATE_DOC_CFG,
80131
];
81132

133+
/// The list of passes run by default.
82134
pub const DEFAULT_PASSES: &'static [&'static str] = &[
83135
"strip-hidden",
84136
"strip-private",
@@ -87,20 +139,24 @@ pub const DEFAULT_PASSES: &'static [&'static str] = &[
87139
"propagate-doc-cfg",
88140
];
89141

142+
/// The list of default passes run with `--document-private-items` is passed to rustdoc.
90143
pub const DEFAULT_PRIVATE_PASSES: &'static [&'static str] = &[
91144
"strip-priv-imports",
92145
"collapse-docs",
93146
"unindent-comments",
94147
"propagate-doc-cfg",
95148
];
96149

150+
/// A shorthand way to refer to which set of passes to use, based on the presence of
151+
/// `--no-defaults` or `--document-private-items`.
97152
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
98153
pub enum DefaultPassOption {
99154
Default,
100155
Private,
101156
None,
102157
}
103158

159+
/// Returns the given default set of passes.
104160
pub fn defaults(default_set: DefaultPassOption) -> &'static [&'static str] {
105161
match default_set {
106162
DefaultPassOption::Default => DEFAULT_PASSES,
@@ -109,6 +165,11 @@ pub fn defaults(default_set: DefaultPassOption) -> &'static [&'static str] {
109165
}
110166
}
111167

168+
/// If the given name matches a known pass, returns its information.
169+
pub fn find_pass(pass_name: &str) -> Option<Pass> {
170+
PASSES.iter().find(|p| p.name() == pass_name).cloned()
171+
}
172+
112173
struct Stripper<'a> {
113174
retained: &'a mut DefIdSet,
114175
access_levels: &'a AccessLevels<DefId>,

src/librustdoc/passes/strip_hidden.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,18 @@ use std::mem;
1313

1414
use clean::{self, AttributesExt, NestedAttributesExt};
1515
use clean::Item;
16+
use core::DocContext;
1617
use fold;
1718
use fold::DocFolder;
1819
use fold::StripItem;
1920
use passes::{ImplStripper, Pass};
2021

2122
pub const STRIP_HIDDEN: Pass =
22-
Pass::late("strip-hidden", strip_hidden,
23-
"strips all doc(hidden) items from the output");
23+
Pass::early("strip-hidden", strip_hidden,
24+
"strips all doc(hidden) items from the output");
2425

2526
/// Strip items marked `#[doc(hidden)]`
26-
pub fn strip_hidden(krate: clean::Crate) -> clean::Crate {
27+
pub fn strip_hidden(krate: clean::Crate, _: &DocContext) -> clean::Crate {
2728
let mut retained = DefIdSet();
2829

2930
// strip all #[doc(hidden)] items

0 commit comments

Comments
 (0)