about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-09-24 13:55:22 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-09-25 14:27:42 -0700
commitc838351ba673c283564875226a2fc6bad0bc1ea1 (patch)
treecdf425851b6cec120c668b97a527ad0ce56957e5
parentacab4a8c8e3aef66a279d2d7f7c55ace2cece9fc (diff)
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
-rw-r--r--src/librustdoc/clean.rs3
-rw-r--r--src/librustdoc/html/format.rs1
-rw-r--r--src/librustdoc/html/render.rs17
-rw-r--r--src/librustdoc/passes.rs72
-rw-r--r--src/librustdoc/rustdoc.rs3
5 files changed, 91 insertions, 5 deletions
diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs
index 0b5c0b8da95..8cbe1eed55a 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<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(),
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 75d6cb588e8..6f05b042dba 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 69c01cf8a45..070c0e5d986 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 5c89dfb974d..8376fa52882 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<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 {
diff --git a/src/librustdoc/rustdoc.rs b/src/librustdoc/rustdoc.rs
index 69092618da2..dd52058be8a 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)