about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-05-24 11:56:38 -0700
committerAlex Crichton <alex@alexcrichton.com>2014-05-25 13:26:46 -0700
commit3100bc5b82257820051774eb4aa0447b12f3616a (patch)
tree73e95db17bd57c0f2f6df19d336cfaa6323ce256
parentbd339ced3615c89d439b33f6d6ab7bd04c002f74 (diff)
downloadrust-3100bc5b82257820051774eb4aa0447b12f3616a.tar.gz
rust-3100bc5b82257820051774eb4aa0447b12f3616a.zip
rustdoc: Move inlining to its own module
-rw-r--r--src/doc/rustdoc.md6
-rw-r--r--src/librustc/metadata/csearch.rs2
-rw-r--r--src/librustc/metadata/decoder.rs2
-rw-r--r--src/librustdoc/clean/inline.rs278
-rw-r--r--src/librustdoc/clean/mod.rs (renamed from src/librustdoc/clean.rs)309
-rw-r--r--src/librustdoc/html/render.rs39
-rw-r--r--src/librustdoc/html/static/main.js12
-rw-r--r--src/libstd/lib.rs12
-rw-r--r--src/libstd/prelude.rs98
9 files changed, 406 insertions, 352 deletions
diff --git a/src/doc/rustdoc.md b/src/doc/rustdoc.md
index 625a7a6d802..1034c776ea6 100644
--- a/src/doc/rustdoc.md
+++ b/src/doc/rustdoc.md
@@ -41,7 +41,9 @@ pub fn recalibrate() {
 # }
 ~~~
 
-Documentation can also be controlled via the `doc` attribute on items.
+Documentation can also be controlled via the `doc` attribute on items. This is
+implicitly done by the compiler when using the above form of doc comments
+(converting the slash-based comments to `#[doc]` attributes).
 
 ~~~
 #[doc = "
@@ -50,6 +52,7 @@ Calculates the factorial of a number.
 Given the input integer `n`, this function will calculate `n!` and return it.
 "]
 pub fn factorial(n: int) -> int { if n < 2 {1} else {n * factorial(n)} }
+# fn main() {}
 ~~~
 
 The `doc` attribute can also be used to control how rustdoc emits documentation
@@ -60,6 +63,7 @@ in some cases.
 // `pub use` reaches across crates, but this behavior can also be disabled.
 #[doc(no_inline)]
 pub use std::option::Option;
+# fn main() {}
 ```
 
 Doc comments are markdown, and are currently parsed with the
diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index d7f603d1909..d407cc04680 100644
--- a/src/librustc/metadata/csearch.rs
+++ b/src/librustc/metadata/csearch.rs
@@ -308,7 +308,7 @@ pub fn get_missing_lang_items(cstore: &cstore::CStore, cnum: ast::CrateNum)
 }
 
 pub fn get_method_arg_names(cstore: &cstore::CStore, did: ast::DefId)
-    -> Vec<StrBuf>
+    -> Vec<String>
 {
     let cdata = cstore.get_crate_data(did.krate);
     decoder::get_method_arg_names(&*cdata, did.node)
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index 26149785653..e8be05feae8 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -1310,7 +1310,7 @@ pub fn get_missing_lang_items(cdata: Cmd)
     return result;
 }
 
-pub fn get_method_arg_names(cdata: Cmd, id: ast::NodeId) -> Vec<StrBuf> {
+pub fn get_method_arg_names(cdata: Cmd, id: ast::NodeId) -> Vec<String> {
     let mut ret = Vec::new();
     let method_doc = lookup_item(id, cdata.data());
     match reader::maybe_get_doc(method_doc, tag_method_argument_names) {
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
new file mode 100644
index 00000000000..dd5fddca0db
--- /dev/null
+++ b/src/librustdoc/clean/inline.rs
@@ -0,0 +1,278 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Support for inlining external documentation into the current AST.
+
+use syntax::ast;
+use syntax::ast_util;
+use syntax::attr::AttrMetaMethods;
+
+use rustc::metadata::csearch;
+use rustc::metadata::decoder;
+use rustc::middle::ty;
+
+use core;
+use doctree;
+use clean;
+
+use super::Clean;
+
+/// Attempt to inline the definition of a local node id into this AST.
+///
+/// This function will fetch the definition of the id specified, and if it is
+/// from another crate it will attempt to inline the documentation from the
+/// other crate into this crate.
+///
+/// This is primarily used for `pub use` statements which are, in general,
+/// implementation details. Inlining the documentation should help provide a
+/// better experience when reading the documentation in this use case.
+///
+/// The returned value is `None` if the `id` could not be inlined, and `Some`
+/// of a vector of items if it was successfully expanded.
+pub fn try_inline(id: ast::NodeId) -> Option<Vec<clean::Item>> {
+    let cx = ::ctxtkey.get().unwrap();
+    let tcx = match cx.maybe_typed {
+        core::Typed(ref tycx) => tycx,
+        core::NotTyped(_) => return None,
+    };
+    let def = match tcx.def_map.borrow().find(&id) {
+        Some(def) => *def,
+        None => return None,
+    };
+    let did = ast_util::def_id_of_def(def);
+    if ast_util::is_local(did) { return None }
+    try_inline_def(&**cx, tcx, def)
+}
+
+fn try_inline_def(cx: &core::DocContext,
+                  tcx: &ty::ctxt,
+                  def: ast::Def) -> Option<Vec<clean::Item>> {
+    let mut ret = Vec::new();
+    let did = ast_util::def_id_of_def(def);
+    let inner = match def {
+        ast::DefTrait(did) => {
+            record_extern_fqn(cx, did, clean::TypeTrait);
+            clean::TraitItem(build_external_trait(tcx, did))
+        }
+        ast::DefFn(did, style) => {
+            record_extern_fqn(cx, did, clean::TypeFunction);
+            clean::FunctionItem(build_external_function(tcx, did, style))
+        }
+        ast::DefStruct(did) => {
+            record_extern_fqn(cx, did, clean::TypeStruct);
+            ret.extend(build_impls(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());
+            build_type(tcx, did)
+        }
+        // Assume that the enum type is reexported next to the variant, and
+        // variants don't show up in documentation specially.
+        ast::DefVariant(..) => return Some(Vec::new()),
+        ast::DefMod(did) => {
+            record_extern_fqn(cx, did, clean::TypeModule);
+            clean::ModuleItem(build_module(cx, tcx, did))
+        }
+        _ => return None,
+    };
+    let fqn = csearch::get_item_path(tcx, did);
+    ret.push(clean::Item {
+        source: clean::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)
+}
+
+pub fn load_attrs(tcx: &ty::ctxt, did: ast::DefId) -> Vec<clean::Attribute> {
+    let mut attrs = Vec::new();
+    csearch::get_item_attrs(&tcx.sess.cstore, did, |v| {
+        attrs.extend(v.move_iter().map(|mut a| {
+            // FIXME this isn't quite always true, it's just true about 99% of
+            //       the time when dealing with documentation. For example,
+            //       this would treat doc comments of the form `#[doc = "foo"]`
+            //       incorrectly.
+            if a.name().get() == "doc" && a.value_str().is_some() {
+                a.node.is_sugared_doc = true;
+            }
+            a.clean()
+        }));
+    });
+    attrs
+}
+
+/// Record an external fully qualified name in the external_paths cache.
+///
+/// These names are used later on by HTML rendering to generate things like
+/// source links back to the original item.
+pub fn record_extern_fqn(cx: &core::DocContext,
+                         did: ast::DefId,
+                         kind: clean::TypeKind) {
+    match cx.maybe_typed {
+        core::Typed(ref tcx) => {
+            let fqn = csearch::get_item_path(tcx, did);
+            let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()).collect();
+            cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind));
+        }
+        core::NotTyped(..) => {}
+    }
+}
+
+pub fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> clean::Trait {
+    let def = ty::lookup_trait_def(tcx, did);
+    let methods = ty::trait_methods(tcx, did);
+    clean::Trait {
+        generics: def.generics.clean(),
+        methods: methods.iter().map(|i| i.clean()).collect(),
+        parents: Vec::new(), // FIXME: this is likely wrong
+    }
+}
+
+fn build_external_function(tcx: &ty::ctxt,
+                           did: ast::DefId,
+                           style: ast::FnStyle) -> clean::Function {
+    let t = ty::lookup_item_type(tcx, did);
+    clean::Function {
+        decl: match ty::get(t.ty).sty {
+            ty::ty_bare_fn(ref f) => (did, &f.sig).clean(),
+            _ => fail!("bad function"),
+        },
+        generics: t.generics.clean(),
+        fn_style: style,
+    }
+}
+
+fn build_struct(tcx: &ty::ctxt, did: ast::DefId) -> clean::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);
+
+    clean::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_type(tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEnum {
+    let t = ty::lookup_item_type(tcx, did);
+    match ty::get(t.ty).sty {
+        ty::ty_enum(edid, _) => {
+            return clean::EnumItem(clean::Enum {
+                generics: t.generics.clean(),
+                variants_stripped: false,
+                variants: ty::enum_variants(tcx, edid).clean(),
+            })
+        }
+        _ => {}
+    }
+
+    clean::TypedefItem(clean::Typedef {
+        type_: t.ty.clean(),
+        generics: t.generics.clean(),
+    })
+}
+
+fn build_impls(tcx: &ty::ctxt,
+               did: ast::DefId) -> Vec<clean::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) }));
+        }
+    }
+
+    impls
+}
+
+fn build_impl(tcx: &ty::ctxt, did: ast::DefId) -> clean::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 = csearch::get_impl_methods(&tcx.sess.cstore, did).iter().map(|did| {
+        let mut item = match ty::method(tcx, *did).clean() {
+            clean::Provided(item) => item,
+            clean::Required(item) => item,
+        };
+        item.inner = match item.inner.clone() {
+            clean::TyMethodItem(clean::TyMethod {
+                fn_style, decl, self_, generics
+            }) => {
+                clean::MethodItem(clean::Method {
+                    fn_style: fn_style,
+                    decl: decl,
+                    self_: self_,
+                    generics: generics,
+                })
+            }
+            _ => fail!("not a tymethod"),
+        };
+        item
+    }).collect();
+    clean::Item {
+        inner: clean::ImplItem(clean::Impl {
+            derived: clean::detect_derived(attrs.as_slice()),
+            trait_: associated_trait.clean().map(|bound| {
+                match bound {
+                    clean::TraitBound(ty) => ty,
+                    clean::RegionBound => unreachable!(),
+                }
+            }),
+            for_: ty.ty.clean(),
+            generics: ty.generics.clean(),
+            methods: methods,
+        }),
+        source: clean::Span::empty(),
+        name: None,
+        attrs: attrs,
+        visibility: Some(ast::Inherited),
+        def_id: did,
+    }
+}
+
+fn build_module(cx: &core::DocContext, tcx: &ty::ctxt,
+                did: ast::DefId) -> clean::Module {
+    let mut items = Vec::new();
+
+    // FIXME: this doesn't handle reexports inside the module itself.
+    //        Should they be handled?
+    csearch::each_child_of_item(&tcx.sess.cstore, did, |def, _, _| {
+        match def {
+            decoder::DlDef(def) => {
+                match try_inline_def(cx, tcx, def) {
+                    Some(i) => items.extend(i.move_iter()),
+                    None => {}
+                }
+            }
+            decoder::DlImpl(did) => items.push(build_impl(tcx, did)),
+            decoder::DlField => fail!("unimplemented field"),
+        }
+    });
+
+    clean::Module {
+        items: items,
+        is_crate: false,
+    }
+}
diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean/mod.rs
index ab953419a41..f0f68426425 100644
--- a/src/librustdoc/clean.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -37,6 +37,8 @@ use visit_ast;
 /// Increment this when the `Crate` and related structures change.
 pub static SCHEMA_VERSION: &'static str = "0.8.2";
 
+mod inline;
+
 pub trait Clean<T> {
     fn clean(&self) -> T;
 }
@@ -727,7 +729,7 @@ impl<'a> Clean<FnDecl> for (ast::DefId, &'a ty::FnSig) {
         let cx = super::ctxtkey.get().unwrap();
         let tcx = match cx.maybe_typed {
             core::Typed(ref tcx) => tcx,
-            core::NotTyped(_) => fail!(),
+            core::NotTyped(_) => unreachable!(),
         };
         let (did, sig) = *self;
         let mut names = if did.node != 0 {
@@ -738,9 +740,6 @@ impl<'a> Clean<FnDecl> for (ast::DefId, &'a ty::FnSig) {
         if names.peek().map(|s| s.as_slice()) == Some("self") {
             let _ = names.next();
         }
-        if did.node == 0 {
-            let _ = names.len();
-        }
         FnDecl {
             output: sig.output.clean(),
             cf: Return,
@@ -862,7 +861,7 @@ impl Clean<TraitMethod> for ty::Method {
         let cx = super::ctxtkey.get().unwrap();
         let tcx = match cx.maybe_typed {
             core::Typed(ref tcx) => tcx,
-            core::NotTyped(_) => fail!(),
+            core::NotTyped(_) => unreachable!(),
         };
         let (self_, sig) = match self.explicit_self {
             ast::SelfStatic => (ast::SelfStatic.clean(), self.fty.sig.clone()),
@@ -890,7 +889,7 @@ impl Clean<TraitMethod> for ty::Method {
             name: Some(self.ident.clean()),
             visibility: Some(ast::Inherited),
             def_id: self.def_id,
-            attrs: load_attrs(tcx, self.def_id),
+            attrs: inline::load_attrs(tcx, self.def_id),
             source: Span::empty(),
             inner: TyMethodItem(TyMethod {
                 fn_style: self.fty.fn_style,
@@ -1035,7 +1034,7 @@ impl Clean<Type> for ty::t {
                 let cx = super::ctxtkey.get().unwrap();
                 let tcx = match cx.maybe_typed {
                     core::Typed(ref tycx) => tycx,
-                    core::NotTyped(_) => fail!(),
+                    core::NotTyped(_) => unreachable!(),
                 };
                 let fqn = csearch::get_item_path(tcx, did);
                 let fqn: Vec<String> = fqn.move_iter().map(|i| {
@@ -1110,12 +1109,12 @@ impl Clean<Item> for ty::field_ty {
         let cx = super::ctxtkey.get().unwrap();
         let tcx = match cx.maybe_typed {
             core::Typed(ref tycx) => tycx,
-            core::NotTyped(_) => fail!(),
+            core::NotTyped(_) => unreachable!(),
         };
         let ty = ty::lookup_item_type(tcx, self.id);
         Item {
             name: name.clean(),
-            attrs: load_attrs(tcx, self.id),
+            attrs: inline::load_attrs(tcx, self.id),
             source: Span::empty(),
             visibility: Some(self.vis),
             def_id: self.id,
@@ -1245,7 +1244,11 @@ impl Clean<Item> for ty::VariantInfo {
                             name: Some(name.clean()),
                             attrs: Vec::new(),
                             visibility: Some(ast::Public),
-                            def_id: self.id, // FIXME: this is not accurate
+                            // FIXME: this is not accurate, we need an id for
+                            //        the specific field but we're using the id
+                            //        for the whole variant. Nothing currently
+                            //        uses this so we should be good for now.
+                            def_id: self.id,
                             inner: StructFieldItem(
                                 TypedStructField(ty.clean())
                             )
@@ -1256,7 +1259,7 @@ impl Clean<Item> for ty::VariantInfo {
         };
         Item {
             name: Some(self.name.clean()),
-            attrs: load_attrs(tcx, self.id),
+            attrs: inline::load_attrs(tcx, self.id),
             source: Span::empty(),
             visibility: Some(ast::Public),
             def_id: self.id,
@@ -1377,8 +1380,8 @@ impl Clean<String> for ast::Ident {
     }
 }
 
-impl Clean<StrBuf> for ast::Name {
-    fn clean(&self) -> StrBuf {
+impl Clean<String> for ast::Name {
+    fn clean(&self) -> String {
         token::get_name(*self).get().to_strbuf()
     }
 }
@@ -1480,9 +1483,7 @@ pub struct Impl {
 }
 
 fn detect_derived<M: AttrMetaMethods>(attrs: &[M]) -> bool {
-    attrs.iter().any(|attr| {
-        attr.name().get() == "automatically_derived"
-    })
+    attr::contains_name(attrs, "automatically_derived")
 }
 
 impl Clean<Item> for doctree::Impl {
@@ -1511,9 +1512,12 @@ pub struct ViewItem {
 
 impl Clean<Vec<Item>> for ast::ViewItem {
     fn clean(&self) -> Vec<Item> {
+        // We consider inlining the documentation of `pub use` statments, but we
+        // forcefully don't inline if this is not public or if the
+        // #[doc(no_inline)] attribute is present.
         let denied = self.vis != ast::Public || self.attrs.iter().any(|a| {
             a.name().get() == "doc" && match a.meta_item_list() {
-                Some(l) => attr::contains_name(l, "noinline"),
+                Some(l) => attr::contains_name(l, "no_inline"),
                 None => false,
             }
         });
@@ -1533,8 +1537,11 @@ impl Clean<Vec<Item>> for ast::ViewItem {
                 match path.node {
                     ast::ViewPathGlob(..) => ret.push(convert(&self.node)),
                     ast::ViewPathList(ref a, ref list, ref b) => {
+                        // Attempt to inline all reexported items, but be sure
+                        // to keep any non-inlineable reexports so they can be
+                        // listed in the documentation.
                         let remaining = list.iter().filter(|path| {
-                            match try_inline(path.node.id) {
+                            match inline::try_inline(path.node.id) {
                                 Some(items) => {
                                     ret.extend(items.move_iter()); false
                                 }
@@ -1550,7 +1557,7 @@ impl Clean<Vec<Item>> for ast::ViewItem {
                         }
                     }
                     ast::ViewPathSimple(_, _, id) => {
-                        match try_inline(id) {
+                        match inline::try_inline(id) {
                             Some(items) => ret.extend(items.move_iter()),
                             None => ret.push(convert(&self.node)),
                         }
@@ -1563,82 +1570,6 @@ impl Clean<Vec<Item>> for ast::ViewItem {
     }
 }
 
-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,
-        core::NotTyped(_) => return None,
-    };
-    let def = match tcx.def_map.borrow().find(&id) {
-        Some(def) => *def,
-        None => return None,
-    };
-    let did = ast_util::def_id_of_def(def);
-    if ast_util::is_local(did) { return None }
-    try_inline_def(&**cx, tcx, def)
-}
-
-fn try_inline_def(cx: &core::DocContext,
-                  tcx: &ty::ctxt,
-                  def: ast::Def) -> Option<Vec<Item>> {
-    let mut ret = Vec::new();
-    let did = ast_util::def_id_of_def(def);
-    let inner = match def {
-        ast::DefTrait(did) => {
-            record_extern_fqn(cx, did, TypeTrait);
-            TraitItem(build_external_trait(tcx, did))
-        }
-        ast::DefFn(did, style) => {
-            record_extern_fqn(cx, did, TypeFunction);
-            FunctionItem(build_external_function(tcx, did, style))
-        }
-        ast::DefStruct(did) => {
-            record_extern_fqn(cx, did, TypeStruct);
-            ret.extend(build_impls(tcx, did).move_iter());
-            StructItem(build_struct(tcx, did))
-        }
-        ast::DefTy(did) => {
-            record_extern_fqn(cx, did, TypeEnum);
-            ret.extend(build_impls(tcx, did).move_iter());
-            build_type(tcx, did)
-        }
-        // Assume that the enum type is reexported next to the variant, and
-        // variants don't show up in documentation specially.
-        ast::DefVariant(..) => return Some(Vec::new()),
-        ast::DefMod(did) => {
-            record_extern_fqn(cx, did, TypeModule);
-            ModuleItem(build_module(cx, tcx, did))
-        }
-        _ => return None,
-    };
-    let fqn = csearch::get_item_path(tcx, did);
-    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> {
-    let mut attrs = Vec::new();
-    csearch::get_item_attrs(&tcx.sess.cstore, did, |v| {
-        attrs.extend(v.move_iter().map(|item| {
-            let mut a = attr::mk_attr_outer(item);
-            // FIXME this isn't quite always true, it's just true about 99% of
-            //       the time when dealing with documentation
-            if a.name().get() == "doc" && a.value_str().is_some() {
-                a.node.is_sugared_doc = true;
-            }
-            a.clean()
-        }));
-    });
-    attrs
-}
-
 #[deriving(Clone, Encodable, Decodable)]
 pub enum ViewItemInner {
     ExternCrate(String, Option<String>, ast::NodeId),
@@ -1850,10 +1781,10 @@ fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId {
         core::Typed(ref t) => t,
         core::NotTyped(_) => return did
     };
-    record_extern_fqn(cx, did, kind);
+    inline::record_extern_fqn(cx, did, kind);
     match kind {
         TypeTrait => {
-            let t = build_external_trait(tcx, did);
+            let t = inline::build_external_trait(tcx, did);
             cx.external_traits.borrow_mut().get_mut_ref().insert(did, t);
         }
         _ => {}
@@ -1861,190 +1792,6 @@ fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId {
     return did;
 }
 
-fn record_extern_fqn(cx: &core::DocContext,
-                     did: ast::DefId,
-                     kind: TypeKind) {
-    match cx.maybe_typed {
-        core::Typed(ref tcx) => {
-            let fqn = csearch::get_item_path(tcx, did);
-            let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()).collect();
-            cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind));
-        }
-        core::NotTyped(..) => {}
-    }
-}
-
-fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> Trait {
-    let def = ty::lookup_trait_def(tcx, did);
-    let methods = ty::trait_methods(tcx, did);
-    Trait {
-        generics: def.generics.clean(),
-        methods: methods.iter().map(|i| i.clean()).collect(),
-        parents: Vec::new(), // FIXME: this is likely wrong
-    }
-}
-
-fn build_external_function(tcx: &ty::ctxt,
-                           did: ast::DefId,
-                           style: ast::FnStyle) -> Function {
-    let t = ty::lookup_item_type(tcx, did);
-    Function {
-        decl: match ty::get(t.ty).sty {
-            ty::ty_bare_fn(ref f) => (did, &f.sig).clean(),
-            _ => fail!("bad function"),
-        },
-        generics: t.generics.clean(),
-        fn_style: style,
-    }
-}
-
-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_type(tcx: &ty::ctxt, did: ast::DefId) -> ItemEnum {
-    let t = ty::lookup_item_type(tcx, did);
-    match ty::get(t.ty).sty {
-        ty::ty_enum(edid, _) => {
-            return EnumItem(Enum {
-                generics: t.generics.clean(),
-                variants_stripped: false,
-                variants: ty::enum_variants(tcx, edid).clean(),
-            })
-        }
-        _ => {}
-    }
-
-    TypedefItem(Typedef {
-        type_: t.ty.clean(),
-        generics: t.generics.clean(),
-    })
-}
-
-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 = csearch::get_impl_methods(&tcx.sess.cstore, 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 build_module(cx: &core::DocContext, tcx: &ty::ctxt,
-                did: ast::DefId) -> Module {
-    let mut items = Vec::new();
-
-    csearch::each_child_of_item(&tcx.sess.cstore, did, |def, _, _| {
-        match def {
-            decoder::DlDef(def) => {
-                match try_inline_def(cx, tcx, def) {
-                    Some(i) => items.extend(i.move_iter()),
-                    None => {}
-                }
-            }
-            decoder::DlImpl(did) => items.push(build_impl(tcx, did)),
-            decoder::DlField => fail!("unimplemented field"),
-        }
-    });
-
-    Module {
-        items: items,
-        is_crate: false,
-    }
-}
-
 fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
     ImportSource {
         path: path,
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index ce7f230ea53..d601d2ae957 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -143,7 +143,7 @@ pub struct Cache {
 
     /// Similar to `paths`, but only holds external paths. This is only used for
     /// generating explicit hyperlinks to other crates.
-    pub external_paths: HashMap<ast::DefId, Vec<StrBuf>>,
+    pub external_paths: HashMap<ast::DefId, Vec<String>>,
 
     /// This map contains information about all known traits of this crate.
     /// Implementations of a crate should inherit the documentation of the
@@ -253,7 +253,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
     let analysis = ::analysiskey.get();
     let public_items = analysis.as_ref().map(|a| a.public_items.clone());
     let public_items = public_items.unwrap_or(NodeSet::new());
-    let paths: HashMap<ast::DefId, (Vec<StrBuf>, ItemType)> =
+    let paths: HashMap<ast::DefId, (Vec<String>, ItemType)> =
       analysis.as_ref().map(|a| {
         let paths = a.external_paths.borrow_mut().take_unwrap();
         paths.move_iter().map(|(k, (v, t))| {
@@ -1041,7 +1041,19 @@ impl<'a> Item<'a> {
         }
     }
 
-    fn link(&self) -> Option<String> {
+    /// Generate a url appropriate for an `href` attribute back to the source of
+    /// this item.
+    ///
+    /// The url generated, when clicked, will redirect the browser back to the
+    /// original source code.
+    ///
+    /// If `None` is returned, then a source link couldn't be generated. This
+    /// may happen, for example, with externally inlined items where the source
+    /// of their crate documentation isn't known.
+    fn href(&self) -> Option<String> {
+        // If this item is part of the local crate, then we're guaranteed to
+        // know the span, so we plow forward and generate a proper url. The url
+        // has anchors for the line numbers that we're linking to.
         if ast_util::is_local(self.item.def_id) {
             let mut path = Vec::new();
             clean_srcpath(self.item.source.filename.as_bytes(), |component| {
@@ -1059,6 +1071,18 @@ impl<'a> Item<'a> {
                          krate = self.cx.layout.krate,
                          path = path.connect("/"),
                          href = href))
+
+        // If this item is not part of the local crate, then things get a little
+        // trickier. We don't actually know the span of the external item, but
+        // we know that the documentation on the other end knows the span!
+        //
+        // In this case, we generate a link to the *documentation* for this type
+        // in the original crate. There's an extra URL parameter which says that
+        // we want to go somewhere else, and the JS on the destination page will
+        // pick it up and instantly redirect the browser to the source code.
+        //
+        // If we don't know where the external documentation for this crate is
+        // located, then we return `None`.
         } else {
             let cache = cache_key.get().unwrap();
             let path = cache.external_paths.get(&self.item.def_id);
@@ -1120,8 +1144,13 @@ impl<'a> fmt::Show for Item<'a> {
         }
 
         // Write `src` tag
+        //
+        // When this item is part of a `pub use` in a downstream crate, the
+        // [src] link in the downstream documentation will actually come back to
+        // this page, and this link will be auto-clicked. The `id` attribute is
+        // used to find the link to auto-click.
         if self.cx.include_sources {
-            match self.link() {
+            match self.href() {
                 Some(l) => {
                     try!(write!(fmt,
                                 "<a class='source' id='src-{}' \
@@ -1288,7 +1317,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
                         try!(write!(f, "<code> = </code>"));
                         if s.contains("\n") {
                             write!(f, "<a href='{}'>[definition]</a>",
-                                   item.link())
+                                   item.href())
                         } else {
                             write!(f, "<code>{}</code>", s.as_slice())
                         }
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index ec58162fa92..2fb824653d3 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -676,13 +676,9 @@
         window.register_implementors(window.pending_implementors);
     }
 
-
-    var query = window.location.search.substring(1);
-    var vars = query.split('&');
-    for (var i = 0; i < vars.length; i++) {
-        var pair = vars[i].split('=');
-        if (pair[0] == 'gotosrc') {
-            window.location = $('#src-' + pair[1]).attr('href');
-        }
+    // See documentaiton in html/render.rs for what this is doing.
+    var query = getQueryStringParams();
+    if (query['gotosrc']) {
+        window.location = $('#src-' + query['gotosrc']).attr('href');
     }
 }());
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 0d42e1743f5..1786cc8062e 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -16,10 +16,10 @@
 //!
 //! ## Intrinsic types and operations
 //!
-//! The [`ptr`](../core/ptr/index.html) and [`mem`](../core/mem/index.html)
+//! The [`ptr`](ptr/index.html) and [`mem`](mem/index.html)
 //! modules deal with unsafe pointers and memory manipulation.
-//! [`kinds`](../core/kinds/index.html) defines the special built-in traits,
-//! and [`raw`](../core/raw/index.html) the runtime representation of Rust types.
+//! [`kinds`](kinds/index.html) defines the special built-in traits,
+//! and [`raw`](raw/index.html) the runtime representation of Rust types.
 //! These are some of the lowest-level building blocks in Rust.
 //!
 //! ## Math on primitive types and math traits
@@ -31,11 +31,11 @@
 //!
 //! ## Pervasive types
 //!
-//! The [`option`](option/index.html) and [`result`](../core/result/index.html)
+//! The [`option`](option/index.html) and [`result`](result/index.html)
 //! modules define optional and error-handling types, `Option` and `Result`.
-//! [`iter`](../core/iter/index.html) defines Rust's iterator protocol
+//! [`iter`](iter/index.html) defines Rust's iterator protocol
 //! along with a wide variety of iterators.
-//! [`Cell` and `RefCell`](../core/cell/index.html) are for creating types that
+//! [`Cell` and `RefCell`](cell/index.html) are for creating types that
 //! manage their own mutability.
 //!
 //! ## Vectors, slices and strings
diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs
index ef05f3b167a..07aaeac64be 100644
--- a/src/libstd/prelude.rs
+++ b/src/libstd/prelude.rs
@@ -38,62 +38,62 @@
 //! `drop`, `spawn`, and `channel`.
 
 // Reexported core operators
-#[doc(noinline)] pub use kinds::{Copy, Send, Sized, Share};
-#[doc(noinline)] pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
-#[doc(noinline)] pub use ops::{BitAnd, BitOr, BitXor};
-#[doc(noinline)] pub use ops::{Drop, Deref, DerefMut};
-#[doc(noinline)] pub use ops::{Shl, Shr, Index};
-#[doc(noinline)] pub use option::{Option, Some, None};
-#[doc(noinline)] pub use result::{Result, Ok, Err};
+#[doc(no_inline)] pub use kinds::{Copy, Send, Sized, Share};
+#[doc(no_inline)] pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
+#[doc(no_inline)] pub use ops::{BitAnd, BitOr, BitXor};
+#[doc(no_inline)] pub use ops::{Drop, Deref, DerefMut};
+#[doc(no_inline)] pub use ops::{Shl, Shr, Index};
+#[doc(no_inline)] pub use option::{Option, Some, None};
+#[doc(no_inline)] pub use result::{Result, Ok, Err};
 
 // Reexported functions
-#[doc(noinline)] pub use from_str::from_str;
-#[doc(noinline)] pub use iter::range;
-#[doc(noinline)] pub use mem::drop;
+#[doc(no_inline)] pub use from_str::from_str;
+#[doc(no_inline)] pub use iter::range;
+#[doc(no_inline)] pub use mem::drop;
 
 // Reexported types and traits
 
-#[doc(noinline)] pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr};
-#[doc(noinline)] pub use ascii::IntoBytes;
-#[doc(noinline)] pub use c_str::ToCStr;
-#[doc(noinline)] pub use char::Char;
-#[doc(noinline)] pub use clone::Clone;
-#[doc(noinline)] pub use cmp::{Eq, Ord, TotalEq, TotalOrd};
-#[doc(noinline)] pub use cmp::{Ordering, Less, Equal, Greater, Equiv};
-#[doc(noinline)] pub use container::{Container, Mutable, Map, MutableMap};
-#[doc(noinline)] pub use container::{Set, MutableSet};
-#[doc(noinline)] pub use iter::{FromIterator, Extendable, ExactSize};
-#[doc(noinline)] pub use iter::{Iterator, DoubleEndedIterator};
-#[doc(noinline)] pub use iter::{RandomAccessIterator, CloneableIterator};
-#[doc(noinline)] pub use iter::{OrdIterator, MutableDoubleEndedIterator};
-#[doc(noinline)] pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
-#[doc(noinline)] pub use num::{Signed, Unsigned, Primitive, Int, Float};
-#[doc(noinline)] pub use num::{FloatMath, ToPrimitive, FromPrimitive};
-#[doc(noinline)] pub use option::Expect;
-#[doc(noinline)] pub use owned::Box;
-#[doc(noinline)] pub use path::{GenericPath, Path, PosixPath, WindowsPath};
-#[doc(noinline)] pub use ptr::RawPtr;
-#[doc(noinline)] pub use io::{Buffer, Writer, Reader, Seek};
-#[doc(noinline)] pub use str::{Str, StrVector, StrSlice, OwnedStr};
-#[doc(noinline)] pub use str::{IntoMaybeOwned, StrAllocating};
-#[doc(noinline)] pub use to_str::{ToStr, IntoStr};
-#[doc(noinline)] pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4};
-#[doc(noinline)] pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8};
-#[doc(noinline)] pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12};
-#[doc(noinline)] pub use slice::{CloneableVector, ImmutableCloneableVector};
-#[doc(noinline)] pub use slice::{MutableCloneableVector, MutableTotalOrdVector};
-#[doc(noinline)] pub use slice::{ImmutableVector, MutableVector};
-#[doc(noinline)] pub use slice::{ImmutableEqVector, ImmutableTotalOrdVector};
-#[doc(noinline)] pub use slice::{Vector, VectorVector, OwnedVector};
-#[doc(noinline)] pub use slice::MutableVectorAllocating;
-#[doc(noinline)] pub use string::String;
-#[doc(noinline)] pub use vec::Vec;
+#[doc(no_inline)] pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr};
+#[doc(no_inline)] pub use ascii::IntoBytes;
+#[doc(no_inline)] pub use c_str::ToCStr;
+#[doc(no_inline)] pub use char::Char;
+#[doc(no_inline)] pub use clone::Clone;
+#[doc(no_inline)] pub use cmp::{Eq, Ord, TotalEq, TotalOrd};
+#[doc(no_inline)] pub use cmp::{Ordering, Less, Equal, Greater, Equiv};
+#[doc(no_inline)] pub use container::{Container, Mutable, Map, MutableMap};
+#[doc(no_inline)] pub use container::{Set, MutableSet};
+#[doc(no_inline)] pub use iter::{FromIterator, Extendable, ExactSize};
+#[doc(no_inline)] pub use iter::{Iterator, DoubleEndedIterator};
+#[doc(no_inline)] pub use iter::{RandomAccessIterator, CloneableIterator};
+#[doc(no_inline)] pub use iter::{OrdIterator, MutableDoubleEndedIterator};
+#[doc(no_inline)] pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
+#[doc(no_inline)] pub use num::{Signed, Unsigned, Primitive, Int, Float};
+#[doc(no_inline)] pub use num::{FloatMath, ToPrimitive, FromPrimitive};
+#[doc(no_inline)] pub use option::Expect;
+#[doc(no_inline)] pub use owned::Box;
+#[doc(no_inline)] pub use path::{GenericPath, Path, PosixPath, WindowsPath};
+#[doc(no_inline)] pub use ptr::RawPtr;
+#[doc(no_inline)] pub use io::{Buffer, Writer, Reader, Seek};
+#[doc(no_inline)] pub use str::{Str, StrVector, StrSlice, OwnedStr};
+#[doc(no_inline)] pub use str::{IntoMaybeOwned, StrAllocating};
+#[doc(no_inline)] pub use to_str::{ToStr, IntoStr};
+#[doc(no_inline)] pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4};
+#[doc(no_inline)] pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8};
+#[doc(no_inline)] pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12};
+#[doc(no_inline)] pub use slice::{CloneableVector, ImmutableCloneableVector};
+#[doc(no_inline)] pub use slice::{MutableCloneableVector, MutableTotalOrdVector};
+#[doc(no_inline)] pub use slice::{ImmutableVector, MutableVector};
+#[doc(no_inline)] pub use slice::{ImmutableEqVector, ImmutableTotalOrdVector};
+#[doc(no_inline)] pub use slice::{Vector, VectorVector, OwnedVector};
+#[doc(no_inline)] pub use slice::MutableVectorAllocating;
+#[doc(no_inline)] pub use string::String;
+#[doc(no_inline)] pub use vec::Vec;
 
 // Reexported runtime types
-#[doc(noinline)] pub use comm::{sync_channel, channel};
-#[doc(noinline)] pub use comm::{SyncSender, Sender, Receiver};
-#[doc(noinline)] pub use task::spawn;
+#[doc(no_inline)] pub use comm::{sync_channel, channel};
+#[doc(no_inline)] pub use comm::{SyncSender, Sender, Receiver};
+#[doc(no_inline)] pub use task::spawn;
 
 // Reexported statics
 #[cfg(not(test))]
-#[doc(noinline)] pub use gc::GC;
+#[doc(no_inline)] pub use gc::GC;