rustdoc: Use privacy visibility for pruning
This commit ends rustdoc's approximation of privacy and instead uses the result of the various compiler passes instead. Closes #9827
This commit is contained in:
parent
a7e8957c59
commit
3d693d74b8
@ -199,6 +199,7 @@ pub fn phase_2_configure_and_expand(sess: Session,
|
||||
|
||||
pub struct CrateAnalysis {
|
||||
exp_map2: middle::resolve::ExportMap2,
|
||||
exported_items: middle::privacy::ExportedItems,
|
||||
ty_cx: ty::ctxt,
|
||||
maps: astencode::Maps,
|
||||
reachable: @mut HashSet<ast::NodeId>
|
||||
@ -310,6 +311,7 @@ pub fn phase_3_run_analysis_passes(sess: Session,
|
||||
CrateAnalysis {
|
||||
exp_map2: exp_map2,
|
||||
ty_cx: ty_cx,
|
||||
exported_items: exported_items,
|
||||
maps: astencode::Maps {
|
||||
root_map: root_map,
|
||||
method_map: method_map,
|
||||
|
@ -10,14 +10,17 @@
|
||||
|
||||
use rustc;
|
||||
use rustc::{driver, middle};
|
||||
use rustc::middle::privacy;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::ast_util::is_local;
|
||||
use syntax::diagnostic;
|
||||
use syntax::parse;
|
||||
use syntax;
|
||||
|
||||
use std::os;
|
||||
use std::local_data;
|
||||
use std::hashmap::HashMap;
|
||||
|
||||
use visit_ast::RustdocVisitor;
|
||||
use clean;
|
||||
@ -29,10 +32,19 @@ pub struct DocContext {
|
||||
sess: driver::session::Session
|
||||
}
|
||||
|
||||
pub struct CrateAnalysis {
|
||||
exported_items: privacy::ExportedItems,
|
||||
reexports: HashMap<ast::NodeId, ~[ast::NodeId]>,
|
||||
}
|
||||
|
||||
/// Parses, resolves, and typechecks the given crate
|
||||
fn get_ast_and_resolve(cpath: &Path, libs: ~[Path]) -> DocContext {
|
||||
fn get_ast_and_resolve(cpath: &Path,
|
||||
libs: ~[Path]) -> (DocContext, CrateAnalysis) {
|
||||
use syntax::codemap::dummy_spanned;
|
||||
use rustc::driver::driver::*;
|
||||
use rustc::driver::driver::{file_input, build_configuration,
|
||||
phase_1_parse_input,
|
||||
phase_2_configure_and_expand,
|
||||
phase_3_run_analysis_passes};
|
||||
|
||||
let parsesess = parse::new_parse_sess(None);
|
||||
let input = file_input(cpath.clone());
|
||||
@ -60,14 +72,26 @@ fn get_ast_and_resolve(cpath: &Path, libs: ~[Path]) -> DocContext {
|
||||
|
||||
let mut crate = phase_1_parse_input(sess, cfg.clone(), &input);
|
||||
crate = phase_2_configure_and_expand(sess, cfg, crate);
|
||||
let analysis = phase_3_run_analysis_passes(sess, &crate);
|
||||
let driver::driver::CrateAnalysis {
|
||||
exported_items, ty_cx, exp_map2, _
|
||||
} = phase_3_run_analysis_passes(sess, &crate);
|
||||
|
||||
debug2!("crate: {:?}", crate);
|
||||
DocContext { crate: crate, tycx: analysis.ty_cx, sess: sess }
|
||||
let mut reexports = HashMap::new();
|
||||
for (&module, nodes) in exp_map2.iter() {
|
||||
reexports.insert(module, nodes.iter()
|
||||
.filter(|e| e.reexport && is_local(e.def_id))
|
||||
.map(|e| e.def_id.node)
|
||||
.to_owned_vec());
|
||||
}
|
||||
|
||||
pub fn run_core (libs: ~[Path], path: &Path) -> clean::Crate {
|
||||
let ctxt = @get_ast_and_resolve(path, libs);
|
||||
debug2!("crate: {:?}", crate);
|
||||
return (DocContext { crate: crate, tycx: ty_cx, sess: sess },
|
||||
CrateAnalysis { reexports: reexports, exported_items: exported_items });
|
||||
}
|
||||
|
||||
pub fn run_core (libs: ~[Path], path: &Path) -> (clean::Crate, CrateAnalysis) {
|
||||
let (ctxt, analysis) = get_ast_and_resolve(path, libs);
|
||||
let ctxt = @ctxt;
|
||||
debug2!("defmap:");
|
||||
for (k, v) in ctxt.tycx.def_map.iter() {
|
||||
debug2!("{:?}: {:?}", k, v);
|
||||
@ -77,5 +101,5 @@ pub fn run_core (libs: ~[Path], path: &Path) -> clean::Crate {
|
||||
let v = @mut RustdocVisitor::new();
|
||||
v.visit(&ctxt.crate);
|
||||
|
||||
v.clean()
|
||||
(v.clean(), analysis)
|
||||
}
|
||||
|
@ -582,7 +582,7 @@ impl DocFolder for Cache {
|
||||
clean::StructItem(*) | clean::EnumItem(*) |
|
||||
clean::TypedefItem(*) | clean::TraitItem(*) |
|
||||
clean::FunctionItem(*) | clean::ModuleItem(*) |
|
||||
clean::VariantItem(*) => {
|
||||
clean::ForeignFunctionItem(*) | clean::VariantItem(*) => {
|
||||
self.paths.insert(item.id, (self.stack.clone(), shortty(&item)));
|
||||
}
|
||||
_ => {}
|
||||
|
@ -9,11 +9,14 @@
|
||||
// except according to those terms.
|
||||
|
||||
use std::num;
|
||||
use std::cell::Cell;
|
||||
use std::uint;
|
||||
use std::hashmap::HashSet;
|
||||
use std::local_data;
|
||||
|
||||
use syntax::ast;
|
||||
|
||||
use core;
|
||||
use clean;
|
||||
use clean::Item;
|
||||
use plugins;
|
||||
@ -51,9 +54,73 @@ pub fn strip_hidden(crate: clean::Crate) -> plugins::PluginResult {
|
||||
|
||||
/// 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 crate: clean::Crate) -> plugins::PluginResult {
|
||||
pub fn strip_private(crate: clean::Crate) -> plugins::PluginResult {
|
||||
// This stripper collects all *retained* nodes.
|
||||
struct Stripper<'self>(&'self mut HashSet<ast::NodeId>);
|
||||
let mut retained = HashSet::new();
|
||||
let crate = Cell::new(crate);
|
||||
let exported_items = do local_data::get(super::analysiskey) |analysis| {
|
||||
let analysis = analysis.unwrap();
|
||||
let mut exported_items = analysis.exported_items.clone();
|
||||
{
|
||||
let mut finder = ExportedItemsFinder {
|
||||
exported_items: &mut exported_items,
|
||||
analysis: analysis,
|
||||
};
|
||||
let c = finder.fold_crate(crate.take());
|
||||
crate.put_back(c);
|
||||
}
|
||||
exported_items
|
||||
};
|
||||
let mut crate = crate.take();
|
||||
|
||||
// strip all private items
|
||||
{
|
||||
let mut stripper = Stripper {
|
||||
retained: &mut retained,
|
||||
exported_items: &exported_items,
|
||||
};
|
||||
crate = stripper.fold_crate(crate);
|
||||
}
|
||||
|
||||
// strip all private implementations of traits
|
||||
{
|
||||
let mut stripper = ImplStripper(&retained);
|
||||
crate = stripper.fold_crate(crate);
|
||||
}
|
||||
(crate, None)
|
||||
}
|
||||
|
||||
struct ExportedItemsFinder<'self> {
|
||||
exported_items: &'self mut HashSet<ast::NodeId>,
|
||||
analysis: &'self core::CrateAnalysis,
|
||||
}
|
||||
|
||||
impl<'self> fold::DocFolder for ExportedItemsFinder<'self> {
|
||||
fn fold_item(&mut self, i: Item) -> Option<Item> {
|
||||
match i.inner {
|
||||
clean::ModuleItem(*) => {
|
||||
if self.analysis.exported_items.contains(&i.id) {
|
||||
match self.analysis.reexports.find(&i.id) {
|
||||
Some(l) => {
|
||||
for &id in l.iter() {
|
||||
self.exported_items.insert(id);
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
return self.fold_item_recur(i);
|
||||
}
|
||||
}
|
||||
|
||||
struct Stripper<'self> {
|
||||
retained: &'self mut HashSet<ast::NodeId>,
|
||||
exported_items: &'self HashSet<ast::NodeId>,
|
||||
}
|
||||
|
||||
impl<'self> fold::DocFolder for Stripper<'self> {
|
||||
fn fold_item(&mut self, i: Item) -> Option<Item> {
|
||||
match i.inner {
|
||||
@ -61,18 +128,15 @@ pub fn strip_private(mut crate: clean::Crate) -> plugins::PluginResult {
|
||||
clean::TypedefItem(*) | clean::StaticItem(*) |
|
||||
clean::StructItem(*) | clean::EnumItem(*) |
|
||||
clean::TraitItem(*) | clean::FunctionItem(*) |
|
||||
clean::ViewItemItem(*) | clean::MethodItem(*) |
|
||||
clean::VariantItem(*) | clean::MethodItem(*) |
|
||||
clean::ForeignFunctionItem(*) | clean::ForeignStaticItem(*) => {
|
||||
// XXX: re-exported items should get surfaced in the docs as
|
||||
// well (using the output of resolve analysis)
|
||||
if i.visibility != Some(ast::public) {
|
||||
if !self.exported_items.contains(&i.id) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
// These are public-by-default (if the enum/struct was public)
|
||||
clean::VariantItem(*) | clean::StructFieldItem(*) => {
|
||||
if i.visibility == Some(ast::private) {
|
||||
clean::ViewItemItem(*) | clean::StructFieldItem(*) => {
|
||||
if i.visibility != Some(ast::public) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
@ -96,7 +160,7 @@ pub fn strip_private(mut crate: clean::Crate) -> plugins::PluginResult {
|
||||
};
|
||||
|
||||
let i = if fastreturn {
|
||||
self.insert(i.id);
|
||||
self.retained.insert(i.id);
|
||||
return Some(i);
|
||||
} else {
|
||||
self.fold_item_recur(i)
|
||||
@ -109,7 +173,7 @@ pub fn strip_private(mut crate: clean::Crate) -> plugins::PluginResult {
|
||||
clean::ModuleItem(ref m) if m.items.len() == 0 => None,
|
||||
clean::ImplItem(ref i) if i.methods.len() == 0 => None,
|
||||
_ => {
|
||||
self.insert(i.id);
|
||||
self.retained.insert(i.id);
|
||||
Some(i)
|
||||
}
|
||||
}
|
||||
@ -140,20 +204,6 @@ pub fn strip_private(mut crate: clean::Crate) -> plugins::PluginResult {
|
||||
}
|
||||
}
|
||||
|
||||
let mut retained = HashSet::new();
|
||||
// First, strip all private items
|
||||
{
|
||||
let mut stripper = Stripper(&mut retained);
|
||||
crate = stripper.fold_crate(crate);
|
||||
}
|
||||
|
||||
// Next, strip all private implementations of traits
|
||||
{
|
||||
let mut stripper = ImplStripper(&retained);
|
||||
crate = stripper.fold_crate(crate);
|
||||
}
|
||||
(crate, None)
|
||||
}
|
||||
|
||||
pub fn unindent_comments(crate: clean::Crate) -> plugins::PluginResult {
|
||||
struct CommentCleaner;
|
||||
|
@ -24,6 +24,7 @@ extern mod rustc;
|
||||
extern mod extra;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::local_data;
|
||||
use std::rt::io::Writer;
|
||||
use std::rt::io::file::FileInfo;
|
||||
use std::rt::io;
|
||||
@ -73,6 +74,7 @@ static DEFAULT_PASSES: &'static [&'static str] = &[
|
||||
];
|
||||
|
||||
local_data_key!(pub ctxtkey: @core::DocContext)
|
||||
local_data_key!(pub analysiskey: core::CrateAnalysis)
|
||||
|
||||
type Output = (clean::Crate, ~[plugins::PluginJson]);
|
||||
|
||||
@ -191,11 +193,12 @@ fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output {
|
||||
let libs = Cell::new(matches.opt_strs("L").map(|s| Path(*s)));
|
||||
let cr = Cell::new(Path(cratefile));
|
||||
info2!("starting to run rustc");
|
||||
let crate = do std::task::try {
|
||||
let (crate, analysis) = do std::task::try {
|
||||
let cr = cr.take();
|
||||
core::run_core(libs.take(), &cr)
|
||||
}.unwrap();
|
||||
info2!("finished with rustc");
|
||||
local_data::set(analysiskey, analysis);
|
||||
|
||||
// Process all of the crate attributes, extracting plugin metadata along
|
||||
// with the passes which we are supposed to run.
|
||||
|
Loading…
Reference in New Issue
Block a user