about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-10-12 14:40:41 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-10-14 18:00:54 -0700
commit3d693d74b814eed6140b9ca29ff01eb3411255a2 (patch)
treed7a020d5a6420947a646cee46ba14be16c183120
parenta7e8957c591651b6568d1b495d29ee85d11c0975 (diff)
downloadrust-3d693d74b814eed6140b9ca29ff01eb3411255a2.tar.gz
rust-3d693d74b814eed6140b9ca29ff01eb3411255a2.zip
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
-rw-r--r--src/librustc/driver/driver.rs2
-rw-r--r--src/librustdoc/core.rs38
-rw-r--r--src/librustdoc/html/render.rs2
-rw-r--r--src/librustdoc/passes.rs206
-rw-r--r--src/librustdoc/rustdoc.rs5
5 files changed, 166 insertions, 87 deletions
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index 0c896007fc3..ef8b859efd6 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -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,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 7537366014e..69d9f8f5946 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -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);
+
+    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());
+    }
 
     debug2!("crate: {:?}", crate);
-    DocContext { crate: crate, tycx: analysis.ty_cx, sess: sess }
+    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 {
-    let ctxt = @get_ast_and_resolve(path, libs);
+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)
 }
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index bb78b5aabb5..5b27adb2967 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -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)));
             }
             _ => {}
diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs
index 43f2896a0d2..aa419a90563 100644
--- a/src/librustdoc/passes.rs
+++ b/src/librustdoc/passes.rs
@@ -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,110 +54,157 @@ 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>);
-    impl<'self> fold::DocFolder for Stripper<'self> {
-        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(*) |
-                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) {
-                        return None;
-                    }
-                }
+    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();
 
-                // These are public-by-default (if the enum/struct was public)
-                clean::VariantItem(*) | clean::StructFieldItem(*) => {
-                    if i.visibility == Some(ast::private) {
-                        return None;
+    // 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>,
+}
 
-                // handled below
-                clean::ModuleItem(*) => {}
+impl<'self> fold::DocFolder for Stripper<'self> {
+    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::VariantItem(*) | clean::MethodItem(*) |
+            clean::ForeignFunctionItem(*) | clean::ForeignStaticItem(*) => {
+                if !self.exported_items.contains(&i.id) {
+                    return None;
+                }
+            }
 
-                // impls/tymethods have no control over privacy
-                clean::ImplItem(*) | clean::TyMethodItem(*) => {}
+            clean::ViewItemItem(*) | clean::StructFieldItem(*) => {
+                if i.visibility != Some(ast::public) {
+                    return None;
+                }
             }
 
-            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,
+            // handled below
+            clean::ModuleItem(*) => {}
 
-                // implementations of traits are always public.
-                clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
+            // impls/tymethods have no control over privacy
+            clean::ImplItem(*) | clean::TyMethodItem(*) => {}
+        }
 
-                _ => false,
-            };
+        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,
 
-            let i = if fastreturn {
-                self.insert(i.id);
-                return Some(i);
-            } else {
-                self.fold_item_recur(i)
-            };
+            // implementations of traits are always public.
+            clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
 
-            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,
-                        _ => {
-                            self.insert(i.id);
-                            Some(i)
-                        }
+            _ => false,
+        };
+
+        let i = if fastreturn {
+            self.retained.insert(i.id);
+            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,
+                    _ => {
+                        self.retained.insert(i.id);
+                        Some(i)
                     }
                 }
-                None => None,
             }
+            None => None,
         }
     }
+}
 
-    // This stripper discards all private impls of traits
-    struct ImplStripper<'self>(&'self HashSet<ast::NodeId>);
-    impl<'self> fold::DocFolder for ImplStripper<'self> {
-        fn fold_item(&mut self, i: Item) -> Option<Item> {
-            match i.inner {
-                clean::ImplItem(ref imp) => {
-                    match imp.trait_ {
-                        Some(clean::ResolvedPath{ id, _ }) => {
-                            if !self.contains(&id) {
-                                return None;
-                            }
+// This stripper discards all private impls of traits
+struct ImplStripper<'self>(&'self HashSet<ast::NodeId>);
+impl<'self> fold::DocFolder for ImplStripper<'self> {
+    fn fold_item(&mut self, i: Item) -> Option<Item> {
+        match i.inner {
+            clean::ImplItem(ref imp) => {
+                match imp.trait_ {
+                    Some(clean::ResolvedPath{ id, _ }) => {
+                        if !self.contains(&id) {
+                            return None;
                         }
-                        Some(*) | None => {}
                     }
+                    Some(*) | None => {}
                 }
-                _ => {}
             }
-            self.fold_item_recur(i)
+            _ => {}
         }
+        self.fold_item_recur(i)
     }
-
-    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;
     impl fold::DocFolder for CommentCleaner {
diff --git a/src/librustdoc/rustdoc.rs b/src/librustdoc/rustdoc.rs
index a724ff3bf74..e989796ae88 100644
--- a/src/librustdoc/rustdoc.rs
+++ b/src/librustdoc/rustdoc.rs
@@ -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.