about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-05-29 01:35:44 -0700
committerAlex Crichton <alex@alexcrichton.com>2014-05-31 21:59:50 -0700
commit8c669d7f749a1f714e00eb4cdcac3a68e2208951 (patch)
tree5523fd74d0204d6369a04122b8a1eac008d3c6c4
parentc2564b8fd4f9669d2426e0e637e71139e2004ea3 (diff)
downloadrust-8c669d7f749a1f714e00eb4cdcac3a68e2208951.tar.gz
rust-8c669d7f749a1f714e00eb4cdcac3a68e2208951.zip
rustdoc: Suck in all impls from external crates
There is currently no way to query all impls for a type from an external crate,
and with primitive types in play this is also quite difficult. Instead of
filtering, just suck in all impls from upstream crates into the local AST, and
have them get stripped later.

This will allow population of all implementations of traits for primitive types,
as well as filling in some corner cases with inlining documentation in other
cases.
-rw-r--r--src/librustdoc/clean/inline.rs42
-rw-r--r--src/librustdoc/core.rs2
-rw-r--r--src/librustdoc/test.rs1
3 files changed, 41 insertions, 4 deletions
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index b60e0a70dd0..0c2714355dc 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -67,12 +67,12 @@ fn try_inline_def(cx: &core::DocContext,
         }
         ast::DefStruct(did) => {
             record_extern_fqn(cx, did, clean::TypeStruct);
-            ret.extend(build_impls(tcx, did).move_iter());
+            ret.extend(build_impls(cx, tcx, did).move_iter());
             clean::StructItem(build_struct(tcx, did))
         }
         ast::DefTy(did) => {
             record_extern_fqn(cx, did, clean::TypeEnum);
-            ret.extend(build_impls(tcx, did).move_iter());
+            ret.extend(build_impls(cx, tcx, did).move_iter());
             build_type(tcx, did)
         }
         // Assume that the enum type is reexported next to the variant, and
@@ -193,7 +193,8 @@ fn build_type(tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEnum {
     })
 }
 
-fn build_impls(tcx: &ty::ctxt,
+fn build_impls(cx: &core::DocContext,
+               tcx: &ty::ctxt,
                did: ast::DefId) -> Vec<clean::Item> {
     ty::populate_implementations_for_type_if_necessary(tcx, did);
     let mut impls = Vec::new();
@@ -205,6 +206,38 @@ fn build_impls(tcx: &ty::ctxt,
         }
     }
 
+    // If this is the first time we've inlined something from this crate, then
+    // we inline *all* impls from the crate into this crate. Note that there's
+    // currently no way for us to filter this based on type, and we likely need
+    // many impls for a variety of reasons.
+    //
+    // Primarily, the impls will be used to populate the documentation for this
+    // type being inlined, but impls can also be used when generating
+    // documentation for primitives (no way to find those specifically).
+    if cx.populated_crate_impls.borrow_mut().insert(did.krate) {
+        csearch::each_top_level_item_of_crate(&tcx.sess.cstore,
+                                              did.krate,
+                                              |def, _, _| {
+            populate_impls(tcx, def, &mut impls)
+        });
+
+        fn populate_impls(tcx: &ty::ctxt,
+                          def: decoder::DefLike,
+                          impls: &mut Vec<clean::Item>) {
+            match def {
+                decoder::DlImpl(did) => impls.push(build_impl(tcx, did)),
+                decoder::DlDef(ast::DefMod(did)) => {
+                    csearch::each_child_of_item(&tcx.sess.cstore,
+                                                did,
+                                                |def, _, _| {
+                        populate_impls(tcx, def, impls)
+                    })
+                }
+                _ => {}
+            }
+        }
+    }
+
     impls
 }
 
@@ -268,7 +301,8 @@ fn build_module(cx: &core::DocContext, tcx: &ty::ctxt,
                     None => {}
                 }
             }
-            decoder::DlImpl(did) => items.push(build_impl(tcx, did)),
+            // All impls were inlined above
+            decoder::DlImpl(..) => {}
             decoder::DlField => fail!("unimplemented field"),
         }
     });
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 27e39e1235c..87b19fecb1f 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -42,6 +42,7 @@ pub struct DocContext {
     pub external_traits: RefCell<Option<HashMap<ast::DefId, clean::Trait>>>,
     pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>,
     pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
+    pub populated_crate_impls: RefCell<HashSet<ast::CrateNum>>,
 }
 
 impl DocContext {
@@ -114,6 +115,7 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<String>)
         external_typarams: RefCell::new(Some(HashMap::new())),
         external_paths: RefCell::new(Some(HashMap::new())),
         inlined: RefCell::new(Some(HashSet::new())),
+        populated_crate_impls: RefCell::new(HashSet::new()),
     }, CrateAnalysis {
         exported_items: exported_items,
         public_items: public_items,
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index e5fc8f1f1a1..c1f61de9be2 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -79,6 +79,7 @@ pub fn run(input: &str,
         external_traits: RefCell::new(None),
         external_typarams: RefCell::new(None),
         inlined: RefCell::new(None),
+        populated_crate_impls: RefCell::new(HashSet::new()),
     };
     super::ctxtkey.replace(Some(ctx));