about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-01-07 18:46:16 -0800
committerAlex Crichton <alex@alexcrichton.com>2014-01-07 18:46:16 -0800
commit3425901d934f9e897b76f42309670285293df902 (patch)
tree19beba59281786ca0877b08268ec413cbf973784
parent4329fc6730e381b3b06f9987327072c50a739ad4 (diff)
downloadrust-3425901d934f9e897b76f42309670285293df902.tar.gz
rust-3425901d934f9e897b76f42309670285293df902.zip
Inline reexports in rustdoc
If a reexport comes from a non-public module, then the documentation for the
reexport will be inlined into the module that exports it, but if the reexport is
targeted at a public type (like the prelude), then it is not inlined but rather
hyperlinked.
-rw-r--r--src/librustc/driver/driver.rs9
-rw-r--r--src/librustc/middle/privacy.rs31
-rw-r--r--src/librustdoc/clean.rs2
-rw-r--r--src/librustdoc/core.rs17
-rw-r--r--src/librustdoc/test.rs2
-rw-r--r--src/librustdoc/visit_ast.rs377
6 files changed, 289 insertions, 149 deletions
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index 0fccf50e009..46bdbab2257 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -209,6 +209,7 @@ pub fn phase_2_configure_and_expand(sess: Session,
 pub struct CrateAnalysis {
     exp_map2: middle::resolve::ExportMap2,
     exported_items: middle::privacy::ExportedItems,
+    public_items: middle::privacy::PublicItems,
     ty_cx: ty::ctxt,
     maps: astencode::Maps,
     reachable: @RefCell<HashSet<ast::NodeId>>
@@ -268,9 +269,10 @@ pub fn phase_3_run_analysis_passes(sess: Session,
                                           method_map, ty_cx));
 
     let maps = (external_exports, last_private_map);
-    let exported_items = time(time_passes, "privacy checking", maps, |(a, b)|
-             middle::privacy::check_crate(ty_cx, &method_map, &exp_map2,
-                                          a, b, crate));
+    let (exported_items, public_items) =
+            time(time_passes, "privacy checking", maps, |(a, b)|
+                 middle::privacy::check_crate(ty_cx, &method_map, &exp_map2,
+                                              a, b, crate));
 
     time(time_passes, "effect checking", (), |_|
          middle::effect::check_crate(ty_cx, method_map, crate));
@@ -322,6 +324,7 @@ pub fn phase_3_run_analysis_passes(sess: Session,
         exp_map2: exp_map2,
         ty_cx: ty_cx,
         exported_items: exported_items,
+        public_items: public_items,
         maps: astencode::Maps {
             root_map: root_map,
             method_map: method_map,
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index 5e095061b42..58b35c0b1d8 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -35,6 +35,11 @@ type Context<'a> = (&'a method_map, &'a resolve::ExportMap2);
 /// A set of AST nodes exported by the crate.
 pub type ExportedItems = HashSet<ast::NodeId>;
 
+/// A set of AST nodes that are fully public in the crate. This map is used for
+/// documentation purposes (reexporting a private struct inlines the doc,
+/// reexporting a public struct doesn't inline the doc).
+pub type PublicItems = HashSet<ast::NodeId>;
+
 ////////////////////////////////////////////////////////////////////////////////
 /// The parent visitor, used to determine what's the parent of what (node-wise)
 ////////////////////////////////////////////////////////////////////////////////
@@ -165,6 +170,12 @@ struct EmbargoVisitor<'a> {
     // means that the destination of the reexport is exported, and hence the
     // destination must also be exported.
     reexports: HashSet<ast::NodeId>,
+
+    // These two fields are closely related to one another in that they are only
+    // used for generation of the 'PublicItems' set, not for privacy checking at
+    // all
+    public_items: PublicItems,
+    prev_public: bool,
 }
 
 impl<'a> EmbargoVisitor<'a> {
@@ -186,7 +197,13 @@ impl<'a> EmbargoVisitor<'a> {
 
 impl<'a> Visitor<()> for EmbargoVisitor<'a> {
     fn visit_item(&mut self, item: &ast::item, _: ()) {
-        let orig_all_pub = self.prev_exported;
+        let orig_all_pub = self.prev_public;
+        self.prev_public = orig_all_pub && item.vis == ast::public;
+        if self.prev_public {
+            self.public_items.insert(item.id);
+        }
+
+        let orig_all_exported = self.prev_exported;
         match item.node {
             // impls/extern blocks do not break the "public chain" because they
             // cannot have visibility qualifiers on them anyway
@@ -202,7 +219,7 @@ impl<'a> Visitor<()> for EmbargoVisitor<'a> {
             // `pub` is explicitly listed.
             _ => {
                 self.prev_exported =
-                    (orig_all_pub && item.vis == ast::public) ||
+                    (orig_all_exported && item.vis == ast::public) ||
                      self.reexports.contains(&item.id);
             }
         }
@@ -304,7 +321,8 @@ impl<'a> Visitor<()> for EmbargoVisitor<'a> {
 
         visit::walk_item(self, item, ());
 
-        self.prev_exported = orig_all_pub;
+        self.prev_exported = orig_all_exported;
+        self.prev_public = orig_all_pub;
     }
 
     fn visit_foreign_item(&mut self, a: &ast::foreign_item, _: ()) {
@@ -1002,7 +1020,7 @@ pub fn check_crate(tcx: ty::ctxt,
                    exp_map2: &resolve::ExportMap2,
                    external_exports: resolve::ExternalExports,
                    last_private_map: resolve::LastPrivateMap,
-                   crate: &ast::Crate) -> ExportedItems {
+                   crate: &ast::Crate) -> (ExportedItems, PublicItems) {
     // Figure out who everyone's parent is
     let mut visitor = ParentVisitor {
         parents: HashMap::new(),
@@ -1038,9 +1056,11 @@ pub fn check_crate(tcx: ty::ctxt,
     let mut visitor = EmbargoVisitor {
         tcx: tcx,
         exported_items: HashSet::new(),
+        public_items: HashSet::new(),
         reexports: HashSet::new(),
         exp_map2: exp_map2,
         prev_exported: true,
+        prev_public: true,
     };
     loop {
         let before = visitor.exported_items.len();
@@ -1050,5 +1070,6 @@ pub fn check_crate(tcx: ty::ctxt,
         }
     }
 
-    return visitor.exported_items;
+    let EmbargoVisitor { exported_items, public_items, .. } = visitor;
+    return (exported_items, public_items);
 }
diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs
index ad7fcd6b0c8..8e63dca57b0 100644
--- a/src/librustdoc/clean.rs
+++ b/src/librustdoc/clean.rs
@@ -72,7 +72,7 @@ pub struct Crate {
     externs: HashMap<ast::CrateNum, ExternalCrate>,
 }
 
-impl Clean<Crate> for visit_ast::RustdocVisitor {
+impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
     fn clean(&self) -> Crate {
         use syntax::attr::find_crateid;
         let cx = local_data::get(super::ctxtkey, |x| *x.unwrap());
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 5762e8570df..947038bc8d8 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -34,6 +34,7 @@ pub struct DocContext {
 
 pub struct CrateAnalysis {
     exported_items: privacy::ExportedItems,
+    public_items: privacy::PublicItems,
 }
 
 /// Parses, resolves, and typechecks the given crate
@@ -75,12 +76,15 @@ fn get_ast_and_resolve(cpath: &Path,
     let crate = phase_1_parse_input(sess, cfg.clone(), &input);
     let (crate, ast_map) = phase_2_configure_and_expand(sess, cfg, crate);
     let driver::driver::CrateAnalysis {
-        exported_items, ty_cx, ..
+        exported_items, public_items, ty_cx, ..
     } = phase_3_run_analysis_passes(sess, &crate, ast_map);
 
     debug!("crate: {:?}", crate);
     return (DocContext { crate: crate, tycx: Some(ty_cx), sess: sess },
-            CrateAnalysis { exported_items: exported_items });
+            CrateAnalysis {
+                exported_items: exported_items,
+                public_items: public_items,
+            });
 }
 
 pub fn run_core (libs: HashSet<Path>, cfgs: ~[~str], path: &Path) -> (clean::Crate, CrateAnalysis) {
@@ -88,8 +92,11 @@ pub fn run_core (libs: HashSet<Path>, cfgs: ~[~str], path: &Path) -> (clean::Cra
     let ctxt = @ctxt;
     local_data::set(super::ctxtkey, ctxt);
 
-    let mut v = RustdocVisitor::new();
-    v.visit(&ctxt.crate);
+    let crate = {
+        let mut v = RustdocVisitor::new(ctxt, Some(&analysis));
+        v.visit(&ctxt.crate);
+        v.clean()
+    };
 
-    (v.clean(), analysis)
+    (crate, analysis)
 }
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index a1ef5a62994..31a500718ee 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -67,7 +67,7 @@ pub fn run(input: &str, matches: &getopts::Matches) -> int {
     };
     local_data::set(super::ctxtkey, ctx);
 
-    let mut v = RustdocVisitor::new();
+    let mut v = RustdocVisitor::new(ctx, None);
     v.visit(&ctx.crate);
     let crate = v.clean();
     let (crate, _) = passes::unindent_comments(crate);
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 9b6e809f835..60df2402e9e 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -13,169 +13,278 @@
 
 use syntax::abi::AbiSet;
 use syntax::ast;
+use syntax::ast_util;
+use syntax::ast_map;
 use syntax::codemap::Span;
 
+use core;
 use doctree::*;
 
-pub struct RustdocVisitor {
+pub struct RustdocVisitor<'a> {
     module: Module,
     attrs: ~[ast::Attribute],
+    cx: &'a core::DocContext,
+    analysis: Option<&'a core::CrateAnalysis>,
 }
 
-impl RustdocVisitor {
-    pub fn new() -> RustdocVisitor {
+impl<'a> RustdocVisitor<'a> {
+    pub fn new<'b>(cx: &'b core::DocContext,
+                   analysis: Option<&'b core::CrateAnalysis>) -> RustdocVisitor<'b> {
         RustdocVisitor {
             module: Module::new(None),
             attrs: ~[],
+            cx: cx,
+            analysis: analysis,
         }
     }
-}
 
-impl RustdocVisitor {
     pub fn visit(&mut self, crate: &ast::Crate) {
         self.attrs = crate.attrs.clone();
-        fn visit_struct_def(item: &ast::item, sd: @ast::struct_def, generics:
-                            &ast::Generics) -> Struct {
-            debug!("Visiting struct");
-            let struct_type = struct_type_from_def(sd);
-            Struct {
-                id: item.id,
-                struct_type: struct_type,
-                name: item.ident,
-                vis: item.vis,
-                attrs: item.attrs.clone(),
-                generics: generics.clone(),
-                fields: sd.fields.clone(),
-                where: item.span
-            }
+
+        self.module = self.visit_mod_contents(crate.span, crate.attrs.clone(),
+                                              ast::public, ast::CRATE_NODE_ID,
+                                              &crate.module, None);
+    }
+
+    pub fn visit_struct_def(&mut self, item: &ast::item, sd: @ast::struct_def,
+
+                        generics: &ast::Generics) -> Struct {
+        debug!("Visiting struct");
+        let struct_type = struct_type_from_def(sd);
+        Struct {
+            id: item.id,
+            struct_type: struct_type,
+            name: item.ident,
+            vis: item.vis,
+            attrs: item.attrs.clone(),
+            generics: generics.clone(),
+            fields: sd.fields.clone(),
+            where: item.span
         }
+    }
 
-        fn visit_enum_def(it: &ast::item, def: &ast::enum_def, params: &ast::Generics) -> Enum {
-            debug!("Visiting enum");
-            let mut vars: ~[Variant] = ~[];
-            for x in def.variants.iter() {
-                vars.push(Variant {
-                    name: x.node.name,
-                    attrs: x.node.attrs.clone(),
-                    vis: x.node.vis,
-                    id: x.node.id,
-                    kind: x.node.kind.clone(),
-                    where: x.span,
-                });
-            }
-            Enum {
-                name: it.ident,
-                variants: vars,
-                vis: it.vis,
-                generics: params.clone(),
-                attrs: it.attrs.clone(),
-                id: it.id,
-                where: it.span,
-            }
+    pub fn visit_enum_def(&mut self, it: &ast::item, def: &ast::enum_def,
+                      params: &ast::Generics) -> Enum {
+        debug!("Visiting enum");
+        let mut vars: ~[Variant] = ~[];
+        for x in def.variants.iter() {
+            vars.push(Variant {
+                name: x.node.name,
+                attrs: x.node.attrs.clone(),
+                vis: x.node.vis,
+                id: x.node.id,
+                kind: x.node.kind.clone(),
+                where: x.span,
+            });
+        }
+        Enum {
+            name: it.ident,
+            variants: vars,
+            vis: it.vis,
+            generics: params.clone(),
+            attrs: it.attrs.clone(),
+            id: it.id,
+            where: it.span,
         }
+    }
 
-        fn visit_fn(item: &ast::item, fd: &ast::fn_decl, purity: &ast::purity,
-                     _abi: &AbiSet, gen: &ast::Generics) -> Function {
-            debug!("Visiting fn");
-            Function {
-                id: item.id,
-                vis: item.vis,
-                attrs: item.attrs.clone(),
-                decl: fd.clone(),
-                name: item.ident,
-                where: item.span,
-                generics: gen.clone(),
-                purity: *purity,
-            }
+    pub fn visit_fn(&mut self, item: &ast::item, fd: &ast::fn_decl,
+                    purity: &ast::purity, _abi: &AbiSet,
+                    gen: &ast::Generics) -> Function {
+        debug!("Visiting fn");
+        Function {
+            id: item.id,
+            vis: item.vis,
+            attrs: item.attrs.clone(),
+            decl: fd.clone(),
+            name: item.ident,
+            where: item.span,
+            generics: gen.clone(),
+            purity: *purity,
         }
+    }
 
-        fn visit_mod_contents(span: Span, attrs: ~[ast::Attribute], vis:
-                              ast::visibility, id: ast::NodeId, m: &ast::_mod,
+    pub fn visit_mod_contents(&mut self, span: Span, attrs: ~[ast::Attribute],
+                              vis: ast::visibility, id: ast::NodeId,
+                              m: &ast::_mod,
                               name: Option<ast::Ident>) -> Module {
-            let mut om = Module::new(name);
-            om.view_items = m.view_items.clone();
-            om.where = span;
-            om.attrs = attrs;
-            om.vis = vis;
-            om.id = id;
-            for i in m.items.iter() {
-                visit_item(*i, &mut om);
+        let mut om = Module::new(name);
+        for item in m.view_items.iter() {
+            self.visit_view_item(item, &mut om);
+        }
+        om.where = span;
+        om.attrs = attrs;
+        om.vis = vis;
+        om.id = id;
+        for i in m.items.iter() {
+            self.visit_item(*i, &mut om);
+        }
+        om
+    }
+
+    pub fn visit_view_item(&mut self, item: &ast::view_item, om: &mut Module) {
+        if item.vis != ast::public {
+            return om.view_items.push(item.clone());
+        }
+        let item = match item.node {
+            ast::view_item_use(ref paths) => {
+                // rustc no longer supports "use foo, bar;"
+                assert_eq!(paths.len(), 1);
+                match self.visit_view_path(paths[0], om) {
+                    None => return,
+                    Some(path) => {
+                        ast::view_item {
+                            node: ast::view_item_use(~[path]),
+                            .. item.clone()
+                        }
+                    }
+                }
+            }
+            ast::view_item_extern_mod(..) => item.clone()
+        };
+        om.view_items.push(item);
+    }
+
+    fn visit_view_path(&mut self, path: @ast::view_path,
+                       om: &mut Module) -> Option<@ast::view_path> {
+        match path.node {
+            ast::view_path_simple(_, _, id) => {
+                if self.resolve_id(id, false, om) { return None }
+            }
+            ast::view_path_list(ref p, ref paths, ref b) => {
+                let mut mine = ~[];
+                for path in paths.iter() {
+                    if !self.resolve_id(path.node.id, false, om) {
+                        mine.push(path.clone());
+                    }
+                }
+
+                if mine.len() == 0 { return None }
+                return Some(@::syntax::codemap::Spanned {
+                    node: ast::view_path_list(p.clone(), mine, b.clone()),
+                    span: path.span,
+                })
+            }
+
+            // these are feature gated anyway
+            ast::view_path_glob(_, id) => {
+                if self.resolve_id(id, true, om) { return None }
             }
-            om
         }
+        return Some(path);
+    }
 
-        fn visit_item(item: &ast::item, om: &mut Module) {
-            debug!("Visiting item {:?}", item);
-            match item.node {
-                ast::item_mod(ref m) => {
-                    om.mods.push(visit_mod_contents(item.span, item.attrs.clone(),
-                                                    item.vis, item.id, m,
-                                                    Some(item.ident)));
-                },
-                ast::item_enum(ref ed, ref gen) => om.enums.push(visit_enum_def(item, ed, gen)),
-                ast::item_struct(sd, ref gen) => om.structs.push(visit_struct_def(item, sd, gen)),
-                ast::item_fn(fd, ref pur, ref abi, ref gen, _) =>
-                    om.fns.push(visit_fn(item, fd, pur, abi, gen)),
-                ast::item_ty(ty, ref gen) => {
-                    let t = Typedef {
-                        ty: ty,
-                        gen: gen.clone(),
-                        name: item.ident,
-                        id: item.id,
-                        attrs: item.attrs.clone(),
-                        where: item.span,
-                        vis: item.vis,
-                    };
-                    om.typedefs.push(t);
-                },
-                ast::item_static(ty, ref mut_, ref exp) => {
-                    let s = Static {
-                        type_: ty,
-                        mutability: mut_.clone(),
-                        expr: exp.clone(),
-                        id: item.id,
-                        name: item.ident,
-                        attrs: item.attrs.clone(),
-                        where: item.span,
-                        vis: item.vis,
-                    };
-                    om.statics.push(s);
-                },
-                ast::item_trait(ref gen, ref tr, ref met) => {
-                    let t = Trait {
-                        name: item.ident,
-                        methods: met.clone(),
-                        generics: gen.clone(),
-                        parents: tr.clone(),
-                        id: item.id,
-                        attrs: item.attrs.clone(),
-                        where: item.span,
-                        vis: item.vis,
-                    };
-                    om.traits.push(t);
-                },
-                ast::item_impl(ref gen, ref tr, ty, ref meths) => {
-                    let i = Impl {
-                        generics: gen.clone(),
-                        trait_: tr.clone(),
-                        for_: ty,
-                        methods: meths.clone(),
-                        attrs: item.attrs.clone(),
-                        id: item.id,
-                        where: item.span,
-                        vis: item.vis,
-                    };
-                    om.impls.push(i);
-                },
-                ast::item_foreign_mod(ref fm) => {
-                    om.foreigns.push(fm.clone());
+    fn resolve_id(&mut self, id: ast::NodeId, glob: bool,
+                  om: &mut Module) -> bool {
+        let def = {
+            let dm = match self.cx.tycx {
+                Some(tcx) => tcx.def_map.borrow(),
+                None => return false,
+            };
+            ast_util::def_id_of_def(*dm.get().get(&id))
+        };
+        if !ast_util::is_local(def) { return false }
+        let analysis = match self.analysis {
+            Some(analysis) => analysis, None => return false
+        };
+        if analysis.public_items.contains(&def.node) { return false }
+
+        let item = {
+            let items = self.cx.tycx.unwrap().items.borrow();
+            *items.get().get(&def.node)
+        };
+        match item {
+            ast_map::node_item(it, _) => {
+                if glob {
+                    match it.node {
+                        ast::item_mod(ref m) => {
+                            for vi in m.view_items.iter() {
+                                self.visit_view_item(vi, om);
+                            }
+                            for i in m.items.iter() {
+                                self.visit_item(*i, om);
+                            }
+                        }
+                        _ => { fail!("glob not mapped to a module"); }
+                    }
+                } else {
+                    self.visit_item(it, om);
                 }
-                _ => (),
+                true
             }
+            _ => false,
         }
+    }
 
-        self.module = visit_mod_contents(crate.span, crate.attrs.clone(),
-                                         ast::public, ast::CRATE_NODE_ID,
-                                         &crate.module, None);
+    pub fn visit_item(&mut self, item: &ast::item, om: &mut Module) {
+        debug!("Visiting item {:?}", item);
+        match item.node {
+            ast::item_mod(ref m) => {
+                om.mods.push(self.visit_mod_contents(item.span, item.attrs.clone(),
+                                                item.vis, item.id, m,
+                                                Some(item.ident)));
+            },
+            ast::item_enum(ref ed, ref gen) =>
+                om.enums.push(self.visit_enum_def(item, ed, gen)),
+            ast::item_struct(sd, ref gen) =>
+                om.structs.push(self.visit_struct_def(item, sd, gen)),
+            ast::item_fn(fd, ref pur, ref abi, ref gen, _) =>
+                om.fns.push(self.visit_fn(item, fd, pur, abi, gen)),
+            ast::item_ty(ty, ref gen) => {
+                let t = Typedef {
+                    ty: ty,
+                    gen: gen.clone(),
+                    name: item.ident,
+                    id: item.id,
+                    attrs: item.attrs.clone(),
+                    where: item.span,
+                    vis: item.vis,
+                };
+                om.typedefs.push(t);
+            },
+            ast::item_static(ty, ref mut_, ref exp) => {
+                let s = Static {
+                    type_: ty,
+                    mutability: mut_.clone(),
+                    expr: exp.clone(),
+                    id: item.id,
+                    name: item.ident,
+                    attrs: item.attrs.clone(),
+                    where: item.span,
+                    vis: item.vis,
+                };
+                om.statics.push(s);
+            },
+            ast::item_trait(ref gen, ref tr, ref met) => {
+                let t = Trait {
+                    name: item.ident,
+                    methods: met.clone(),
+                    generics: gen.clone(),
+                    parents: tr.clone(),
+                    id: item.id,
+                    attrs: item.attrs.clone(),
+                    where: item.span,
+                    vis: item.vis,
+                };
+                om.traits.push(t);
+            },
+            ast::item_impl(ref gen, ref tr, ty, ref meths) => {
+                let i = Impl {
+                    generics: gen.clone(),
+                    trait_: tr.clone(),
+                    for_: ty,
+                    methods: meths.clone(),
+                    attrs: item.attrs.clone(),
+                    id: item.id,
+                    where: item.span,
+                    vis: item.vis,
+                };
+                om.impls.push(i);
+            },
+            ast::item_foreign_mod(ref fm) => {
+                om.foreigns.push(fm.clone());
+            }
+            _ => (),
+        }
     }
 }