rustdoc: Fill in external trait methods

This commit alters rustdoc to crawl the metadata of upstream libraries in order
to fill in default methods for traits implemented in downstream crates. This,
for example, documents the `insert` function on hash maps.

This is a fairly lossy extraction from the metadata. Documentation and
attributes are lost, but they aren't used anyway. Unfortunately, argument names
are also lost because they are not present in the metadata. Source links are
also lost because the spans are not serialized.

While not perfect, it appears that presenting this documentation through rustdoc
is much better than nothing, so I wanted to land this to allow iteration on it
later on.
This commit is contained in:
Alex Crichton 2014-05-03 02:08:58 -07:00
parent 9411cec580
commit c746c503f0
7 changed files with 433 additions and 104 deletions

View File

@ -25,6 +25,7 @@ use rustc::driver::driver;
use rustc::metadata::cstore;
use rustc::metadata::csearch;
use rustc::metadata::decoder;
use rustc::middle::ty;
use std::strbuf::StrBuf;
@ -128,7 +129,7 @@ pub struct Item {
pub attrs: Vec<Attribute> ,
pub inner: ItemEnum,
pub visibility: Option<Visibility>,
pub id: ast::NodeId,
pub def_id: ast::DefId,
}
impl Item {
@ -274,7 +275,7 @@ impl Clean<Item> for doctree::Module {
attrs: self.attrs.clean(),
source: where.clean(),
visibility: self.vis.clean(),
id: self.id,
def_id: ast_util::local_def(self.id),
inner: ModuleItem(Module {
is_crate: self.is_crate,
items: items.iter()
@ -339,7 +340,7 @@ impl<'a> attr::AttrMetaMethods for &'a Attribute {
#[deriving(Clone, Encodable, Decodable)]
pub struct TyParam {
pub name: StrBuf,
pub id: ast::NodeId,
pub did: ast::DefId,
pub bounds: Vec<TyParamBound>,
}
@ -347,12 +348,25 @@ impl Clean<TyParam> for ast::TyParam {
fn clean(&self) -> TyParam {
TyParam {
name: self.ident.clean(),
id: self.id,
did: ast::DefId { krate: ast::LOCAL_CRATE, node: self.id },
bounds: self.bounds.clean().move_iter().collect(),
}
}
}
impl Clean<TyParam> for ty::TypeParameterDef {
fn clean(&self) -> TyParam {
let cx = super::ctxtkey.get().unwrap();
cx.external_typarams.borrow_mut().get_mut_ref().insert(self.def_id,
self.ident.clean());
TyParam {
name: self.ident.clean(),
did: self.def_id,
bounds: self.bounds.clean(),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub enum TyParamBound {
RegionBound,
@ -369,6 +383,96 @@ impl Clean<TyParamBound> for ast::TyParamBound {
}
}
fn external_path(name: &str) -> Path {
Path {
global: false,
segments: vec![PathSegment {
name: name.to_strbuf(),
lifetimes: Vec::new(),
types: Vec::new(),
}]
}
}
impl Clean<TyParamBound> for ty::BuiltinBound {
fn clean(&self) -> TyParamBound {
let cx = super::ctxtkey.get().unwrap();
let tcx = match cx.maybe_typed {
core::Typed(ref tcx) => tcx,
core::NotTyped(_) => return RegionBound,
};
let (did, path) = match *self {
ty::BoundStatic => return RegionBound,
ty::BoundSend =>
(tcx.lang_items.send_trait().unwrap(), external_path("Send")),
ty::BoundSized =>
(tcx.lang_items.sized_trait().unwrap(), external_path("Sized")),
ty::BoundCopy =>
(tcx.lang_items.copy_trait().unwrap(), external_path("Copy")),
ty::BoundShare =>
(tcx.lang_items.share_trait().unwrap(), external_path("Share")),
};
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, TypeTrait));
TraitBound(ResolvedPath {
path: path,
typarams: None,
did: did,
})
}
}
impl Clean<TyParamBound> for ty::TraitRef {
fn clean(&self) -> TyParamBound {
let cx = super::ctxtkey.get().unwrap();
let tcx = match cx.maybe_typed {
core::Typed(ref tcx) => tcx,
core::NotTyped(_) => return RegionBound,
};
let fqn = csearch::get_item_path(tcx, self.def_id);
let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf())
.collect::<Vec<StrBuf>>();
let path = external_path(fqn.last().unwrap().as_slice());
cx.external_paths.borrow_mut().get_mut_ref().insert(self.def_id,
(fqn, TypeTrait));
TraitBound(ResolvedPath {
path: path,
typarams: None,
did: self.def_id,
})
}
}
impl Clean<Vec<TyParamBound>> for ty::ParamBounds {
fn clean(&self) -> Vec<TyParamBound> {
let mut v = Vec::new();
for b in self.builtin_bounds.iter() {
if b != ty::BoundSized {
v.push(b.clean());
}
}
for t in self.trait_bounds.iter() {
v.push(t.clean());
}
return v;
}
}
impl Clean<Option<Vec<TyParamBound>>> for ty::substs {
fn clean(&self) -> Option<Vec<TyParamBound>> {
let mut v = Vec::new();
match self.regions {
ty::NonerasedRegions(..) => v.push(RegionBound),
ty::ErasedRegions => {}
}
v.extend(self.tps.iter().map(|t| TraitBound(t.clean())));
if v.len() > 0 {Some(v)} else {None}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct Lifetime(StrBuf);
@ -386,6 +490,29 @@ impl Clean<Lifetime> for ast::Lifetime {
}
}
impl Clean<Lifetime> for ty::RegionParameterDef {
fn clean(&self) -> Lifetime {
Lifetime(token::get_name(self.name).get().to_strbuf())
}
}
impl Clean<Option<Lifetime>> for ty::Region {
fn clean(&self) -> Option<Lifetime> {
match *self {
ty::ReStatic => Some(Lifetime("static".to_strbuf())),
ty::ReLateBound(_, ty::BrNamed(_, name)) =>
Some(Lifetime(token::get_name(name).get().to_strbuf())),
ty::ReLateBound(..) |
ty::ReEarlyBound(..) |
ty::ReFree(..) |
ty::ReScope(..) |
ty::ReInfer(..) |
ty::ReEmpty(..) => None
}
}
}
// maybe use a Generic enum and use ~[Generic]?
#[deriving(Clone, Encodable, Decodable)]
pub struct Generics {
@ -402,6 +529,15 @@ impl Clean<Generics> for ast::Generics {
}
}
impl Clean<Generics> for ty::Generics {
fn clean(&self) -> Generics {
Generics {
lifetimes: self.region_param_defs.clean(),
type_params: self.type_param_defs.clean(),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct Method {
pub generics: Generics,
@ -428,11 +564,11 @@ impl Clean<Item> for ast::Method {
name: Some(self.ident.clean()),
attrs: self.attrs.clean().move_iter().collect(),
source: self.span.clean(),
id: self.id.clone(),
def_id: ast_util::local_def(self.id.clone()),
visibility: self.vis.clean(),
inner: MethodItem(Method {
generics: self.generics.clean(),
self_: self.explicit_self.clean(),
self_: self.explicit_self.node.clean(),
fn_style: self.fn_style.clone(),
decl: decl,
}),
@ -466,12 +602,12 @@ impl Clean<Item> for ast::TypeMethod {
name: Some(self.ident.clean()),
attrs: self.attrs.clean().move_iter().collect(),
source: self.span.clean(),
id: self.id,
def_id: ast_util::local_def(self.id),
visibility: None,
inner: TyMethodItem(TyMethod {
fn_style: self.fn_style.clone(),
decl: decl,
self_: self.explicit_self.clean(),
self_: self.explicit_self.node.clean(),
generics: self.generics.clean(),
}),
}
@ -486,9 +622,9 @@ pub enum SelfTy {
SelfOwned,
}
impl Clean<SelfTy> for ast::ExplicitSelf {
impl Clean<SelfTy> for ast::ExplicitSelf_ {
fn clean(&self) -> SelfTy {
match self.node {
match *self {
ast::SelfStatic => SelfStatic,
ast::SelfValue => SelfValue,
ast::SelfUniq => SelfOwned,
@ -511,7 +647,7 @@ impl Clean<Item> for doctree::Function {
attrs: self.attrs.clean(),
source: self.where.clean(),
visibility: self.vis.clean(),
id: self.id,
def_id: ast_util::local_def(self.id),
inner: FunctionItem(Function {
decl: self.decl.clean(),
generics: self.generics.clean(),
@ -533,7 +669,7 @@ pub struct ClosureDecl {
impl Clean<ClosureDecl> for ast::ClosureTy {
fn clean(&self) -> ClosureDecl {
ClosureDecl {
lifetimes: self.lifetimes.clean().move_iter().collect(),
lifetimes: self.lifetimes.clean(),
decl: self.decl.clean(),
onceness: self.onceness,
fn_style: self.fn_style,
@ -571,6 +707,25 @@ impl Clean<FnDecl> for ast::FnDecl {
}
}
impl Clean<FnDecl> for ty::FnSig {
fn clean(&self) -> FnDecl {
FnDecl {
output: self.output.clean(),
cf: Return,
attrs: Vec::new(), // FIXME: this is likely wrong
inputs: Arguments {
values: self.inputs.iter().map(|t| {
Argument {
type_: t.clean(),
id: 0,
name: "".to_strbuf(), // FIXME: where are the names?
}
}).collect(),
},
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub struct Argument {
pub type_: Type,
@ -616,7 +771,7 @@ impl Clean<Item> for doctree::Trait {
name: Some(self.name.clean()),
attrs: self.attrs.clean(),
source: self.where.clean(),
id: self.id,
def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(),
inner: TraitItem(Trait {
methods: self.methods.clean(),
@ -669,6 +824,58 @@ impl Clean<TraitMethod> for ast::TraitMethod {
}
}
impl Clean<TraitMethod> for ty::Method {
fn clean(&self) -> TraitMethod {
let m = if self.provided_source.is_some() {Provided} else {Required};
let cx = super::ctxtkey.get().unwrap();
let tcx = match cx.maybe_typed {
core::Typed(ref tcx) => tcx,
core::NotTyped(_) => fail!(),
};
let mut attrs = Vec::new();
csearch::get_item_attrs(&tcx.sess.cstore, self.def_id, |v| {
attrs.extend(v.move_iter().map(|i| i.clean()));
});
let (self_, sig) = match self.explicit_self {
ast::SelfStatic => (ast::SelfStatic.clean(), self.fty.sig.clone()),
s => {
let sig = ty::FnSig {
inputs: Vec::from_slice(self.fty.sig.inputs.slice_from(1)),
..self.fty.sig.clone()
};
let s = match s {
ast::SelfRegion(..) => {
match ty::get(*self.fty.sig.inputs.get(0)).sty {
ty::ty_rptr(r, mt) => {
SelfBorrowed(r.clean(), mt.mutbl.clean())
}
_ => s.clean(),
}
}
s => s.clean(),
};
(s, sig)
}
};
m(Item {
name: Some(self.ident.clean()),
visibility: Some(ast::Inherited),
def_id: self.def_id,
attrs: attrs,
source: Span {
filename: "".to_strbuf(),
loline: 0, locol: 0, hiline: 0, hicol: 0,
},
inner: TyMethodItem(TyMethod {
fn_style: self.fty.fn_style,
generics: self.generics.clean(),
self_: self_,
decl: sig.clean(),
})
})
}
}
/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
/// type out of the AST/ty::ctxt given one of these, if more information is needed. Most importantly
/// it does not preserve mutability or boxes.
@ -684,9 +891,9 @@ pub enum Type {
TyParamBinder(ast::NodeId),
/// For parameterized types, so the consumer of the JSON don't go looking
/// for types which don't exist anywhere.
Generic(ast::NodeId),
Generic(ast::DefId),
/// For references to self
Self(ast::NodeId),
Self(ast::DefId),
/// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
Primitive(ast::PrimTy),
Closure(Box<ClosureDecl>, Option<Lifetime>),
@ -753,6 +960,93 @@ impl Clean<Type> for ast::Ty {
}
}
impl Clean<Type> for ty::t {
fn clean(&self) -> Type {
match ty::get(*self).sty {
ty::ty_nil => Unit,
ty::ty_bot => Bottom,
ty::ty_bool => Bool,
ty::ty_char => Primitive(ast::TyChar),
ty::ty_int(t) => Primitive(ast::TyInt(t)),
ty::ty_uint(u) => Primitive(ast::TyUint(u)),
ty::ty_float(f) => Primitive(ast::TyFloat(f)),
ty::ty_box(t) => Managed(box t.clean()),
ty::ty_uniq(t) => Unique(box t.clean()),
ty::ty_str => String,
ty::ty_vec(mt, None) => Vector(box mt.ty.clean()),
ty::ty_vec(mt, Some(i)) => FixedVector(box mt.ty.clean(),
format_strbuf!("{}", i)),
ty::ty_ptr(mt) => RawPointer(mt.mutbl.clean(), box mt.ty.clean()),
ty::ty_rptr(r, mt) => BorrowedRef {
lifetime: r.clean(),
mutability: mt.mutbl.clean(),
type_: box mt.ty.clean(),
},
ty::ty_bare_fn(ref fty) => BareFunction(box BareFunctionDecl {
fn_style: fty.fn_style,
generics: Generics {
lifetimes: Vec::new(), type_params: Vec::new()
},
decl: fty.sig.clean(),
abi: fty.abi.to_str().to_strbuf(),
}),
ty::ty_closure(ref fty) => {
let decl = box ClosureDecl {
lifetimes: Vec::new(), // FIXME: this looks wrong...
decl: fty.sig.clean(),
onceness: fty.onceness,
fn_style: fty.fn_style,
bounds: fty.bounds.iter().map(|i| i.clean()).collect(),
};
match fty.store {
ty::UniqTraitStore => Proc(decl),
ty::RegionTraitStore(ref r, _) => Closure(decl, r.clean()),
}
}
ty::ty_struct(did, ref substs) |
ty::ty_enum(did, ref substs) |
ty::ty_trait(box ty::TyTrait { def_id: did, ref substs, .. }) => {
let cx = super::ctxtkey.get().unwrap();
let tcx = match cx.maybe_typed {
core::Typed(ref tycx) => tycx,
core::NotTyped(_) => fail!(),
};
let fqn = csearch::get_item_path(tcx, did);
let fqn: Vec<StrBuf> = fqn.move_iter().map(|i| {
i.to_str().to_strbuf()
}).collect();
let mut path = external_path(fqn.last().unwrap().to_str());
let kind = match ty::get(*self).sty {
ty::ty_struct(..) => TypeStruct,
ty::ty_trait(..) => TypeTrait,
_ => TypeEnum,
};
path.segments.get_mut(0).lifetimes = match substs.regions {
ty::ErasedRegions => Vec::new(),
ty::NonerasedRegions(ref v) => {
v.iter().filter_map(|v| v.clean()).collect()
}
};
path.segments.get_mut(0).types = substs.tps.clean();
cx.external_paths.borrow_mut().get_mut_ref().insert(did,
(fqn, kind));
ResolvedPath {
path: path,
typarams: None,
did: did,
}
}
ty::ty_tup(ref t) => Tuple(t.iter().map(|t| t.clean()).collect()),
ty::ty_param(ref p) => Generic(p.def_id),
ty::ty_self(did) => Self(did),
ty::ty_infer(..) => fail!("ty_infer"),
ty::ty_err => fail!("ty_err"),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub enum StructField {
HiddenStructField, // inserted later by strip passes
@ -770,7 +1064,7 @@ impl Clean<Item> for ast::StructField {
attrs: self.node.attrs.clean().move_iter().collect(),
source: self.span.clean(),
visibility: Some(vis),
id: self.node.id,
def_id: ast_util::local_def(self.node.id),
inner: StructFieldItem(TypedStructField(self.node.ty.clean())),
}
}
@ -798,7 +1092,7 @@ impl Clean<Item> for doctree::Struct {
name: Some(self.name.clean()),
attrs: self.attrs.clean(),
source: self.where.clean(),
id: self.id,
def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(),
inner: StructItem(Struct {
struct_type: self.struct_type,
@ -843,7 +1137,7 @@ impl Clean<Item> for doctree::Enum {
name: Some(self.name.clean()),
attrs: self.attrs.clean(),
source: self.where.clean(),
id: self.id,
def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(),
inner: EnumItem(Enum {
variants: self.variants.clean(),
@ -866,7 +1160,7 @@ impl Clean<Item> for doctree::Variant {
attrs: self.attrs.clean(),
source: self.where.clean(),
visibility: self.vis.clean(),
id: self.id,
def_id: ast_util::local_def(self.id),
inner: VariantItem(Variant {
kind: self.kind.clean(),
}),
@ -988,7 +1282,7 @@ impl Clean<Item> for doctree::Typedef {
name: Some(self.name.clean()),
attrs: self.attrs.clean(),
source: self.where.clean(),
id: self.id.clone(),
def_id: ast_util::local_def(self.id.clone()),
visibility: self.vis.clean(),
inner: TypedefItem(Typedef {
type_: self.ty.clean(),
@ -1037,7 +1331,7 @@ impl Clean<Item> for doctree::Static {
name: Some(self.name.clean()),
attrs: self.attrs.clean(),
source: self.where.clean(),
id: self.id,
def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(),
inner: StaticItem(Static {
type_: self.type_.clean(),
@ -1089,7 +1383,7 @@ impl Clean<Item> for doctree::Impl {
name: None,
attrs: self.attrs.clean(),
source: self.where.clean(),
id: self.id,
def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(),
inner: ImplItem(Impl {
generics: self.generics.clean(),
@ -1113,7 +1407,7 @@ impl Clean<Item> for ast::ViewItem {
name: None,
attrs: self.attrs.clean().move_iter().collect(),
source: self.span.clean(),
id: 0,
def_id: ast_util::local_def(0),
visibility: self.vis.clean(),
inner: ViewItemItem(ViewItem {
inner: self.node.clean()
@ -1219,7 +1513,7 @@ impl Clean<Item> for ast::ForeignItem {
name: Some(self.ident.clean()),
attrs: self.attrs.clean().move_iter().collect(),
source: self.span.clean(),
id: self.id,
def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(),
inner: inner,
}
@ -1288,7 +1582,7 @@ fn name_from_pat(p: &ast::Pat) -> StrBuf {
}
/// Given a Type, resolve it using the def_map
fn resolve_type(path: Path, tpbs: Option<Vec<TyParamBound> >,
fn resolve_type(path: Path, tpbs: Option<Vec<TyParamBound>>,
id: ast::NodeId) -> Type {
let cx = super::ctxtkey.get().unwrap();
let tycx = match cx.maybe_typed {
@ -1303,13 +1597,13 @@ fn resolve_type(path: Path, tpbs: Option<Vec<TyParamBound> >,
};
match def {
ast::DefSelfTy(i) => return Self(i),
ast::DefSelfTy(i) => return Self(ast_util::local_def(i)),
ast::DefPrimTy(p) => match p {
ast::TyStr => return String,
ast::TyBool => return Bool,
_ => return Primitive(p)
},
ast::DefTyParam(i, _) => return Generic(i.node),
ast::DefTyParam(i, _) => return Generic(i),
ast::DefTyParamBinder(i) => return TyParamBinder(i),
_ => {}
};
@ -1337,9 +1631,26 @@ fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId {
let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()).collect();
debug!("recording {} => {}", did, fqn);
cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind));
match kind {
TypeTrait => {
let t = build_external_trait(tcx, did);
cx.external_traits.borrow_mut().get_mut_ref().insert(did, t);
}
_ => {}
}
return did;
}
fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> Trait {
let def = csearch::get_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 resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
ImportSource {
path: path,
@ -1369,7 +1680,7 @@ impl Clean<Item> for doctree::Macro {
attrs: self.attrs.clean(),
source: self.where.clean(),
visibility: ast::Public.clean(),
id: self.id,
def_id: ast_util::local_def(self.id),
inner: MacroItem(Macro {
source: self.where.to_src(),
}),

View File

@ -20,7 +20,7 @@ use syntax;
use std::cell::RefCell;
use std::os;
use collections::{HashSet, HashMap};
use collections::{HashMap, HashSet};
use visit_ast::RustdocVisitor;
use clean;
@ -39,6 +39,8 @@ pub struct DocContext {
pub maybe_typed: MaybeTyped,
pub src: Path,
pub external_paths: ExternalPaths,
pub external_traits: RefCell<Option<HashMap<ast::DefId, clean::Trait>>>,
pub external_typarams: RefCell<Option<HashMap<ast::DefId, StrBuf>>>,
}
impl DocContext {
@ -54,6 +56,8 @@ pub struct CrateAnalysis {
pub exported_items: privacy::ExportedItems,
pub public_items: privacy::PublicItems,
pub external_paths: ExternalPaths,
pub external_traits: RefCell<Option<HashMap<ast::DefId, clean::Trait>>>,
pub external_typarams: RefCell<Option<HashMap<ast::DefId, StrBuf>>>,
}
/// Parses, resolves, and typechecks the given crate
@ -104,11 +108,15 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<StrBuf>)
krate: krate,
maybe_typed: Typed(ty_cx),
src: cpath.clone(),
external_traits: RefCell::new(Some(HashMap::new())),
external_typarams: RefCell::new(Some(HashMap::new())),
external_paths: RefCell::new(Some(HashMap::new())),
}, CrateAnalysis {
exported_items: exported_items,
public_items: public_items,
external_paths: RefCell::new(None),
external_traits: RefCell::new(None),
external_typarams: RefCell::new(None),
})
}
@ -126,5 +134,9 @@ pub fn run_core(libs: HashSet<Path>, cfgs: Vec<StrBuf>, path: &Path)
let external_paths = ctxt.external_paths.borrow_mut().take();
*analysis.external_paths.borrow_mut() = external_paths;
let map = ctxt.external_traits.borrow_mut().take();
*analysis.external_traits.borrow_mut() = map;
let map = ctxt.external_typarams.borrow_mut().take();
*analysis.external_typarams.borrow_mut() = map;
(krate, analysis)
}

View File

@ -19,7 +19,7 @@ pub trait DocFolder {
/// don't override!
fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
let Item { attrs, name, source, visibility, id, inner } = item;
let Item { attrs, name, source, visibility, def_id, inner } = item;
let inner = inner;
let inner = match inner {
StructItem(mut i) => {
@ -83,7 +83,7 @@ pub trait DocFolder {
};
Some(Item { attrs: attrs, name: name, source: source, inner: inner,
visibility: visibility, id: id })
visibility: visibility, def_id: def_id })
}
fn fold_mod(&mut self, m: Module) -> Module {

View File

@ -284,11 +284,15 @@ fn tybounds(w: &mut fmt::Formatter,
impl fmt::Show for clean::Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
clean::TyParamBinder(id) | clean::Generic(id) => {
clean::TyParamBinder(id) => {
let m = cache_key.get().unwrap();
f.write(m.typarams.get(&id).as_bytes())
f.write(m.typarams.get(&ast_util::local_def(id)).as_bytes())
}
clean::ResolvedPath{ did, ref typarams, ref path} => {
clean::Generic(did) => {
let m = cache_key.get().unwrap();
f.write(m.typarams.get(&did).as_bytes())
}
clean::ResolvedPath{ did, ref typarams, ref path } => {
try!(resolved_path(f, did, path, false));
tybounds(f, typarams)
}

View File

@ -85,7 +85,7 @@ pub struct Context {
/// functions), and the value is the list of containers belonging to this
/// header. This map will change depending on the surrounding context of the
/// page.
pub sidebar: HashMap<StrBuf, Vec<StrBuf> >,
pub sidebar: HashMap<StrBuf, Vec<StrBuf>>,
/// This flag indicates whether [src] links should be generated or not. If
/// the source files are present in the html rendering, then this will be
/// `true`.
@ -124,7 +124,7 @@ pub struct Cache {
/// Mapping of typaram ids to the name of the type parameter. This is used
/// when pretty-printing a type (so pretty printing doesn't have to
/// painfully maintain a context like this)
pub typarams: HashMap<ast::NodeId, StrBuf>,
pub typarams: HashMap<ast::DefId, StrBuf>,
/// Maps a type id to all known implementations for that type. This is only
/// recognized for intra-crate `ResolvedPath` types, and is used to print
@ -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<StrBuf>)> >,
pub impls: HashMap<ast::NodeId, Vec<(clean::Impl, Option<StrBuf>)>>,
/// 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
@ -145,15 +145,12 @@ pub struct Cache {
/// Implementations of a crate should inherit the documentation of the
/// parent trait if no extra documentation is specified, and default methods
/// should show up in documentation about trait implementations.
pub traits: HashMap<ast::NodeId, clean::Trait>,
pub traits: HashMap<ast::DefId, clean::Trait>,
/// When rendering traits, it's often useful to be able to list all
/// implementors of the trait, and this mapping is exactly, that: a mapping
/// of trait ids to the list of known implementors of the trait
pub implementors: HashMap<ast::NodeId, Vec<Implementor>>,
/// Implementations of external traits, keyed by the external trait def id.
pub foreign_implementors: HashMap<ast::DefId, Vec<Implementor>>,
pub implementors: HashMap<ast::DefId, Vec<Implementor>>,
/// Cache of where external crate documentation can be found.
pub extern_locations: HashMap<ast::CrateNum, ExternalLocation>,
@ -251,6 +248,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
// Crawl the crate to build various caches used for the output
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 = analysis.as_ref().map(|a| {
let paths = a.external_paths.borrow_mut().take_unwrap();
paths.move_iter().map(|(k, (v, t))| {
@ -267,18 +265,21 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
}).unwrap_or(HashMap::new());
let mut cache = Cache {
impls: HashMap::new(),
typarams: HashMap::new(),
paths: paths,
traits: HashMap::new(),
implementors: HashMap::new(),
foreign_implementors: HashMap::new(),
stack: Vec::new(),
parent_stack: Vec::new(),
search_index: Vec::new(),
extern_locations: HashMap::new(),
privmod: false,
public_items: public_items.unwrap_or(NodeSet::new()),
public_items: public_items,
orphan_methods: Vec::new(),
traits: analysis.as_ref().map(|a| {
a.external_traits.borrow_mut().take_unwrap()
}).unwrap_or(HashMap::new()),
typarams: analysis.as_ref().map(|a| {
a.external_typarams.borrow_mut().take_unwrap()
}).unwrap_or(HashMap::new()),
};
cache.stack.push(krate.name.clone());
krate = cache.fold_crate(krate);
@ -431,7 +432,8 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
// Update the list of all implementors for traits
let dst = cx.dst.join("implementors");
try!(mkdir(&dst));
for (&did, imps) in cache.foreign_implementors.iter() {
for (&did, imps) in cache.implementors.iter() {
if ast_util::is_local(did) { continue }
let &(ref remote_path, remote_item_type) = cache.paths.get(&did);
let mut mydst = dst.clone();
@ -686,7 +688,7 @@ impl DocFolder for Cache {
// trait
match item.inner {
clean::TraitItem(ref t) => {
self.traits.insert(item.id, t.clone());
self.traits.insert(item.def_id, t.clone());
}
_ => {}
}
@ -695,15 +697,10 @@ impl DocFolder for Cache {
match item.inner {
clean::ImplItem(ref i) => {
match i.trait_ {
// FIXME: this is_local() check seems to be losing
// information
Some(clean::ResolvedPath{ did, .. }) => {
let v = if ast_util::is_local(did) {
self.implementors.find_or_insert(did.node, Vec::new())
} else {
self.foreign_implementors.find_or_insert(did,
Vec::new())
};
let v = self.implementors.find_or_insert_with(did, |_| {
Vec::new()
});
match i.for_ {
clean::ResolvedPath{..} => {
v.unshift(PathType(i.for_.clone()));
@ -789,16 +786,19 @@ impl DocFolder for Cache {
clean::TypedefItem(..) | clean::TraitItem(..) |
clean::FunctionItem(..) | clean::ModuleItem(..) |
clean::ForeignFunctionItem(..) => {
// Reexported items mean that the same id can show up twice in
// the rustdoc ast that we're looking at. We know, however, that
// a reexported item doesn't show up in the `public_items` map,
// so we can skip inserting into the paths map if there was
// already an entry present and we're not a public item.
let did = ast_util::local_def(item.id);
if !self.paths.contains_key(&did) ||
self.public_items.contains(&item.id) {
self.paths.insert(did, (self.stack.clone(),
shortty(&item)));
if ast_util::is_local(item.def_id) {
// Reexported items mean that the same id can show up twice
// in the rustdoc ast that we're looking at. We know,
// however, that a reexported item doesn't show up in the
// `public_items` map, so we can skip inserting into the
// paths map if there was already an entry present and we're
// not a public item.
let id = item.def_id.node;
if !self.paths.contains_key(&item.def_id) ||
self.public_items.contains(&id) {
self.paths.insert(item.def_id,
(self.stack.clone(), shortty(&item)));
}
}
}
// link variants to their parent enum because pages aren't emitted
@ -806,8 +806,7 @@ impl DocFolder for Cache {
clean::VariantItem(..) => {
let mut stack = self.stack.clone();
stack.pop();
self.paths.insert(ast_util::local_def(item.id),
(stack, item_type::Enum));
self.paths.insert(item.def_id, (stack, item_type::Enum));
}
_ => {}
}
@ -815,7 +814,10 @@ impl DocFolder for Cache {
// Maintain the parent stack
let parent_pushed = match item.inner {
clean::TraitItem(..) | clean::EnumItem(..) | clean::StructItem(..) => {
self.parent_stack.push(item.id); true
if ast_util::is_local(item.def_id) {
self.parent_stack.push(item.def_id.node);
}
true
}
clean::ImplItem(ref i) => {
match i.for_ {
@ -893,7 +895,7 @@ impl DocFolder for Cache {
impl<'a> Cache {
fn generics(&mut self, generics: &clean::Generics) {
for typ in generics.type_params.iter() {
self.typarams.insert(typ.id, typ.name.clone());
self.typarams.insert(typ.did, typ.name.clone());
}
}
}
@ -1411,7 +1413,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
try!(write!(w, "</div>"));
}
match cache_key.get().unwrap().implementors.find(&it.id) {
match cache_key.get().unwrap().implementors.find(&it.def_id) {
Some(implementors) => {
try!(write!(w, "
<h2 id='implementors'>Implementors</h2>
@ -1667,7 +1669,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.id) {
match cache_key.get().unwrap().impls.find(&it.def_id.node) {
Some(v) => {
let mut non_trait = v.iter().filter(|p| {
p.ref0().trait_.is_none()
@ -1714,16 +1716,10 @@ fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
fn render_impl(w: &mut fmt::Formatter, i: &clean::Impl,
dox: &Option<StrBuf>) -> fmt::Result {
try!(write!(w, "<h3 class='impl'><code>impl{} ", i.generics));
let trait_id = match i.trait_ {
Some(ref ty) => {
try!(write!(w, "{} for ", *ty));
match *ty {
clean::ResolvedPath { did, .. } => Some(did),
_ => None,
}
}
None => None
};
match i.trait_ {
Some(ref ty) => try!(write!(w, "{} for ", *ty)),
None => {}
}
try!(write!(w, "{}</code></h3>", i.for_));
match *dox {
Some(ref dox) => {
@ -1753,31 +1749,34 @@ fn render_impl(w: &mut fmt::Formatter, i: &clean::Impl,
try!(docmeth(w, meth, true));
}
fn render_default_methods(w: &mut fmt::Formatter,
t: &clean::Trait,
i: &clean::Impl) -> fmt::Result {
for method in t.methods.iter() {
let n = method.item().name.clone();
match i.methods.iter().find(|m| { m.name == n }) {
Some(..) => continue,
None => {}
}
try!(docmeth(w, method.item(), false));
}
Ok(())
}
// If we've implemented a trait, then also emit documentation for all
// default methods which weren't overridden in the implementation block.
match trait_id {
None => {}
// FIXME: this should work for non-local traits
Some(did) if ast_util::is_local(did) => {
match i.trait_ {
Some(clean::ResolvedPath { did, .. }) => {
try!({
match cache_key.get().unwrap().traits.find(&did.node) {
Some(t) => {
for method in t.methods.iter() {
let n = method.item().name.clone();
match i.methods.iter().find(|m| m.name == n) {
Some(..) => continue,
None => {}
}
try!(docmeth(w, method.item(), false));
}
}
match cache_key.get().unwrap().traits.find(&did) {
Some(t) => try!(render_default_methods(w, t, i)),
None => {}
}
Ok(())
})
}
Some(..) => {}
Some(..) | None => {}
}
try!(write!(w, "</div>"));
Ok(())
@ -1849,7 +1848,7 @@ impl<'a> fmt::Show for Sidebar<'a> {
}
}
fn build_sidebar(m: &clean::Module) -> HashMap<StrBuf, Vec<StrBuf> > {
fn build_sidebar(m: &clean::Module) -> HashMap<StrBuf, Vec<StrBuf>> {
let mut map = HashMap::new();
for item in m.items.iter() {
let short = shortty(item).to_static_str();

View File

@ -35,7 +35,7 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
fn fold_item(&mut self, i: Item) -> Option<Item> {
if i.is_hidden_from_doc() {
debug!("found one in strip_hidden; removing");
self.stripped.insert(i.id);
self.stripped.insert(i.def_id.node);
// use a dedicated hidden item for given item type if any
match i.inner {
@ -124,7 +124,8 @@ impl<'a> fold::DocFolder for Stripper<'a> {
clean::TraitItem(..) | clean::FunctionItem(..) |
clean::VariantItem(..) | clean::MethodItem(..) |
clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) => {
if !self.exported_items.contains(&i.id) {
if ast_util::is_local(i.def_id) &&
!self.exported_items.contains(&i.def_id.node) {
return None;
}
}
@ -173,7 +174,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
};
let i = if fastreturn {
self.retained.insert(i.id);
self.retained.insert(i.def_id.node);
return Some(i);
} else {
self.fold_item_recur(i)
@ -188,7 +189,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
i.doc_value().is_none() => None,
clean::ImplItem(ref i) if i.methods.len() == 0 => None,
_ => {
self.retained.insert(i.id);
self.retained.insert(i.def_id.node);
Some(i)
}
}

View File

@ -76,6 +76,8 @@ pub fn run(input: &str,
maybe_typed: core::NotTyped(sess),
src: input_path,
external_paths: RefCell::new(Some(HashMap::new())),
external_traits: RefCell::new(None),
external_typarams: RefCell::new(None),
};
super::ctxtkey.replace(Some(ctx));