diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index bd911f42db0..236c98b72e6 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -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(), }), diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index f105e14e6e4..470f706e81e 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -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) } diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 0098bcfb4b7..77b12aec97b 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -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 { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 563da5318f7..948d47b2eaf 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -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) } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index ed6c25c7c80..752f193fa3f 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -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(); diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index a4491817479..a0d993dfe7d 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -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) } } diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 6a07b7a906e..5b4a9bd27b7 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -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));