rustdoc: Implement stripping based on privacy

This will probably need to get tweaked once the privacy rules have been fully
agreed on, but for now this has all of the infrastructure necessary for
filtering out private items.

Closes #9410
This commit is contained in:
Alex Crichton 2013-09-24 13:55:22 -07:00
parent acab4a8c8e
commit c838351ba6
5 changed files with 91 additions and 5 deletions

View file

@ -15,6 +15,7 @@ use its = syntax::parse::token::ident_to_str;
use syntax;
use syntax::ast;
use syntax::ast_util;
use syntax::attr::AttributeMethods;
use std;
@ -283,7 +284,7 @@ impl Clean<Item> for ast::method {
attrs: self.attrs.clean(),
source: self.span.clean(),
id: self.self_id.clone(),
visibility: None,
visibility: self.vis.clean(),
inner: MethodItem(Method {
generics: self.generics.clean(),
self_: self.explicit_self.clean(),

View file

@ -13,6 +13,7 @@ use std::local_data;
use std::rt::io;
use syntax::ast;
use syntax::ast_util;
use clean;
use html::render::{cache_key, current_location_key};

View file

@ -615,13 +615,21 @@ fn document(w: &mut io::Writer, item: &clean::Item) {
fn item_module(w: &mut io::Writer, cx: &Context,
item: &clean::Item, items: &[clean::Item]) {
document(w, item);
debug2!("{:?}", items);
let mut indices = vec::from_fn(items.len(), |i| i);
fn lt(i1: &clean::Item, i2: &clean::Item) -> bool {
fn lt(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> bool {
if shortty(i1) == shortty(i2) {
return i1.name < i2.name;
}
match (&i1.inner, &i2.inner) {
(&clean::ViewItemItem(ref a), &clean::ViewItemItem(ref b)) => {
match (&a.inner, &b.inner) {
(&clean::ExternMod(*), _) => true,
(_, &clean::ExternMod(*)) => false,
_ => idx1 < idx2,
}
}
(&clean::ViewItemItem(*), _) => true,
(_, &clean::ViewItemItem(*)) => false,
(&clean::ModuleItem(*), _) => true,
@ -638,18 +646,19 @@ fn item_module(w: &mut io::Writer, cx: &Context,
(_, &clean::FunctionItem(*)) => false,
(&clean::TypedefItem(*), _) => true,
(_, &clean::TypedefItem(*)) => false,
_ => false,
_ => idx1 < idx2,
}
}
debug2!("{:?}", indices);
do sort::quick_sort(indices) |&i1, &i2| {
lt(&items[i1], &items[i2])
lt(&items[i1], &items[i2], i1, i2)
}
debug2!("{:?}", indices);
let mut curty = "";
for &idx in indices.iter() {
let myitem = &items[idx];
if myitem.name.is_none() { loop }
let myty = shortty(myitem);
if myty != curty {

View file

@ -46,6 +46,78 @@ pub fn strip_hidden(crate: clean::Crate) -> plugins::PluginResult {
(crate, None)
}
/// 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(crate: clean::Crate) -> plugins::PluginResult {
struct Stripper;
impl fold::DocFolder for Stripper {
fn fold_item(&mut self, i: Item) -> Option<Item> {
match i.inner {
// These items can all get re-exported
clean::TypedefItem(*) | clean::StaticItem(*) |
clean::StructItem(*) | clean::EnumItem(*) |
clean::TraitItem(*) | clean::FunctionItem(*) |
clean::ViewItemItem(*) | clean::MethodItem(*) => {
// XXX: re-exported items should get surfaced in the docs as
// well (using the output of resolve analysis)
if i.visibility != Some(ast::public) {
return None;
}
}
// These are public-by-default (if the enum was public)
clean::VariantItem(*) => {
if i.visibility == Some(ast::private) {
return None;
}
}
// We show these regardless of whether they're public/private
// because it's useful to see sometimes
clean::StructFieldItem(*) => {}
// handled below
clean::ModuleItem(*) => {}
// impls/tymethods have no control over privacy
clean::ImplItem(*) | clean::TyMethodItem(*) => {}
}
let fastreturn = match i.inner {
// nothing left to do for traits (don't want to filter their
// methods out, visibility controlled by the trait)
clean::TraitItem(*) => true,
// implementations of traits are always public.
clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
_ => false,
};
let i = if fastreturn {
return Some(i);
} else {
self.fold_item_recur(i)
};
match i {
Some(i) => {
match i.inner {
// emptied modules/impls have no need to exist
clean::ModuleItem(ref m) if m.items.len() == 0 => None,
clean::ImplItem(ref i) if i.methods.len() == 0 => None,
_ => Some(i),
}
}
None => None,
}
}
}
let mut stripper = Stripper;
let crate = stripper.fold_crate(crate);
(crate, None)
}
pub fn unindent_comments(crate: clean::Crate) -> plugins::PluginResult {
struct CommentCleaner;
impl fold::DocFolder for CommentCleaner {

View file

@ -56,11 +56,14 @@ static PASSES: &'static [Pass] = &[
"removes excess indentation on comments in order for markdown to like it"),
("collapse-docs", passes::collapse_docs,
"concatenates all document attributes into one document attribute"),
("strip-private", passes::strip_private,
"strips all private items from a crate which cannot be seen externally"),
];
static DEFAULT_PASSES: &'static [&'static str] = &[
"unindent-comments",
"collapse-docs",
"strip-private",
];
local_data_key!(pub ctxtkey: @core::DocContext)