From c838351ba673c283564875226a2fc6bad0bc1ea1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 24 Sep 2013 13:55:22 -0700 Subject: [PATCH] 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 --- src/librustdoc/clean.rs | 3 +- src/librustdoc/html/format.rs | 1 + src/librustdoc/html/render.rs | 17 +++++++-- src/librustdoc/passes.rs | 72 +++++++++++++++++++++++++++++++++++ src/librustdoc/rustdoc.rs | 3 ++ 5 files changed, 91 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index 0b5c0b8da95b8..8cbe1eed55af4 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -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 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(), diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 75d6cb588e8ec..6f05b042dba1c 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -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}; diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 69c01cf8a45a2..070c0e5d98642 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -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 { diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index 5c89dfb974da2..8376fa52882ad 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -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 { + 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 { diff --git a/src/librustdoc/rustdoc.rs b/src/librustdoc/rustdoc.rs index 69092618da20c..dd52058be8ac4 100644 --- a/src/librustdoc/rustdoc.rs +++ b/src/librustdoc/rustdoc.rs @@ -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)