rustdoc: Move inlining to its own module

This commit is contained in:
Alex Crichton 2014-05-24 11:56:38 -07:00
parent bd339ced36
commit 3100bc5b82
9 changed files with 406 additions and 352 deletions

View File

@ -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

View File

@ -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)

View File

@ -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) {

View File

@ -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,
}
}

View File

@ -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<T> {
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<String> = 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<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 @@ fn clean(&self) -> Vec<Item> {
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<Item> {
}
}
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<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,
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,

View File

@ -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 @@ fn ismodule(&self) -> bool {
}
}
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 @@ fn link(&self) -> Option<String> {
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,
"<a class='source' id='src-{}' \
@ -1288,7 +1317,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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())
}

View File

@ -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');
}
}());

View File

@ -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

View File

@ -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;