Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustdoc: refactor how passes are structured, and turn intra-doc-link collection into a pass #52800

Merged
merged 7 commits into from
Aug 5, 2018
564 changes: 13 additions & 551 deletions src/librustdoc/clean/mod.rs

Large diffs are not rendered by default.

83 changes: 74 additions & 9 deletions src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use rustc_metadata::creader::CrateLoader;
use rustc_metadata::cstore::CStore;
use rustc_target::spec::TargetTriple;

use syntax::ast::{self, Ident, Name, NodeId};
use syntax::ast::{self, Ident};
use syntax::codemap;
use syntax::edition::Edition;
use syntax::feature_gate::UnstableFeatures;
Expand All @@ -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;
Expand All @@ -57,7 +58,6 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> {
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub resolver: &'a RefCell<resolve::Resolver<'rcx, 'cstore>>,
/// The stack of module NodeIds up till this point
pub mod_ids: RefCell<Vec<NodeId>>,
pub crate_name: Option<String>,
pub cstore: Rc<CStore>,
pub populated_all_crate_impls: Cell<bool>,
Expand Down Expand Up @@ -87,7 +87,6 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> {
pub all_fake_def_ids: RefCell<FxHashSet<DefId>>,
/// Maps (type_id, trait_id) -> auto trait impl
pub generated_synthetics: RefCell<FxHashSet<(DefId, DefId)>>,
pub current_item_name: RefCell<Option<Name>>,
pub all_traits: Vec<DefId>,
}

Expand Down Expand Up @@ -322,7 +321,10 @@ 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.

Expand Down Expand Up @@ -517,23 +519,86 @@ pub fn run_core(search_paths: SearchPaths,
ty_substs: Default::default(),
lt_substs: Default::default(),
impl_trait_bounds: Default::default(),
mod_ids: Default::default(),
send_trait: send_trait,
fake_def_ids: RefCell::new(FxHashMap()),
all_fake_def_ids: RefCell::new(FxHashSet()),
generated_synthetics: RefCell::new(FxHashSet()),
current_item_name: RefCell::new(None),
all_traits: tcx.all_traits(LOCAL_CRATE).to_vec(),
};
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);
}
}

ctxt.sess().abort_if_errors();

(krate, ctxt.renderinfo.into_inner(), passes)
}), &sess)
})
}
78 changes: 15 additions & 63 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#![feature(entry_and_modify)]
#![feature(ptr_offset_from)]
#![feature(crate_visibility_modifier)]
#![feature(const_fn)]

#![recursion_limit="256"]

Expand Down Expand Up @@ -96,8 +97,6 @@ mod visit_lib;
mod test;
mod theme;

use clean::AttributesExt;

struct Output {
krate: clean::Crate,
renderinfo: html::render::RenderInfo,
Expand Down Expand Up @@ -367,8 +366,8 @@ fn main_args(args: &[String]) -> isize {

if matches.opt_strs("passes") == ["list"] {
println!("Available passes for running rustdoc:");
for &(name, _, description) in passes::PASSES {
println!("{:>20} - {}", name, description);
for pass in passes::PASSES {
println!("{:>20} - {}", pass.name(), pass.description());
}
println!("\nDefault passes for rustdoc:");
for &name in passes::DEFAULT_PASSES {
Expand Down Expand Up @@ -630,16 +629,16 @@ 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
} else {
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();
Expand Down Expand Up @@ -673,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");

Expand All @@ -687,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");
}
Expand All @@ -751,8 +698,13 @@ where R: 'static + Send,

for pass in &passes {
// determine if we know about this pass
let pass = match passes::PASSES.iter().find(|(p, ..)| p == pass) {
Some(pass) => pass.1,
let pass = match passes::find_pass(pass) {
Some(pass) => if let Some(pass) = pass.late_fn() {
pass
} else {
// not a late pass, but still valid so don't report the error
continue
}
None => {
error!("unknown pass {}, skipping", *pass);

Expand Down
5 changes: 5 additions & 0 deletions src/librustdoc/passes/collapse_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@
use clean::{self, DocFragment, Item};
use fold;
use fold::DocFolder;
use passes::Pass;
use std::mem::replace;

pub const COLLAPSE_DOCS: Pass =
Pass::late("collapse-docs", collapse_docs,
"concatenates all document attributes into one document attribute");

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum DocFragmentKind {
Sugared,
Expand Down
Loading