introduce "early passes" an convert a few over
This commit is contained in:
parent
aaec1014d8
commit
d3d6f76887
@ -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)
|
||||
})
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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>,
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user