rustdoc: Start inlining structs across crates

This commit is contained in:
Alex Crichton 2014-05-23 00:42:33 -07:00
parent 8b8e70ba1d
commit c81b511bfd
3 changed files with 192 additions and 34 deletions

View file

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

View file

@ -132,7 +132,7 @@ pub struct Cache {
///
/// The values of the map are a list of implementations and documentation
/// found on that implementation.
pub impls: HashMap<ast::NodeId, Vec<(clean::Impl, Option<String>)>>,
pub impls: HashMap<ast::DefId, Vec<(clean::Impl, Option<String>)>>,
/// Maintains a mapping of local crate node ids to the fully qualified name
/// and "short type description" of that node. This is used when generating
@ -837,10 +837,8 @@ impl DocFolder for Cache {
match item {
clean::Item{ attrs, inner: clean::ImplItem(i), .. } => {
match i.for_ {
clean::ResolvedPath { did, .. }
if ast_util::is_local(did) =>
{
let v = self.impls.find_or_insert_with(did.node, |_| {
clean::ResolvedPath { did, .. } => {
let v = self.impls.find_or_insert_with(did, |_| {
Vec::new()
});
// extract relevant documentation for this impl
@ -1664,7 +1662,7 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
}
fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
match cache_key.get().unwrap().impls.find(&it.def_id.node) {
match cache_key.get().unwrap().impls.find(&it.def_id) {
Some(v) => {
let mut non_trait = v.iter().filter(|p| {
p.ref0().trait_.is_none()

View file

@ -152,7 +152,8 @@ impl<'a> fold::DocFolder for Stripper<'a> {
clean::ImplItem(clean::Impl{
for_: clean::ResolvedPath{ did, .. }, ..
}) => {
if !self.exported_items.contains(&did.node) {
if ast_util::is_local(did) &&
!self.exported_items.contains(&did.node) {
return None;
}
}