From 3100bc5b82257820051774eb4aa0447b12f3616a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 May 2014 11:56:38 -0700 Subject: [PATCH] rustdoc: Move inlining to its own module --- src/doc/rustdoc.md | 6 +- src/librustc/metadata/csearch.rs | 2 +- src/librustc/metadata/decoder.rs | 2 +- src/librustdoc/clean/inline.rs | 278 +++++++++++++++++++ src/librustdoc/{clean.rs => clean/mod.rs} | 309 ++-------------------- src/librustdoc/html/render.rs | 39 ++- src/librustdoc/html/static/main.js | 12 +- src/libstd/lib.rs | 12 +- src/libstd/prelude.rs | 98 +++---- 9 files changed, 406 insertions(+), 352 deletions(-) create mode 100644 src/librustdoc/clean/inline.rs rename src/librustdoc/{clean.rs => clean/mod.rs} (85%) 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 + -> Vec { 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 { +pub fn get_method_arg_names(cdata: Cmd, id: ast::NodeId) -> Vec { 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 or the MIT license +// , 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> { + 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> { + 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 { + 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 { + 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 similarity index 85% rename from src/librustdoc/clean.rs rename to src/librustdoc/clean/mod.rs index ab953419a41..f0f68426425 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean/mod.rs @@ -37,6 +37,8 @@ /// Increment this when the `Crate` and related structures change. pub static SCHEMA_VERSION: &'static str = "0.8.2"; +mod inline; + pub trait Clean { fn clean(&self) -> T; } @@ -727,7 +729,7 @@ fn clean(&self) -> FnDecl { 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 @@ fn clean(&self) -> FnDecl { 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 @@ fn clean(&self) -> TraitMethod { 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 @@ fn clean(&self) -> TraitMethod { 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 @@ fn clean(&self) -> Type { 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 = fqn.move_iter().map(|i| { @@ -1110,12 +1109,12 @@ fn clean(&self) -> Item { 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 @@ fn clean(&self) -> Item { 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 @@ fn clean(&self) -> Item { }; 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 @@ fn clean(&self) -> String { } } -impl Clean for ast::Name { - fn clean(&self) -> StrBuf { +impl Clean for ast::Name { + fn clean(&self) -> String { token::get_name(*self).get().to_strbuf() } } @@ -1480,9 +1483,7 @@ pub struct Impl { } fn detect_derived(attrs: &[M]) -> bool { - attrs.iter().any(|attr| { - attr.name().get() == "automatically_derived" - }) + attr::contains_name(attrs, "automatically_derived") } impl Clean for doctree::Impl { @@ -1511,9 +1512,12 @@ pub struct ViewItem { impl Clean> for ast::ViewItem { fn clean(&self) -> Vec { + // 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 @@ fn clean(&self) -> Vec { 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 @@ fn clean(&self) -> Vec { } } 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 @@ fn clean(&self) -> Vec { } } -fn try_inline(id: ast::NodeId) -> Option> { - 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> { - 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 { - 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, 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 { - 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>, + pub external_paths: HashMap>, /// 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, ItemType)> = + let paths: HashMap, 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 @@ fn ismodule(&self) -> bool { } } - fn link(&self) -> Option { + /// 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 { + // 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 @@ fn link(&self) -> Option { 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 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { } // 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, " fmt::Result { try!(write!(f, " = ")); if s.contains("\n") { write!(f, "[definition]", - item.link()) + item.href()) } else { write!(f, "{}", 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;