introduce "early passes" an convert a few over

This commit is contained in:
QuietMisdreavus 2018-07-27 10:22:16 -05:00
parent aaec1014d8
commit d3d6f76887
6 changed files with 150 additions and 74 deletions

View File

@ -45,8 +45,9 @@ use std::path::PathBuf;
use visit_ast::RustdocVisitor;
use clean;
use clean::{get_path_for_type, Clean, MAX_DEF_ID};
use clean::{get_path_for_type, Clean, MAX_DEF_ID, AttributesExt};
use html::render::RenderInfo;
use passes;
pub use rustc::session::config::{Input, Options, CodegenOptions};
pub use rustc::session::search_paths::SearchPaths;
@ -322,7 +323,9 @@ pub fn run_core(search_paths: SearchPaths,
error_format: ErrorOutputType,
cmd_lints: Vec<(String, lint::Level)>,
lint_cap: Option<lint::Level>,
describe_lints: bool) -> (clean::Crate, RenderInfo)
describe_lints: bool,
mut manual_passes: Vec<String>,
mut default_passes: passes::DefaultPassOption) -> (clean::Crate, RenderInfo, Vec<String>)
{
// Parse, resolve, and typecheck the given crate.
@ -527,13 +530,76 @@ pub fn run_core(search_paths: SearchPaths,
};
debug!("crate: {:?}", tcx.hir.krate());
let krate = {
let mut krate = {
let mut v = RustdocVisitor::new(&ctxt);
v.visit(tcx.hir.krate());
v.clean(&ctxt)
};
(krate, ctxt.renderinfo.into_inner())
fn report_deprecated_attr(name: &str, diag: &errors::Handler) {
let mut msg = diag.struct_warn(&format!("the `#![doc({})]` attribute is \
considered deprecated", name));
msg.warn("please see https://github.com/rust-lang/rust/issues/44136");
if name == "no_default_passes" {
msg.help("you may want to use `#![doc(document_private_items)]`");
}
msg.emit();
}
// Process all of the crate attributes, extracting plugin metadata along
// with the passes which we are supposed to run.
for attr in krate.module.as_ref().unwrap().attrs.lists("doc") {
let diag = ctxt.sess().diagnostic();
let name = attr.name().map(|s| s.as_str());
let name = name.as_ref().map(|s| &s[..]);
if attr.is_word() {
if name == Some("no_default_passes") {
report_deprecated_attr("no_default_passes", diag);
if default_passes == passes::DefaultPassOption::Default {
default_passes = passes::DefaultPassOption::None;
}
}
} else if let Some(value) = attr.value_str() {
let sink = match name {
Some("passes") => {
report_deprecated_attr("passes = \"...\"", diag);
&mut manual_passes
},
Some("plugins") => {
report_deprecated_attr("plugins = \"...\"", diag);
eprintln!("WARNING: #![doc(plugins = \"...\")] no longer functions; \
see CVE-2018-1000622");
continue
},
_ => continue,
};
for p in value.as_str().split_whitespace() {
sink.push(p.to_string());
}
}
if attr.is_word() && name == Some("document_private_items") {
if default_passes == passes::DefaultPassOption::Default {
default_passes = passes::DefaultPassOption::Private;
}
}
}
let mut passes: Vec<String> =
passes::defaults(default_passes).iter().map(|p| p.to_string()).collect();
passes.extend(manual_passes);
for pass in &passes {
// the "unknown pass" error will be reported when late passes are run
if let Some(pass) = passes::find_pass(pass).and_then(|p| p.early_fn()) {
krate = pass(krate, &ctxt);
}
}
(krate, ctxt.renderinfo.into_inner(), passes)
}), &sess)
})
}

View File

@ -97,8 +97,6 @@ mod visit_lib;
mod test;
mod theme;
use clean::AttributesExt;
struct Output {
krate: clean::Crate,
renderinfo: html::render::RenderInfo,
@ -631,7 +629,7 @@ fn rust_input<R, F>(cratefile: PathBuf,
where R: 'static + Send,
F: 'static + Send + FnOnce(Output) -> R
{
let mut default_passes = if matches.opt_present("no-defaults") {
let default_passes = if matches.opt_present("no-defaults") {
passes::DefaultPassOption::None
} else if matches.opt_present("document-private-items") {
passes::DefaultPassOption::Private
@ -639,8 +637,8 @@ where R: 'static + Send,
passes::DefaultPassOption::Default
};
let mut manual_passes = matches.opt_strs("passes");
let mut plugins = matches.opt_strs("plugins");
let manual_passes = matches.opt_strs("passes");
let plugins = matches.opt_strs("plugins");
// First, parse the crate and extract all relevant information.
let mut paths = SearchPaths::new();
@ -674,11 +672,11 @@ where R: 'static + Send,
let result = rustc_driver::monitor(move || syntax::with_globals(move || {
use rustc::session::config::Input;
let (mut krate, renderinfo) =
let (mut krate, renderinfo, passes) =
core::run_core(paths, cfgs, externs, Input::File(cratefile), triple, maybe_sysroot,
display_warnings, crate_name.clone(),
force_unstable_if_unmarked, edition, cg, error_format,
lint_opts, lint_cap, describe_lints);
lint_opts, lint_cap, describe_lints, manual_passes, default_passes);
info!("finished with rustc");
@ -688,58 +686,6 @@ where R: 'static + Send,
krate.version = crate_version;
let diag = core::new_handler(error_format, None);
fn report_deprecated_attr(name: &str, diag: &errors::Handler) {
let mut msg = diag.struct_warn(&format!("the `#![doc({})]` attribute is \
considered deprecated", name));
msg.warn("please see https://github.com/rust-lang/rust/issues/44136");
if name == "no_default_passes" {
msg.help("you may want to use `#![doc(document_private_items)]`");
}
msg.emit();
}
// Process all of the crate attributes, extracting plugin metadata along
// with the passes which we are supposed to run.
for attr in krate.module.as_ref().unwrap().attrs.lists("doc") {
let name = attr.name().map(|s| s.as_str());
let name = name.as_ref().map(|s| &s[..]);
if attr.is_word() {
if name == Some("no_default_passes") {
report_deprecated_attr("no_default_passes", &diag);
if default_passes == passes::DefaultPassOption::Default {
default_passes = passes::DefaultPassOption::None;
}
}
} else if let Some(value) = attr.value_str() {
let sink = match name {
Some("passes") => {
report_deprecated_attr("passes = \"...\"", &diag);
&mut manual_passes
},
Some("plugins") => {
report_deprecated_attr("plugins = \"...\"", &diag);
&mut plugins
},
_ => continue,
};
sink.extend(value.as_str().split_whitespace().map(|p| p.to_string()));
}
if attr.is_word() && name == Some("document_private_items") {
if default_passes == passes::DefaultPassOption::Default {
default_passes = passes::DefaultPassOption::Private;
}
}
}
let mut passes: Vec<String> =
passes::defaults(default_passes).iter().map(|p| p.to_string()).collect();
passes.extend(manual_passes);
if !plugins.is_empty() {
eprintln!("WARNING: --plugins no longer functions; see CVE-2018-1000622");
}
@ -752,7 +698,7 @@ where R: 'static + Send,
for pass in &passes {
// determine if we know about this pass
let pass = match passes::PASSES.iter().find(|p| p.name() == pass) {
let pass = match passes::find_pass(pass) {
Some(pass) => if let Some(pass) = pass.late_fn() {
pass
} else {

View File

@ -8,12 +8,17 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Contains information about "passes", used to modify crate information during the documentation
//! process.
use rustc::hir::def_id::DefId;
use rustc::middle::privacy::AccessLevels;
use rustc::util::nodemap::DefIdSet;
use std::mem;
use std::fmt;
use clean::{self, GetDefId, Item};
use core::DocContext;
use fold;
use fold::StripItem;
@ -35,41 +40,87 @@ pub use self::unindent_comments::UNINDENT_COMMENTS;
mod propagate_doc_cfg;
pub use self::propagate_doc_cfg::PROPAGATE_DOC_CFG;
#[derive(Copy, Clone, Debug)]
/// Represents a single pass.
#[derive(Copy, Clone)]
pub enum Pass {
/// An "early pass" is run in the compiler context, and can gather information about types and
/// traits and the like.
EarlyPass {
name: &'static str,
pass: fn(clean::Crate, &DocContext) -> clean::Crate,
description: &'static str,
},
/// A "late pass" is run between crate cleaning and page generation.
LatePass {
name: &'static str,
pass: fn(clean::Crate) -> clean::Crate,
description: &'static str,
},
}
impl fmt::Debug for Pass {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut dbg = match *self {
Pass::EarlyPass { .. } => f.debug_struct("EarlyPass"),
Pass::LatePass { .. } => f.debug_struct("LatePass"),
};
dbg.field("name", &self.name())
.field("pass", &"...")
.field("description", &self.description())
.finish()
}
}
impl Pass {
/// Constructs a new early pass.
pub const fn early(name: &'static str,
pass: fn(clean::Crate, &DocContext) -> clean::Crate,
description: &'static str) -> Pass {
Pass::EarlyPass { name, pass, description }
}
/// Constructs a new late pass.
pub const fn late(name: &'static str,
pass: fn(clean::Crate) -> clean::Crate,
description: &'static str) -> Pass {
Pass::LatePass { name, pass, description }
}
/// Returns the name of this pass.
pub fn name(self) -> &'static str {
match self {
Pass::EarlyPass { name, .. } |
Pass::LatePass { name, .. } => name,
}
}
/// Returns the description of this pass.
pub fn description(self) -> &'static str {
match self {
Pass::EarlyPass { description, .. } |
Pass::LatePass { description, .. } => description,
}
}
/// If this pass is an early pass, returns the pointer to its function.
pub fn early_fn(self) -> Option<fn(clean::Crate, &DocContext) -> clean::Crate> {
match self {
Pass::EarlyPass { pass, .. } => Some(pass),
_ => None,
}
}
/// If this pass is a late pass, returns the pointer to its function.
pub fn late_fn(self) -> Option<fn(clean::Crate) -> clean::Crate> {
match self {
Pass::LatePass { pass, .. } => Some(pass),
_ => None,
}
}
}
/// The full list of passes.
pub const PASSES: &'static [Pass] = &[
STRIP_HIDDEN,
UNINDENT_COMMENTS,
@ -79,6 +130,7 @@ pub const PASSES: &'static [Pass] = &[
PROPAGATE_DOC_CFG,
];
/// The list of passes run by default.
pub const DEFAULT_PASSES: &'static [&'static str] = &[
"strip-hidden",
"strip-private",
@ -87,6 +139,7 @@ pub const DEFAULT_PASSES: &'static [&'static str] = &[
"propagate-doc-cfg",
];
/// The list of default passes run with `--document-private-items` is passed to rustdoc.
pub const DEFAULT_PRIVATE_PASSES: &'static [&'static str] = &[
"strip-priv-imports",
"collapse-docs",
@ -94,6 +147,8 @@ pub const DEFAULT_PRIVATE_PASSES: &'static [&'static str] = &[
"propagate-doc-cfg",
];
/// A shorthand way to refer to which set of passes to use, based on the presence of
/// `--no-defaults` or `--document-private-items`.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum DefaultPassOption {
Default,
@ -101,6 +156,7 @@ pub enum DefaultPassOption {
None,
}
/// Returns the given default set of passes.
pub fn defaults(default_set: DefaultPassOption) -> &'static [&'static str] {
match default_set {
DefaultPassOption::Default => DEFAULT_PASSES,
@ -109,6 +165,11 @@ pub fn defaults(default_set: DefaultPassOption) -> &'static [&'static str] {
}
}
/// If the given name matches a known pass, returns its information.
pub fn find_pass(pass_name: &str) -> Option<Pass> {
PASSES.iter().find(|p| p.name() == pass_name).cloned()
}
struct Stripper<'a> {
retained: &'a mut DefIdSet,
access_levels: &'a AccessLevels<DefId>,

View File

@ -13,17 +13,18 @@ use std::mem;
use clean::{self, AttributesExt, NestedAttributesExt};
use clean::Item;
use core::DocContext;
use fold;
use fold::DocFolder;
use fold::StripItem;
use passes::{ImplStripper, Pass};
pub const STRIP_HIDDEN: Pass =
Pass::late("strip-hidden", strip_hidden,
Pass::early("strip-hidden", strip_hidden,
"strips all doc(hidden) items from the output");
/// Strip items marked `#[doc(hidden)]`
pub fn strip_hidden(krate: clean::Crate) -> clean::Crate {
pub fn strip_hidden(krate: clean::Crate, _: &DocContext) -> clean::Crate {
let mut retained = DefIdSet();
// strip all #[doc(hidden)] items

View File

@ -9,12 +9,13 @@
// except according to those terms.
use clean;
use core::DocContext;
use fold::DocFolder;
use passes::{ImportStripper, Pass};
pub const STRIP_PRIV_IMPORTS: Pass = Pass::late("strip-priv-imports", strip_priv_imports,
pub const STRIP_PRIV_IMPORTS: Pass = Pass::early("strip-priv-imports", strip_priv_imports,
"strips all private import statements (`use`, `extern crate`) from a crate");
pub fn strip_priv_imports(krate: clean::Crate) -> clean::Crate {
pub fn strip_priv_imports(krate: clean::Crate, _: &DocContext) -> clean::Crate {
ImportStripper.fold_crate(krate)
}

View File

@ -11,17 +11,18 @@
use rustc::util::nodemap::DefIdSet;
use clean;
use core::DocContext;
use fold::DocFolder;
use passes::{ImplStripper, ImportStripper, Stripper, Pass};
pub const STRIP_PRIVATE: Pass =
Pass::late("strip-private", strip_private,
Pass::early("strip-private", strip_private,
"strips all private items from a crate which cannot be seen externally, \
implies strip-priv-imports");
/// Strip private items from the point of view of a crate or externally from a
/// crate, specified by the `xcrate` flag.
pub fn strip_private(mut krate: clean::Crate) -> clean::Crate {
pub fn strip_private(mut krate: clean::Crate, _: &DocContext) -> clean::Crate {
// This stripper collects all *retained* nodes.
let mut retained = DefIdSet();
let access_levels = krate.access_levels.clone();