]> git.lizzy.rs Git - rust.git/commitdiff
rustdoc: Start inlining structs across crates
authorAlex Crichton <alex@alexcrichton.com>
Fri, 23 May 2014 07:42:33 +0000 (00:42 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Sun, 25 May 2014 08:17:57 +0000 (01:17 -0700)
src/librustdoc/clean.rs
src/librustdoc/html/render.rs
src/librustdoc/passes.rs

index 8f98ccc04050a46e6f045c7420c61f72037a43dd..5497ca7b135a0e55d75ff692165389ac24a93e3e 100644 (file)
@@ -27,7 +27,7 @@
 use rustc::metadata::decoder;
 use rustc::middle::ty;
 
-use std::string::String;
+use std::rc::Rc;
 
 use core;
 use doctree;
@@ -53,6 +53,12 @@ fn clean(&self) -> U {
     }
 }
 
+impl<T: Clean<U>, U> Clean<U> for Rc<T> {
+    fn clean(&self) -> U {
+        (**self).clean()
+    }
+}
+
 impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
     fn clean(&self) -> Option<U> {
         match self {
@@ -337,6 +343,14 @@ fn name_str_pair(&self) -> Option<(InternedString, InternedString)> {
         None
     }
 }
+impl<'a> attr::AttrMetaMethods for &'a Attribute {
+    fn name(&self) -> InternedString { (**self).name() }
+    fn value_str(&self) -> Option<InternedString> { (**self).value_str() }
+    fn meta_item_list<'a>(&'a self) -> Option<&'a [@ast::MetaItem]> { None }
+    fn name_str_pair(&self) -> Option<(InternedString, InternedString)> {
+        None
+    }
+}
 
 #[deriving(Clone, Encodable, Decodable)]
 pub struct TyParam {
@@ -859,10 +873,7 @@ fn clean(&self) -> TraitMethod {
             visibility: Some(ast::Inherited),
             def_id: self.def_id,
             attrs: load_attrs(tcx, self.def_id),
-            source: Span {
-                filename: "".to_strbuf(),
-                loline: 0, locol: 0, hiline: 0, hicol: 0,
-            },
+            source: Span::empty(),
             inner: TyMethodItem(TyMethod {
                 fn_style: self.fty.fn_style,
                 generics: self.generics.clean(),
@@ -1070,6 +1081,31 @@ fn clean(&self) -> Item {
     }
 }
 
+impl Clean<Item> for ty::field_ty {
+    fn clean(&self) -> Item {
+        use syntax::parse::token::special_idents::unnamed_field;
+        let name = if self.name == unnamed_field.name {
+            None
+        } else {
+            Some(self.name)
+        };
+        let cx = super::ctxtkey.get().unwrap();
+        let tcx = match cx.maybe_typed {
+            core::Typed(ref tycx) => tycx,
+            core::NotTyped(_) => fail!(),
+        };
+        let ty = ty::lookup_item_type(tcx, self.id);
+        Item {
+            name: name.clean(),
+            attrs: load_attrs(tcx, self.id),
+            source: Span::empty(),
+            visibility: Some(self.vis),
+            def_id: self.id,
+            inner: StructFieldItem(TypedStructField(ty.ty.clean())),
+        }
+    }
+}
+
 pub type Visibility = ast::Visibility;
 
 impl Clean<Option<Visibility>> for ast::Visibility {
@@ -1199,6 +1235,16 @@ pub struct Span {
     pub hicol: uint,
 }
 
+impl Span {
+    fn empty() -> Span {
+        Span {
+            filename: "".to_strbuf(),
+            loline: 0, locol: 0,
+            hiline: 0, hicol: 0,
+        }
+    }
+}
+
 impl Clean<Span> for syntax::codemap::Span {
     fn clean(&self) -> Span {
         let ctxt = super::ctxtkey.get().unwrap();
@@ -1270,6 +1316,12 @@ fn clean(&self) -> String {
     }
 }
 
+impl Clean<StrBuf> for ast::Name {
+    fn clean(&self) -> StrBuf {
+        token::get_name(*self).get().to_strbuf()
+    }
+}
+
 #[deriving(Clone, Encodable, Decodable)]
 pub struct Typedef {
     pub type_: Type,
@@ -1366,19 +1418,14 @@ pub struct Impl {
     pub derived: bool,
 }
 
+fn detect_derived<M: AttrMetaMethods>(attrs: &[M]) -> bool {
+    attrs.iter().any(|attr| {
+        attr.name().get() == "automatically_derived"
+    })
+}
+
 impl Clean<Item> for doctree::Impl {
     fn clean(&self) -> Item {
-        let mut derived = false;
-        for attr in self.attrs.iter() {
-            match attr.node.value.node {
-                ast::MetaWord(ref s) => {
-                    if s.get() == "automatically_derived" {
-                        derived = true;
-                    }
-                }
-                _ => {}
-            }
-        }
         Item {
             name: None,
             attrs: self.attrs.clean(),
@@ -1390,7 +1437,7 @@ fn clean(&self) -> Item {
                 trait_: self.trait_.clean(),
                 for_: self.for_.clean(),
                 methods: self.methods.clean(),
-                derived: derived,
+                derived: detect_derived(self.attrs.as_slice()),
             }),
         }
     }
@@ -1427,7 +1474,9 @@ fn clean(&self) -> Vec<Item> {
                     ast::ViewPathList(ref a, ref list, ref b) => {
                         let remaining = list.iter().filter(|path| {
                             match try_inline(path.node.id) {
-                                Some(item) => { ret.push(item); false }
+                                Some(items) => {
+                                    ret.extend(items.move_iter()); false
+                                }
                                 None => true,
                             }
                         }).map(|a| a.clone()).collect::<Vec<ast::PathListIdent>>();
@@ -1441,7 +1490,7 @@ fn clean(&self) -> Vec<Item> {
                     }
                     ast::ViewPathSimple(_, _, id) => {
                         match try_inline(id) {
-                            Some(item) => ret.push(item),
+                            Some(items) => ret.extend(items.move_iter()),
                             None => ret.push(convert(&self.node)),
                         }
                     }
@@ -1453,7 +1502,7 @@ fn clean(&self) -> Vec<Item> {
     }
 }
 
-fn try_inline(id: ast::NodeId) -> Option<Item> {
+fn try_inline(id: ast::NodeId) -> Option<Vec<Item>> {
     let cx = super::ctxtkey.get().unwrap();
     let tcx = match cx.maybe_typed {
         core::Typed(ref tycx) => tycx,
@@ -1465,23 +1514,28 @@ fn try_inline(id: ast::NodeId) -> Option<Item> {
     };
     let did = ast_util::def_id_of_def(def);
     if ast_util::is_local(did) { return None }
+
+    let mut ret = Vec::new();
     let inner = match def {
         ast::DefTrait(did) => TraitItem(build_external_trait(tcx, did)),
         ast::DefFn(did, style) =>
             FunctionItem(build_external_function(tcx, did, style)),
+        ast::DefStruct(did) => {
+            ret.extend(build_impls(tcx, did).move_iter());
+            StructItem(build_struct(tcx, did))
+        }
         _ => return None,
     };
     let fqn = csearch::get_item_path(tcx, did);
-    Some(Item {
-        source: Span {
-            filename: "".to_strbuf(), loline: 0, locol: 0, hiline: 0, hicol: 0,
-        },
+    ret.push(Item {
+        source: Span::empty(),
         name: Some(fqn.last().unwrap().to_str().to_strbuf()),
         attrs: load_attrs(tcx, did),
         inner: inner,
         visibility: Some(ast::Public),
         def_id: did,
-    })
+    });
+    Some(ret)
 }
 
 fn load_attrs(tcx: &ty::ctxt, did: ast::DefId) -> Vec<Attribute> {
@@ -1726,7 +1780,7 @@ fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId {
 }
 
 fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> Trait {
-    let def = csearch::get_trait_def(tcx, did);
+    let def = ty::lookup_trait_def(tcx, did);
     let methods = ty::trait_methods(tcx, did);
     Trait {
         generics: def.generics.clean(),
@@ -1738,7 +1792,7 @@ fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> Trait {
 fn build_external_function(tcx: &ty::ctxt,
                            did: ast::DefId,
                            style: ast::FnStyle) -> Function {
-    let t = csearch::get_type(tcx, did);
+    let t = ty::lookup_item_type(tcx, did);
     Function {
         decl: match ty::get(t.ty).sty {
             ty::ty_bare_fn(ref f) => f.sig.clean(),
@@ -1749,6 +1803,111 @@ fn build_external_function(tcx: &ty::ctxt,
     }
 }
 
+fn build_struct(tcx: &ty::ctxt, did: ast::DefId) -> Struct {
+    use syntax::parse::token::special_idents::unnamed_field;
+
+    let t = ty::lookup_item_type(tcx, did);
+    let fields = ty::lookup_struct_fields(tcx, did);
+
+    Struct {
+        struct_type: match fields.as_slice() {
+            [] => doctree::Unit,
+            [ref f] if f.name == unnamed_field.name => doctree::Newtype,
+            [ref f, ..] if f.name == unnamed_field.name => doctree::Tuple,
+            _ => doctree::Plain,
+        },
+        generics: t.generics.clean(),
+        fields: fields.iter().map(|f| f.clean()).collect(),
+        fields_stripped: false,
+    }
+}
+
+fn build_impls(tcx: &ty::ctxt,
+               did: ast::DefId) -> Vec<Item> {
+    ty::populate_implementations_for_type_if_necessary(tcx, did);
+    let mut impls = Vec::new();
+
+    match tcx.inherent_impls.borrow().find(&did) {
+        None => {}
+        Some(i) => {
+            impls.extend(i.borrow().iter().map(|&did| { build_impl(tcx, did) }));
+        }
+    }
+
+    // csearch::each_impl(&tcx.sess.cstore, did.krate, |imp| {
+    //     // if imp.krate
+    //     let t = ty::lookup_item_type(tcx, imp);
+    //     println!("{}", ::rustc::util::ppaux::ty_to_str(tcx, t.ty));
+    //     match ty::get(t.ty).sty {
+    //         ty::ty_struct(tdid, _) |
+    //         ty::ty_enum(tdid, _) if tdid == did => {
+    //             impls.push(build_impl(tcx, imp));
+    //         }
+    //         _ => {}
+    //     }
+    // });
+    // for (k, v) in tcx.trait_impls.borrow().iter() {
+    //     if k.krate != did.krate { continue }
+    //     for imp in v.borrow().iter() {
+    //         if imp.krate != did.krate { continue }
+    //         let t = ty::lookup_item_type(tcx, *imp);
+    //         println!("{}", ::rustc::util::ppaux::ty_to_str(tcx, t.ty));
+    //         match ty::get(t.ty).sty {
+    //             ty::ty_struct(tdid, _) |
+    //             ty::ty_enum(tdid, _) if tdid == did => {
+    //                 impls.push(build_impl(tcx, *imp));
+    //             }
+    //             _ => {}
+    //         }
+    //     }
+    // }
+
+    impls
+}
+
+fn build_impl(tcx: &ty::ctxt, did: ast::DefId) -> Item {
+    let associated_trait = csearch::get_impl_trait(tcx, did);
+    let attrs = load_attrs(tcx, did);
+    let ty = ty::lookup_item_type(tcx, did);
+    let methods = tcx.impl_methods.borrow().get(&did).iter().map(|did| {
+        let mut item = match ty::method(tcx, *did).clean() {
+            Provided(item) => item,
+            Required(item) => item,
+        };
+        item.inner = match item.inner.clone() {
+            TyMethodItem(TyMethod { fn_style, decl, self_, generics }) => {
+                MethodItem(Method {
+                    fn_style: fn_style,
+                    decl: decl,
+                    self_: self_,
+                    generics: generics,
+                })
+            }
+            _ => fail!("not a tymethod"),
+        };
+        item
+    }).collect();
+    Item {
+        inner: ImplItem(Impl {
+            derived: detect_derived(attrs.as_slice()),
+            trait_: associated_trait.clean().map(|bound| {
+                match bound {
+                    TraitBound(ty) => ty,
+                    RegionBound => fail!(),
+                }
+            }),
+            for_: ty.ty.clean(),
+            generics: ty.generics.clean(),
+            methods: methods,
+        }),
+        source: Span::empty(),
+        name: None,
+        attrs: attrs,
+        visibility: Some(ast::Inherited),
+        def_id: did,
+    }
+}
+
 fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
     ImportSource {
         path: path,
index 76b7a7a2101e2ca5f3066dddf46ba84583e37078..93bd5249a2f71459a074c3e0ccbfa43e71482575 100644 (file)
@@ -132,7 +132,7 @@ pub struct Cache {
     ///
     /// The values of the map are a list of implementations and documentation
     /// found on that implementation.
-    pub impls: HashMap<ast::NodeId, Vec<(clean::Impl, Option<String>)>>,
+    pub impls: HashMap<ast::DefId, Vec<(clean::Impl, Option<String>)>>,
 
     /// Maintains a mapping of local crate node ids to the fully qualified name
     /// and "short type description" of that node. This is used when generating
@@ -837,10 +837,8 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                 match item {
                     clean::Item{ attrs, inner: clean::ImplItem(i), .. } => {
                         match i.for_ {
-                            clean::ResolvedPath { did, .. }
-                                if ast_util::is_local(did) =>
-                            {
-                                let v = self.impls.find_or_insert_with(did.node, |_| {
+                            clean::ResolvedPath { did, .. } => {
+                                let v = self.impls.find_or_insert_with(did, |_| {
                                     Vec::new()
                                 });
                                 // extract relevant documentation for this impl
@@ -1664,7 +1662,7 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
 }
 
 fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
-    match cache_key.get().unwrap().impls.find(&it.def_id.node) {
+    match cache_key.get().unwrap().impls.find(&it.def_id) {
         Some(v) => {
             let mut non_trait = v.iter().filter(|p| {
                 p.ref0().trait_.is_none()
index 16c319d6363bb1702f409ff095c93274f48ced28..390f81642e6b2092cbb045a238a9b5e6fe2f37f5 100644 (file)
@@ -152,7 +152,8 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             clean::ImplItem(clean::Impl{
                 for_: clean::ResolvedPath{ did, .. }, ..
             }) => {
-                if !self.exported_items.contains(&did.node) {
+                if ast_util::is_local(did) &&
+                   !self.exported_items.contains(&did.node) {
                     return None;
                 }
             }