auto merge of #15263 : aturon/rust/rustdoc-stability-index, r=alexcrichton

This commit hooks rustdoc into the stability index infrastructure in two
ways:

1. It looks up stability levels via the index, rather than by manual
attributes.

2. It adds stability level information throughout rustdoc output, rather
than just at the top header. In particular, a stability color (with
mouseover text) appears next to essentially every item that appears
in rustdoc's HTML output.

Along the way, the stability index code has been lightly refactored.
This commit is contained in:
bors 2014-07-01 06:31:35 +00:00
commit 721b4cb5c5
12 changed files with 284 additions and 174 deletions

View File

@ -30,7 +30,7 @@ use middle::def::*;
use middle::trans::adt; // for `adt::is_ffi_safe` use middle::trans::adt; // for `adt::is_ffi_safe`
use middle::typeck::astconv::ast_ty_to_ty; use middle::typeck::astconv::ast_ty_to_ty;
use middle::typeck::infer; use middle::typeck::infer;
use middle::{typeck, ty, def, pat_util}; use middle::{typeck, ty, def, pat_util, stability};
use util::ppaux::{ty_to_str}; use util::ppaux::{ty_to_str};
use util::nodemap::NodeSet; use util::nodemap::NodeSet;
use lint::{Context, LintPass, LintArray}; use lint::{Context, LintPass, LintArray};
@ -1426,11 +1426,7 @@ impl LintPass for Stability {
Some(method) => { Some(method) => {
match method.origin { match method.origin {
typeck::MethodStatic(def_id) => { typeck::MethodStatic(def_id) => {
// If this implements a trait method, get def_id def_id
// of the method inside trait definition.
// Otherwise, use the current def_id (which refers
// to the method inside impl).
ty::trait_method_of_method(cx.tcx, def_id).unwrap_or(def_id)
} }
typeck::MethodParam(typeck::MethodParam { typeck::MethodParam(typeck::MethodParam {
trait_id: trait_id, trait_id: trait_id,
@ -1454,8 +1450,7 @@ impl LintPass for Stability {
// check anything for crate-local usage. // check anything for crate-local usage.
if ast_util::is_local(id) { return } if ast_util::is_local(id) { return }
let stability = cx.tcx.stability.borrow_mut().lookup(&cx.tcx.sess.cstore, id); let stability = stability::lookup(cx.tcx, id);
let (lint, label) = match stability { let (lint, label) = match stability {
// no stability attributes == Unstable // no stability attributes == Unstable
None => (UNSTABLE, "unmarked"), None => (UNSTABLE, "unmarked"),

View File

@ -24,6 +24,7 @@ use middle::ty::{node_id_to_type, lookup_item_type};
use middle::astencode; use middle::astencode;
use middle::ty; use middle::ty;
use middle::typeck; use middle::typeck;
use middle::stability;
use middle; use middle;
use util::nodemap::{NodeMap, NodeSet}; use util::nodemap::{NodeMap, NodeSet};
@ -328,7 +329,7 @@ fn encode_enum_variant_info(ecx: &EncodeContext,
encode_visibility(ebml_w, variant.node.vis); encode_visibility(ebml_w, variant.node.vis);
encode_attributes(ebml_w, variant.node.attrs.as_slice()); encode_attributes(ebml_w, variant.node.attrs.as_slice());
let stab = ecx.tcx.stability.borrow().lookup_local(variant.node.id); let stab = stability::lookup(ecx.tcx, ast_util::local_def(variant.node.id));
encode_stability(ebml_w, stab); encode_stability(ebml_w, stab);
match variant.node.kind { match variant.node.kind {
@ -592,7 +593,9 @@ fn encode_info_for_mod(ecx: &EncodeContext,
encode_path(ebml_w, path.clone()); encode_path(ebml_w, path.clone());
encode_visibility(ebml_w, vis); encode_visibility(ebml_w, vis);
encode_stability(ebml_w, ecx.tcx.stability.borrow().lookup_local(id));
let stab = stability::lookup(ecx.tcx, ast_util::local_def(id));
encode_stability(ebml_w, stab);
// Encode the reexports of this module, if this module is public. // Encode the reexports of this module, if this module is public.
if vis == Public { if vis == Public {
@ -722,7 +725,8 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext,
encode_symbol(ecx, ebml_w, ctor_id); encode_symbol(ecx, ebml_w, ctor_id);
} }
encode_stability(ebml_w, ecx.tcx.stability.borrow().lookup_local(ctor_id)); let stab = stability::lookup(ecx.tcx, ast_util::local_def(ctor_id));
encode_stability(ebml_w, stab);
// indicate that this is a tuple struct ctor, because downstream users will normally want // indicate that this is a tuple struct ctor, because downstream users will normally want
// the tuple struct definition, but without this there is no way for them to tell that // the tuple struct definition, but without this there is no way for them to tell that
@ -768,7 +772,7 @@ fn encode_info_for_method(ecx: &EncodeContext,
encode_method_ty_fields(ecx, ebml_w, m); encode_method_ty_fields(ecx, ebml_w, m);
encode_parent_item(ebml_w, local_def(parent_id)); encode_parent_item(ebml_w, local_def(parent_id));
let stab = ecx.tcx.stability.borrow().lookup_local(m.def_id.node); let stab = stability::lookup(ecx.tcx, m.def_id);
encode_stability(ebml_w, stab); encode_stability(ebml_w, stab);
// The type for methods gets encoded twice, which is unfortunate. // The type for methods gets encoded twice, which is unfortunate.
@ -915,10 +919,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
} }
debug!("encoding info for item at {}", debug!("encoding info for item at {}",
ecx.tcx.sess.codemap().span_to_str(item.span)); tcx.sess.codemap().span_to_str(item.span));
let def_id = local_def(item.id); let def_id = local_def(item.id);
let stab = tcx.stability.borrow().lookup_local(item.id); let stab = stability::lookup(tcx, ast_util::local_def(item.id));
match item.node { match item.node {
ItemStatic(_, m, _) => { ItemStatic(_, m, _) => {
@ -1206,7 +1210,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_method_ty_fields(ecx, ebml_w, &*method_ty); encode_method_ty_fields(ecx, ebml_w, &*method_ty);
encode_parent_item(ebml_w, def_id); encode_parent_item(ebml_w, def_id);
let stab = tcx.stability.borrow().lookup_local(method_def_id.node); let stab = stability::lookup(tcx, method_def_id);
encode_stability(ebml_w, stab); encode_stability(ebml_w, stab);
let elem = ast_map::PathName(method_ty.ident.name); let elem = ast_map::PathName(method_ty.ident.name);

View File

@ -20,7 +20,8 @@ use syntax::ast::{Generics, StructDef, Ident};
use syntax::ast_util::is_local; use syntax::ast_util::is_local;
use syntax::attr::Stability; use syntax::attr::Stability;
use syntax::visit::{FnKind, FkMethod, Visitor}; use syntax::visit::{FnKind, FkMethod, Visitor};
use metadata::{cstore, csearch}; use middle::ty;
use metadata::csearch;
/// A stability index, giving the stability level for items and methods. /// A stability index, giving the stability level for items and methods.
pub struct Index { pub struct Index {
@ -105,21 +106,24 @@ impl Index {
attr::find_stability(krate.attrs.as_slice())); attr::find_stability(krate.attrs.as_slice()));
annotator.index annotator.index
} }
}
/// Lookup the stability for a node, loading external crate /// Lookup the stability for a node, loading external crate
/// metadata as necessary. /// metadata as necessary.
pub fn lookup(&mut self, cstore: &cstore::CStore, id: DefId) -> Option<Stability> { pub fn lookup(tcx: &ty::ctxt, id: DefId) -> Option<Stability> {
if is_local(id) { // is this definition the implementation of a trait method?
self.lookup_local(id.node) match ty::trait_method_of_method(tcx, id) {
} else { Some(trait_method_id) if trait_method_id != id => {
let stab = csearch::get_stability(cstore, id); lookup(tcx, trait_method_id)
self.extern_cache.insert(id, stab.clone()); }
_ if is_local(id) => {
tcx.stability.borrow().local.find_copy(&id.node)
}
_ => {
let stab = csearch::get_stability(&tcx.sess.cstore, id);
let mut index = tcx.stability.borrow_mut();
(*index).extern_cache.insert(id, stab.clone());
stab stab
} }
} }
/// Lookup the stability for a local node without loading any external crates
pub fn lookup_local(&self, id: NodeId) -> Option<Stability> {
self.local.find_copy(&id)
}
} }

View File

@ -18,6 +18,7 @@ use rustc::metadata::csearch;
use rustc::metadata::decoder; use rustc::metadata::decoder;
use rustc::middle::def; use rustc::middle::def;
use rustc::middle::ty; use rustc::middle::ty;
use rustc::middle::stability;
use core; use core;
use doctree; use doctree;
@ -102,6 +103,7 @@ fn try_inline_def(cx: &core::DocContext,
attrs: load_attrs(tcx, did), attrs: load_attrs(tcx, did),
inner: inner, inner: inner,
visibility: Some(ast::Public), visibility: Some(ast::Public),
stability: stability::lookup(tcx, did).clean(),
def_id: did, def_id: did,
}); });
Some(ret) Some(ret)
@ -317,6 +319,7 @@ fn build_impl(cx: &core::DocContext,
name: None, name: None,
attrs: attrs, attrs: attrs,
visibility: Some(ast::Inherited), visibility: Some(ast::Inherited),
stability: stability::lookup(tcx, did).clean(),
def_id: did, def_id: did,
}) })
} }

View File

@ -29,6 +29,7 @@ use rustc::middle::def;
use rustc::middle::subst; use rustc::middle::subst;
use rustc::middle::subst::VecPerParamSpace; use rustc::middle::subst::VecPerParamSpace;
use rustc::middle::ty; use rustc::middle::ty;
use rustc::middle::stability;
use std::rc::Rc; use std::rc::Rc;
use std::u32; use std::u32;
@ -44,6 +45,17 @@ pub static SCHEMA_VERSION: &'static str = "0.8.3";
mod inline; mod inline;
// load the current DocContext from TLD
fn get_cx() -> Gc<core::DocContext> {
*super::ctxtkey.get().unwrap()
}
// extract the stability index for a node from TLD, if possible
fn get_stability(def_id: ast::DefId) -> Option<Stability> {
get_cx().tcx_opt().and_then(|tcx| stability::lookup(tcx, def_id))
.map(|stab| stab.clean())
}
pub trait Clean<T> { pub trait Clean<T> {
fn clean(&self) -> T; fn clean(&self) -> T;
} }
@ -97,7 +109,7 @@ pub struct Crate {
impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> { impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
fn clean(&self) -> Crate { fn clean(&self) -> Crate {
let cx = super::ctxtkey.get().unwrap(); let cx = get_cx();
let mut externs = Vec::new(); let mut externs = Vec::new();
cx.sess().cstore.iter_crate_data(|n, meta| { cx.sess().cstore.iter_crate_data(|n, meta| {
@ -158,6 +170,7 @@ impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
name: Some(prim.to_url_str().to_string()), name: Some(prim.to_url_str().to_string()),
attrs: Vec::new(), attrs: Vec::new(),
visibility: None, visibility: None,
stability: None,
def_id: ast_util::local_def(prim.to_node_id()), def_id: ast_util::local_def(prim.to_node_id()),
inner: PrimitiveItem(prim), inner: PrimitiveItem(prim),
}; };
@ -193,25 +206,18 @@ pub struct ExternalCrate {
impl Clean<ExternalCrate> for cstore::crate_metadata { impl Clean<ExternalCrate> for cstore::crate_metadata {
fn clean(&self) -> ExternalCrate { fn clean(&self) -> ExternalCrate {
let mut primitives = Vec::new(); let mut primitives = Vec::new();
let cx = super::ctxtkey.get().unwrap(); get_cx().tcx_opt().map(|tcx| {
match cx.maybe_typed { csearch::each_top_level_item_of_crate(&tcx.sess.cstore,
core::Typed(ref tcx) => { self.cnum,
csearch::each_top_level_item_of_crate(&tcx.sess.cstore, |def, _, _| {
self.cnum, let did = match def {
|def, _, _| { decoder::DlDef(def::DefMod(did)) => did,
let did = match def { _ => return
decoder::DlDef(def::DefMod(did)) => did, };
_ => return let attrs = inline::load_attrs(tcx, did);
}; Primitive::find(attrs.as_slice()).map(|prim| primitives.push(prim));
let attrs = inline::load_attrs(tcx, did); })
match Primitive::find(attrs.as_slice()) { });
Some(prim) => primitives.push(prim),
None => {}
}
});
}
core::NotTyped(..) => {}
}
ExternalCrate { ExternalCrate {
name: self.name.to_string(), name: self.name.to_string(),
attrs: decoder::get_crate_attributes(self.data()).clean(), attrs: decoder::get_crate_attributes(self.data()).clean(),
@ -233,6 +239,7 @@ pub struct Item {
pub inner: ItemEnum, pub inner: ItemEnum,
pub visibility: Option<Visibility>, pub visibility: Option<Visibility>,
pub def_id: ast::DefId, pub def_id: ast::DefId,
pub stability: Option<Stability>,
} }
impl Item { impl Item {
@ -380,6 +387,7 @@ impl Clean<Item> for doctree::Module {
attrs: self.attrs.clean(), attrs: self.attrs.clean(),
source: where.clean(), source: where.clean(),
visibility: self.vis.clean(), visibility: self.vis.clean(),
stability: self.stab.clean(),
def_id: ast_util::local_def(self.id), def_id: ast_util::local_def(self.id),
inner: ModuleItem(Module { inner: ModuleItem(Module {
is_crate: self.is_crate, is_crate: self.is_crate,
@ -465,9 +473,8 @@ impl Clean<TyParam> for ast::TyParam {
impl Clean<TyParam> for ty::TypeParameterDef { impl Clean<TyParam> for ty::TypeParameterDef {
fn clean(&self) -> TyParam { fn clean(&self) -> TyParam {
let cx = super::ctxtkey.get().unwrap(); get_cx().external_typarams.borrow_mut().get_mut_ref()
cx.external_typarams.borrow_mut().get_mut_ref().insert(self.def_id, .insert(self.def_id, self.ident.clean());
self.ident.clean());
TyParam { TyParam {
name: self.ident.clean(), name: self.ident.clean(),
did: self.def_id, did: self.def_id,
@ -515,7 +522,7 @@ fn external_path(name: &str, substs: &subst::Substs) -> Path {
impl Clean<TyParamBound> for ty::BuiltinBound { impl Clean<TyParamBound> for ty::BuiltinBound {
fn clean(&self) -> TyParamBound { fn clean(&self) -> TyParamBound {
let cx = super::ctxtkey.get().unwrap(); let cx = get_cx();
let tcx = match cx.maybe_typed { let tcx = match cx.maybe_typed {
core::Typed(ref tcx) => tcx, core::Typed(ref tcx) => tcx,
core::NotTyped(_) => return RegionBound, core::NotTyped(_) => return RegionBound,
@ -550,7 +557,7 @@ impl Clean<TyParamBound> for ty::BuiltinBound {
impl Clean<TyParamBound> for ty::TraitRef { impl Clean<TyParamBound> for ty::TraitRef {
fn clean(&self) -> TyParamBound { fn clean(&self) -> TyParamBound {
let cx = super::ctxtkey.get().unwrap(); let cx = get_cx();
let tcx = match cx.maybe_typed { let tcx = match cx.maybe_typed {
core::Typed(ref tcx) => tcx, core::Typed(ref tcx) => tcx,
core::NotTyped(_) => return RegionBound, core::NotTyped(_) => return RegionBound,
@ -709,8 +716,9 @@ impl Clean<Item> for ast::Method {
name: Some(self.ident.clean()), name: Some(self.ident.clean()),
attrs: self.attrs.clean().move_iter().collect(), attrs: self.attrs.clean().move_iter().collect(),
source: self.span.clean(), source: self.span.clean(),
def_id: ast_util::local_def(self.id.clone()), def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(), visibility: self.vis.clean(),
stability: get_stability(ast_util::local_def(self.id)),
inner: MethodItem(Method { inner: MethodItem(Method {
generics: self.generics.clean(), generics: self.generics.clean(),
self_: self.explicit_self.node.clean(), self_: self.explicit_self.node.clean(),
@ -749,6 +757,7 @@ impl Clean<Item> for ast::TypeMethod {
source: self.span.clean(), source: self.span.clean(),
def_id: ast_util::local_def(self.id), def_id: ast_util::local_def(self.id),
visibility: None, visibility: None,
stability: get_stability(ast_util::local_def(self.id)),
inner: TyMethodItem(TyMethod { inner: TyMethodItem(TyMethod {
fn_style: self.fn_style.clone(), fn_style: self.fn_style.clone(),
decl: decl, decl: decl,
@ -792,6 +801,7 @@ impl Clean<Item> for doctree::Function {
attrs: self.attrs.clean(), attrs: self.attrs.clean(),
source: self.where.clean(), source: self.where.clean(),
visibility: self.vis.clean(), visibility: self.vis.clean(),
stability: self.stab.clean(),
def_id: ast_util::local_def(self.id), def_id: ast_util::local_def(self.id),
inner: FunctionItem(Function { inner: FunctionItem(Function {
decl: self.decl.clean(), decl: self.decl.clean(),
@ -854,14 +864,10 @@ impl Clean<FnDecl> for ast::FnDecl {
impl<'a> Clean<FnDecl> for (ast::DefId, &'a ty::FnSig) { impl<'a> Clean<FnDecl> for (ast::DefId, &'a ty::FnSig) {
fn clean(&self) -> FnDecl { fn clean(&self) -> FnDecl {
let cx = super::ctxtkey.get().unwrap(); let cx = get_cx();
let tcx = match cx.maybe_typed {
core::Typed(ref tcx) => tcx,
core::NotTyped(_) => unreachable!(),
};
let (did, sig) = *self; let (did, sig) = *self;
let mut names = if did.node != 0 { let mut names = if did.node != 0 {
csearch::get_method_arg_names(&tcx.sess.cstore, did).move_iter() csearch::get_method_arg_names(&cx.tcx().sess.cstore, did).move_iter()
} else { } else {
Vec::new().move_iter() Vec::new().move_iter()
}.peekable(); }.peekable();
@ -932,6 +938,7 @@ impl Clean<Item> for doctree::Trait {
source: self.where.clean(), source: self.where.clean(),
def_id: ast_util::local_def(self.id), def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(), visibility: self.vis.clean(),
stability: self.stab.clean(),
inner: TraitItem(Trait { inner: TraitItem(Trait {
methods: self.methods.clean(), methods: self.methods.clean(),
generics: self.generics.clean(), generics: self.generics.clean(),
@ -985,11 +992,7 @@ impl Clean<TraitMethod> for ast::TraitMethod {
impl Clean<Item> for ty::Method { impl Clean<Item> for ty::Method {
fn clean(&self) -> Item { fn clean(&self) -> Item {
let cx = super::ctxtkey.get().unwrap(); let cx = get_cx();
let tcx = match cx.maybe_typed {
core::Typed(ref tcx) => tcx,
core::NotTyped(_) => unreachable!(),
};
let (self_, sig) = match self.explicit_self { let (self_, sig) = match self.explicit_self {
ast::SelfStatic => (ast::SelfStatic.clean(), self.fty.sig.clone()), ast::SelfStatic => (ast::SelfStatic.clean(), self.fty.sig.clone()),
s => { s => {
@ -1015,8 +1018,9 @@ impl Clean<Item> for ty::Method {
Item { Item {
name: Some(self.ident.clean()), name: Some(self.ident.clean()),
visibility: Some(ast::Inherited), visibility: Some(ast::Inherited),
stability: get_stability(self.def_id),
def_id: self.def_id, def_id: self.def_id,
attrs: inline::load_attrs(tcx, self.def_id), attrs: inline::load_attrs(cx.tcx(), self.def_id),
source: Span::empty(), source: Span::empty(),
inner: TyMethodItem(TyMethod { inner: TyMethodItem(TyMethod {
fn_style: self.fty.fn_style, fn_style: self.fty.fn_style,
@ -1261,12 +1265,7 @@ impl Clean<Type> for ty::t {
ty::ty_struct(did, ref substs) | ty::ty_struct(did, ref substs) |
ty::ty_enum(did, ref substs) | ty::ty_enum(did, ref substs) |
ty::ty_trait(box ty::TyTrait { def_id: did, ref substs, .. }) => { ty::ty_trait(box ty::TyTrait { def_id: did, ref substs, .. }) => {
let cx = super::ctxtkey.get().unwrap(); let fqn = csearch::get_item_path(get_cx().tcx(), did);
let tcx = match cx.maybe_typed {
core::Typed(ref tycx) => tycx,
core::NotTyped(_) => unreachable!(),
};
let fqn = csearch::get_item_path(tcx, did);
let fqn: Vec<String> = fqn.move_iter().map(|i| { let fqn: Vec<String> = fqn.move_iter().map(|i| {
i.to_str() i.to_str()
}).collect(); }).collect();
@ -1277,8 +1276,8 @@ impl Clean<Type> for ty::t {
}; };
let path = external_path(fqn.last().unwrap().to_str().as_slice(), let path = external_path(fqn.last().unwrap().to_str().as_slice(),
substs); substs);
cx.external_paths.borrow_mut().get_mut_ref().insert(did, get_cx().external_paths.borrow_mut().get_mut_ref()
(fqn, kind)); .insert(did, (fqn, kind));
ResolvedPath { ResolvedPath {
path: path, path: path,
typarams: None, typarams: None,
@ -1318,6 +1317,7 @@ impl Clean<Item> for ast::StructField {
attrs: self.node.attrs.clean().move_iter().collect(), attrs: self.node.attrs.clean().move_iter().collect(),
source: self.span.clean(), source: self.span.clean(),
visibility: Some(vis), visibility: Some(vis),
stability: get_stability(ast_util::local_def(self.node.id)),
def_id: ast_util::local_def(self.node.id), def_id: ast_util::local_def(self.node.id),
inner: StructFieldItem(TypedStructField(self.node.ty.clean())), inner: StructFieldItem(TypedStructField(self.node.ty.clean())),
} }
@ -1332,17 +1332,14 @@ impl Clean<Item> for ty::field_ty {
} else { } else {
Some(self.name) Some(self.name)
}; };
let cx = super::ctxtkey.get().unwrap(); let cx = get_cx();
let tcx = match cx.maybe_typed { let ty = ty::lookup_item_type(cx.tcx(), self.id);
core::Typed(ref tycx) => tycx,
core::NotTyped(_) => unreachable!(),
};
let ty = ty::lookup_item_type(tcx, self.id);
Item { Item {
name: name.clean(), name: name.clean(),
attrs: inline::load_attrs(tcx, self.id), attrs: inline::load_attrs(cx.tcx(), self.id),
source: Span::empty(), source: Span::empty(),
visibility: Some(self.vis), visibility: Some(self.vis),
stability: get_stability(self.id),
def_id: self.id, def_id: self.id,
inner: StructFieldItem(TypedStructField(ty.ty.clean())), inner: StructFieldItem(TypedStructField(ty.ty.clean())),
} }
@ -1373,6 +1370,7 @@ impl Clean<Item> for doctree::Struct {
source: self.where.clean(), source: self.where.clean(),
def_id: ast_util::local_def(self.id), def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(), visibility: self.vis.clean(),
stability: self.stab.clean(),
inner: StructItem(Struct { inner: StructItem(Struct {
struct_type: self.struct_type, struct_type: self.struct_type,
generics: self.generics.clean(), generics: self.generics.clean(),
@ -1418,6 +1416,7 @@ impl Clean<Item> for doctree::Enum {
source: self.where.clean(), source: self.where.clean(),
def_id: ast_util::local_def(self.id), def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(), visibility: self.vis.clean(),
stability: self.stab.clean(),
inner: EnumItem(Enum { inner: EnumItem(Enum {
variants: self.variants.clean(), variants: self.variants.clean(),
generics: self.generics.clean(), generics: self.generics.clean(),
@ -1439,6 +1438,7 @@ impl Clean<Item> for doctree::Variant {
attrs: self.attrs.clean(), attrs: self.attrs.clean(),
source: self.where.clean(), source: self.where.clean(),
visibility: self.vis.clean(), visibility: self.vis.clean(),
stability: self.stab.clean(),
def_id: ast_util::local_def(self.id), def_id: ast_util::local_def(self.id),
inner: VariantItem(Variant { inner: VariantItem(Variant {
kind: self.kind.clean(), kind: self.kind.clean(),
@ -1450,11 +1450,7 @@ impl Clean<Item> for doctree::Variant {
impl Clean<Item> for ty::VariantInfo { impl Clean<Item> for ty::VariantInfo {
fn clean(&self) -> Item { fn clean(&self) -> Item {
// use syntax::parse::token::special_idents::unnamed_field; // use syntax::parse::token::special_idents::unnamed_field;
let cx = super::ctxtkey.get().unwrap(); let cx = get_cx();
let tcx = match cx.maybe_typed {
core::Typed(ref tycx) => tycx,
core::NotTyped(_) => fail!("tcx not present"),
};
let kind = match self.arg_names.as_ref().map(|s| s.as_slice()) { let kind = match self.arg_names.as_ref().map(|s| s.as_slice()) {
None | Some([]) if self.args.len() == 0 => CLikeVariant, None | Some([]) if self.args.len() == 0 => CLikeVariant,
None | Some([]) => { None | Some([]) => {
@ -1470,6 +1466,7 @@ impl Clean<Item> for ty::VariantInfo {
name: Some(name.clean()), name: Some(name.clean()),
attrs: Vec::new(), attrs: Vec::new(),
visibility: Some(ast::Public), visibility: Some(ast::Public),
stability: get_stability(self.id),
// FIXME: this is not accurate, we need an id for // FIXME: this is not accurate, we need an id for
// the specific field but we're using the id // the specific field but we're using the id
// for the whole variant. Nothing currently // for the whole variant. Nothing currently
@ -1485,11 +1482,12 @@ impl Clean<Item> for ty::VariantInfo {
}; };
Item { Item {
name: Some(self.name.clean()), name: Some(self.name.clean()),
attrs: inline::load_attrs(tcx, self.id), attrs: inline::load_attrs(cx.tcx(), self.id),
source: Span::empty(), source: Span::empty(),
visibility: Some(ast::Public), visibility: Some(ast::Public),
def_id: self.id, def_id: self.id,
inner: VariantItem(Variant { kind: kind }), inner: VariantItem(Variant { kind: kind }),
stability: None,
} }
} }
} }
@ -1626,6 +1624,7 @@ impl Clean<Item> for doctree::Typedef {
source: self.where.clean(), source: self.where.clean(),
def_id: ast_util::local_def(self.id.clone()), def_id: ast_util::local_def(self.id.clone()),
visibility: self.vis.clean(), visibility: self.vis.clean(),
stability: self.stab.clean(),
inner: TypedefItem(Typedef { inner: TypedefItem(Typedef {
type_: self.ty.clean(), type_: self.ty.clean(),
generics: self.gen.clean(), generics: self.gen.clean(),
@ -1675,6 +1674,7 @@ impl Clean<Item> for doctree::Static {
source: self.where.clean(), source: self.where.clean(),
def_id: ast_util::local_def(self.id), def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(), visibility: self.vis.clean(),
stability: self.stab.clean(),
inner: StaticItem(Static { inner: StaticItem(Static {
type_: self.type_.clean(), type_: self.type_.clean(),
mutability: self.mutability.clean(), mutability: self.mutability.clean(),
@ -1720,6 +1720,7 @@ impl Clean<Item> for doctree::Impl {
source: self.where.clean(), source: self.where.clean(),
def_id: ast_util::local_def(self.id), def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(), visibility: self.vis.clean(),
stability: self.stab.clean(),
inner: ImplItem(Impl { inner: ImplItem(Impl {
generics: self.generics.clean(), generics: self.generics.clean(),
trait_: self.trait_.clean(), trait_: self.trait_.clean(),
@ -1754,6 +1755,7 @@ impl Clean<Vec<Item>> for ast::ViewItem {
source: self.span.clean(), source: self.span.clean(),
def_id: ast_util::local_def(0), def_id: ast_util::local_def(0),
visibility: self.vis.clean(), visibility: self.vis.clean(),
stability: None,
inner: ViewItemItem(ViewItem { inner: node.clean() }), inner: ViewItemItem(ViewItem { inner: node.clean() }),
} }
}; };
@ -1895,6 +1897,7 @@ impl Clean<Item> for ast::ForeignItem {
source: self.span.clean(), source: self.span.clean(),
def_id: ast_util::local_def(self.id), def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(), visibility: self.vis.clean(),
stability: None,
inner: inner, inner: inner,
} }
} }
@ -1977,7 +1980,7 @@ fn name_from_pat(p: &ast::Pat) -> String {
/// Given a Type, resolve it using the def_map /// 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 { id: ast::NodeId) -> Type {
let cx = super::ctxtkey.get().unwrap(); let cx = get_cx();
let tycx = match cx.maybe_typed { let tycx = match cx.maybe_typed {
core::Typed(ref tycx) => tycx, core::Typed(ref tycx) => tycx,
// If we're extracting tests, this return value doesn't matter. // If we're extracting tests, this return value doesn't matter.
@ -2012,7 +2015,7 @@ fn resolve_type(path: Path, tpbs: Option<Vec<TyParamBound>>,
def::DefTyParamBinder(i) => return TyParamBinder(i), def::DefTyParamBinder(i) => return TyParamBinder(i),
_ => {} _ => {}
}; };
let did = register_def(&**cx, def); let did = register_def(&*cx, def);
ResolvedPath { path: path, typarams: tpbs, did: did } ResolvedPath { path: path, typarams: tpbs, did: did }
} }
@ -2051,13 +2054,9 @@ fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
} }
fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> { fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> {
let cx = super::ctxtkey.get().unwrap(); get_cx().tcx_opt().and_then(|tcx| {
match cx.maybe_typed { tcx.def_map.borrow().find(&id).map(|&def| register_def(&*get_cx(), def))
core::Typed(ref tcx) => { })
tcx.def_map.borrow().find(&id).map(|&def| register_def(&**cx, def))
}
core::NotTyped(_) => None
}
} }
#[deriving(Clone, Encodable, Decodable)] #[deriving(Clone, Encodable, Decodable)]
@ -2072,6 +2071,7 @@ impl Clean<Item> for doctree::Macro {
attrs: self.attrs.clean(), attrs: self.attrs.clean(),
source: self.where.clean(), source: self.where.clean(),
visibility: ast::Public.clean(), visibility: ast::Public.clean(),
stability: self.stab.clean(),
def_id: ast_util::local_def(self.id), def_id: ast_util::local_def(self.id),
inner: MacroItem(Macro { inner: MacroItem(Macro {
source: self.where.to_src(), source: self.where.to_src(),
@ -2079,3 +2079,19 @@ impl Clean<Item> for doctree::Macro {
} }
} }
} }
#[deriving(Clone, Encodable, Decodable)]
pub struct Stability {
pub level: attr::StabilityLevel,
pub text: String
}
impl Clean<Stability> for attr::Stability {
fn clean(&self) -> Stability {
Stability {
level: self.level,
text: self.text.as_ref().map_or("".to_string(),
|interned| interned.get().to_string()),
}
}
}

View File

@ -10,7 +10,7 @@
use rustc; use rustc;
use rustc::{driver, middle}; use rustc::{driver, middle};
use rustc::middle::privacy; use rustc::middle::{privacy, ty};
use rustc::lint; use rustc::lint;
use syntax::ast; use syntax::ast;
@ -26,6 +26,7 @@ use visit_ast::RustdocVisitor;
use clean; use clean;
use clean::Clean; use clean::Clean;
/// Are we generating documentation (`Typed`) or tests (`NotTyped`)?
pub enum MaybeTyped { pub enum MaybeTyped {
Typed(middle::ty::ctxt), Typed(middle::ty::ctxt),
NotTyped(driver::session::Session) NotTyped(driver::session::Session)
@ -52,6 +53,18 @@ impl DocContext {
NotTyped(ref sess) => sess NotTyped(ref sess) => sess
} }
} }
pub fn tcx_opt<'a>(&'a self) -> Option<&'a ty::ctxt> {
match self.maybe_typed {
Typed(ref tcx) => Some(tcx),
NotTyped(_) => None
}
}
pub fn tcx<'a>(&'a self) -> &'a ty::ctxt {
let tcx_opt = self.tcx_opt();
tcx_opt.expect("tcx not present")
}
} }
pub struct CrateAnalysis { pub struct CrateAnalysis {

View File

@ -14,6 +14,7 @@
use syntax; use syntax;
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::ast; use syntax::ast;
use syntax::attr;
use syntax::ast::{Ident, NodeId}; use syntax::ast::{Ident, NodeId};
use std::gc::Gc; use std::gc::Gc;
@ -32,6 +33,7 @@ pub struct Module {
pub statics: Vec<Static>, pub statics: Vec<Static>,
pub traits: Vec<Trait>, pub traits: Vec<Trait>,
pub vis: ast::Visibility, pub vis: ast::Visibility,
pub stab: Option<attr::Stability>,
pub impls: Vec<Impl>, pub impls: Vec<Impl>,
pub foreigns: Vec<ast::ForeignMod>, pub foreigns: Vec<ast::ForeignMod>,
pub view_items: Vec<ast::ViewItem>, pub view_items: Vec<ast::ViewItem>,
@ -45,6 +47,7 @@ impl Module {
name : name, name : name,
id: 0, id: 0,
vis: ast::Inherited, vis: ast::Inherited,
stab: None,
where_outer: syntax::codemap::DUMMY_SP, where_outer: syntax::codemap::DUMMY_SP,
where_inner: syntax::codemap::DUMMY_SP, where_inner: syntax::codemap::DUMMY_SP,
attrs : Vec::new(), attrs : Vec::new(),
@ -83,6 +86,7 @@ pub enum TypeBound {
pub struct Struct { pub struct Struct {
pub vis: ast::Visibility, pub vis: ast::Visibility,
pub stab: Option<attr::Stability>,
pub id: NodeId, pub id: NodeId,
pub struct_type: StructType, pub struct_type: StructType,
pub name: Ident, pub name: Ident,
@ -94,6 +98,7 @@ pub struct Struct {
pub struct Enum { pub struct Enum {
pub vis: ast::Visibility, pub vis: ast::Visibility,
pub stab: Option<attr::Stability>,
pub variants: Vec<Variant>, pub variants: Vec<Variant>,
pub generics: ast::Generics, pub generics: ast::Generics,
pub attrs: Vec<ast::Attribute>, pub attrs: Vec<ast::Attribute>,
@ -108,6 +113,7 @@ pub struct Variant {
pub kind: ast::VariantKind, pub kind: ast::VariantKind,
pub id: ast::NodeId, pub id: ast::NodeId,
pub vis: ast::Visibility, pub vis: ast::Visibility,
pub stab: Option<attr::Stability>,
pub where: Span, pub where: Span,
} }
@ -117,6 +123,7 @@ pub struct Function {
pub id: NodeId, pub id: NodeId,
pub name: Ident, pub name: Ident,
pub vis: ast::Visibility, pub vis: ast::Visibility,
pub stab: Option<attr::Stability>,
pub fn_style: ast::FnStyle, pub fn_style: ast::FnStyle,
pub where: Span, pub where: Span,
pub generics: ast::Generics, pub generics: ast::Generics,
@ -130,6 +137,7 @@ pub struct Typedef {
pub attrs: Vec<ast::Attribute>, pub attrs: Vec<ast::Attribute>,
pub where: Span, pub where: Span,
pub vis: ast::Visibility, pub vis: ast::Visibility,
pub stab: Option<attr::Stability>,
} }
pub struct Static { pub struct Static {
@ -139,6 +147,7 @@ pub struct Static {
pub name: Ident, pub name: Ident,
pub attrs: Vec<ast::Attribute>, pub attrs: Vec<ast::Attribute>,
pub vis: ast::Visibility, pub vis: ast::Visibility,
pub stab: Option<attr::Stability>,
pub id: ast::NodeId, pub id: ast::NodeId,
pub where: Span, pub where: Span,
} }
@ -152,6 +161,7 @@ pub struct Trait {
pub id: ast::NodeId, pub id: ast::NodeId,
pub where: Span, pub where: Span,
pub vis: ast::Visibility, pub vis: ast::Visibility,
pub stab: Option<attr::Stability>,
} }
pub struct Impl { pub struct Impl {
@ -162,6 +172,7 @@ pub struct Impl {
pub attrs: Vec<ast::Attribute>, pub attrs: Vec<ast::Attribute>,
pub where: Span, pub where: Span,
pub vis: ast::Visibility, pub vis: ast::Visibility,
pub stab: Option<attr::Stability>,
pub id: ast::NodeId, pub id: ast::NodeId,
} }
@ -170,6 +181,7 @@ pub struct Macro {
pub id: ast::NodeId, pub id: ast::NodeId,
pub attrs: Vec<ast::Attribute>, pub attrs: Vec<ast::Attribute>,
pub where: Span, pub where: Span,
pub stab: Option<attr::Stability>,
} }
pub fn struct_type_from_def(sd: &ast::StructDef) -> StructType { pub fn struct_type_from_def(sd: &ast::StructDef) -> StructType {

View File

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

View File

@ -37,6 +37,10 @@ pub struct FnStyleSpace(pub ast::FnStyle);
pub struct Method<'a>(pub &'a clean::SelfTy, pub &'a clean::FnDecl); pub struct Method<'a>(pub &'a clean::SelfTy, pub &'a clean::FnDecl);
/// Similar to VisSpace, but used for mutability /// Similar to VisSpace, but used for mutability
pub struct MutableSpace(pub clean::Mutability); pub struct MutableSpace(pub clean::Mutability);
/// Wrapper struct for properly emitting the stability level.
pub struct Stability<'a>(pub &'a Option<clean::Stability>);
/// Wrapper struct for emitting the stability level concisely.
pub struct ConciseStability<'a>(pub &'a Option<clean::Stability>);
impl VisSpace { impl VisSpace {
pub fn get(&self) -> Option<ast::Visibility> { pub fn get(&self) -> Option<ast::Visibility> {
@ -596,3 +600,34 @@ impl fmt::Show for MutableSpace {
} }
} }
} }
impl<'a> fmt::Show for Stability<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Stability(stab) = *self;
match *stab {
Some(ref stability) => {
write!(f, "<a class='stability {lvl}' title='{reason}'>{lvl}</a>",
lvl = stability.level.to_str(),
reason = stability.text)
}
None => Ok(())
}
}
}
impl<'a> fmt::Show for ConciseStability<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let ConciseStability(stab) = *self;
match *stab {
Some(ref stability) => {
write!(f, "<a class='stability {lvl}' title='{lvl}{colon}{reason}'></a>",
lvl = stability.level.to_str(),
colon = if stability.text.len() > 0 { ": " } else { "" },
reason = stability.text)
}
None => {
write!(f, "<a class='stability Unmarked' title='No stability level'></a>")
}
}
}
}

View File

@ -46,14 +46,13 @@ use externalfiles::ExternalHtml;
use serialize::json::ToJson; use serialize::json::ToJson;
use syntax::ast; use syntax::ast;
use syntax::ast_util; use syntax::ast_util;
use syntax::attr;
use syntax::parse::token::InternedString;
use rustc::util::nodemap::NodeSet; use rustc::util::nodemap::NodeSet;
use clean; use clean;
use doctree; use doctree;
use fold::DocFolder; use fold::DocFolder;
use html::format::{VisSpace, Method, FnStyleSpace, MutableSpace}; use html::format::{VisSpace, Method, FnStyleSpace, MutableSpace, Stability};
use html::format::{ConciseStability};
use html::highlight; use html::highlight;
use html::item_type::{ItemType, shortty}; use html::item_type::{ItemType, shortty};
use html::item_type; use html::item_type;
@ -114,6 +113,15 @@ pub struct Implementor {
generics: clean::Generics, generics: clean::Generics,
trait_: clean::Type, trait_: clean::Type,
for_: clean::Type, for_: clean::Type,
stability: Option<clean::Stability>,
}
/// Metadata about implementations for a type.
#[deriving(Clone)]
pub struct Impl {
impl_: clean::Impl,
dox: Option<String>,
stability: Option<clean::Stability>,
} }
/// This cache is used to store information about the `clean::Crate` being /// This cache is used to store information about the `clean::Crate` being
@ -137,7 +145,7 @@ pub struct Cache {
/// ///
/// The values of the map are a list of implementations and documentation /// The values of the map are a list of implementations and documentation
/// found on that implementation. /// found on that implementation.
pub impls: HashMap<ast::DefId, Vec<(clean::Impl, Option<String>)>>, pub impls: HashMap<ast::DefId, Vec<Impl>>,
/// Maintains a mapping of local crate node ids to the fully qualified name /// 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 /// and "short type description" of that node. This is used when generating
@ -550,7 +558,8 @@ fn write_shared(cx: &Context,
// going on). If they're in different crates then the crate defining // going on). If they're in different crates then the crate defining
// the trait will be interested in our implementation. // the trait will be interested in our implementation.
if imp.def_id.krate == did.krate { continue } if imp.def_id.krate == did.krate { continue }
try!(write!(&mut f, r#""impl{} {} for {}","#, try!(write!(&mut f, r#""{}impl{} {} for {}","#,
ConciseStability(&imp.stability),
imp.generics, imp.trait_, imp.for_)); imp.generics, imp.trait_, imp.for_));
} }
try!(writeln!(&mut f, r"];")); try!(writeln!(&mut f, r"];"));
@ -782,6 +791,7 @@ impl DocFolder for Cache {
generics: i.generics.clone(), generics: i.generics.clone(),
trait_: i.trait_.get_ref().clone(), trait_: i.trait_.get_ref().clone(),
for_: i.for_.clone(), for_: i.for_.clone(),
stability: item.stability.clone(),
}); });
} }
Some(..) | None => {} Some(..) | None => {}
@ -967,7 +977,11 @@ impl DocFolder for Cache {
let v = self.impls.find_or_insert_with(did, |_| { let v = self.impls.find_or_insert_with(did, |_| {
Vec::new() Vec::new()
}); });
v.push((i, dox)); v.push(Impl {
impl_: i,
dox: dox,
stability: item.stability.clone(),
});
} }
None => {} None => {}
} }
@ -1248,19 +1262,8 @@ impl<'a> fmt::Show for Item<'a> {
try!(write!(fmt, "<a class='{}' href=''>{}</a>", try!(write!(fmt, "<a class='{}' href=''>{}</a>",
shortty(self.item), self.item.name.get_ref().as_slice())); shortty(self.item), self.item.name.get_ref().as_slice()));
// Write stability attributes // Write stability level
match attr::find_stability_generic(self.item.attrs.iter()) { try!(write!(fmt, "{}", Stability(&self.item.stability)));
Some((ref stability, _)) => {
try!(write!(fmt,
"<a class='stability {lvl}' title='{reason}'>{lvl}</a>",
lvl = stability.level.to_str(),
reason = match stability.text {
Some(ref s) => (*s).clone(),
None => InternedString::new(""),
}));
}
None => {}
}
// Write `src` tag // Write `src` tag
// //
@ -1454,10 +1457,11 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
try!(write!(w, " try!(write!(w, "
<tr> <tr>
<td><code>{}static {}{}: {}</code>{}</td> <td>{}<code>{}static {}{}: {}</code>{}</td>
<td class='docblock'>{}&nbsp;</td> <td class='docblock'>{}&nbsp;</td>
</tr> </tr>
", ",
ConciseStability(&myitem.stability),
VisSpace(myitem.visibility), VisSpace(myitem.visibility),
MutableSpace(s.mutability), MutableSpace(s.mutability),
*myitem.name.get_ref(), *myitem.name.get_ref(),
@ -1492,7 +1496,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
if myitem.name.is_none() { continue } if myitem.name.is_none() { continue }
try!(write!(w, " try!(write!(w, "
<tr> <tr>
<td><a class='{class}' href='{href}' <td>{stab}<a class='{class}' href='{href}'
title='{title}'>{}</a></td> title='{title}'>{}</a></td>
<td class='docblock short'>{}</td> <td class='docblock short'>{}</td>
</tr> </tr>
@ -1501,7 +1505,8 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
Markdown(shorter(myitem.doc_value())), Markdown(shorter(myitem.doc_value())),
class = shortty(myitem), class = shortty(myitem),
href = item_path(myitem), href = item_path(myitem),
title = full_path(cx, myitem))); title = full_path(cx, myitem),
stab = ConciseStability(&myitem.stability)));
} }
} }
} }
@ -1565,9 +1570,10 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
try!(document(w, it)); try!(document(w, it));
fn meth(w: &mut fmt::Formatter, m: &clean::TraitMethod) -> fmt::Result { fn meth(w: &mut fmt::Formatter, m: &clean::TraitMethod) -> fmt::Result {
try!(write!(w, "<h3 id='{}.{}' class='method'><code>", try!(write!(w, "<h3 id='{}.{}' class='method'>{}<code>",
shortty(m.item()), shortty(m.item()),
*m.item().name.get_ref())); *m.item().name.get_ref(),
ConciseStability(&m.item().stability)));
try!(render_method(w, m.item())); try!(render_method(w, m.item()));
try!(write!(w, "</code></h3>")); try!(write!(w, "</code></h3>"));
try!(document(w, m.item())); try!(document(w, m.item()));
@ -1604,7 +1610,8 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
match cache.implementors.find(&it.def_id) { match cache.implementors.find(&it.def_id) {
Some(implementors) => { Some(implementors) => {
for i in implementors.iter() { for i in implementors.iter() {
try!(writeln!(w, "<li><code>impl{} {} for {}</code></li>", try!(writeln!(w, "<li>{}<code>impl{} {} for {}</code></li>",
ConciseStability(&i.stability),
i.generics, i.trait_, i.for_)); i.generics, i.trait_, i.for_));
} }
} }
@ -1677,7 +1684,8 @@ fn item_struct(w: &mut fmt::Formatter, it: &clean::Item,
try!(write!(w, "<h2 class='fields'>Fields</h2>\n<table>")); try!(write!(w, "<h2 class='fields'>Fields</h2>\n<table>"));
for field in fields { for field in fields {
try!(write!(w, "<tr><td id='structfield.{name}'>\ try!(write!(w, "<tr><td id='structfield.{name}'>\
<code>{name}</code></td><td>", {stab}<code>{name}</code></td><td>",
stab = ConciseStability(&field.stability),
name = field.name.get_ref().as_slice())); name = field.name.get_ref().as_slice()));
try!(document(w, field)); try!(document(w, field));
try!(write!(w, "</td></tr>")); try!(write!(w, "</td></tr>"));
@ -1743,7 +1751,8 @@ fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
if e.variants.len() > 0 { if e.variants.len() > 0 {
try!(write!(w, "<h2 class='variants'>Variants</h2>\n<table>")); try!(write!(w, "<h2 class='variants'>Variants</h2>\n<table>"));
for variant in e.variants.iter() { for variant in e.variants.iter() {
try!(write!(w, "<tr><td id='variant.{name}'><code>{name}</code></td><td>", try!(write!(w, "<tr><td id='variant.{name}'>{stab}<code>{name}</code></td><td>",
stab = ConciseStability(&variant.stability),
name = variant.name.get_ref().as_slice())); name = variant.name.get_ref().as_slice()));
try!(document(w, variant)); try!(document(w, variant));
match variant.inner { match variant.inner {
@ -1853,39 +1862,25 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result { fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
match cache_key.get().unwrap().impls.find(&it.def_id) { match cache_key.get().unwrap().impls.find(&it.def_id) {
Some(v) => { Some(v) => {
let mut non_trait = v.iter().filter(|p| { let (non_trait, traits) = v.partitioned(|i| i.impl_.trait_.is_none());
p.ref0().trait_.is_none()
});
let non_trait = non_trait.collect::<Vec<&(clean::Impl, Option<String>)>>();
let mut traits = v.iter().filter(|p| {
p.ref0().trait_.is_some()
});
let traits = traits.collect::<Vec<&(clean::Impl, Option<String>)>>();
if non_trait.len() > 0 { if non_trait.len() > 0 {
try!(write!(w, "<h2 id='methods'>Methods</h2>")); try!(write!(w, "<h2 id='methods'>Methods</h2>"));
for &(ref i, ref dox) in non_trait.move_iter() { for i in non_trait.iter() {
try!(render_impl(w, i, dox)); try!(render_impl(w, i));
} }
} }
if traits.len() > 0 { if traits.len() > 0 {
try!(write!(w, "<h2 id='implementations'>Trait \ try!(write!(w, "<h2 id='implementations'>Trait \
Implementations</h2>")); Implementations</h2>"));
let mut any_derived = false; let (derived, manual) = traits.partition(|i| i.impl_.derived);
for & &(ref i, ref dox) in traits.iter() { for i in manual.iter() {
if !i.derived { try!(render_impl(w, i));
try!(render_impl(w, i, dox));
} else {
any_derived = true;
}
} }
if any_derived { if derived.len() > 0 {
try!(write!(w, "<h3 id='derived_implementations'>Derived Implementations \ try!(write!(w, "<h3 id='derived_implementations'>Derived Implementations \
</h3>")); </h3>"));
for &(ref i, ref dox) in traits.move_iter() { for i in derived.iter() {
if i.derived { try!(render_impl(w, i));
try!(render_impl(w, i, dox));
}
} }
} }
} }
@ -1895,15 +1890,16 @@ fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
Ok(()) Ok(())
} }
fn render_impl(w: &mut fmt::Formatter, i: &clean::Impl, fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
dox: &Option<String>) -> fmt::Result { try!(write!(w, "<h3 class='impl'>{}<code>impl{} ",
try!(write!(w, "<h3 class='impl'><code>impl{} ", i.generics)); ConciseStability(&i.stability),
match i.trait_ { i.impl_.generics));
match i.impl_.trait_ {
Some(ref ty) => try!(write!(w, "{} for ", *ty)), Some(ref ty) => try!(write!(w, "{} for ", *ty)),
None => {} None => {}
} }
try!(write!(w, "{}</code></h3>", i.for_)); try!(write!(w, "{}</code></h3>", i.impl_.for_));
match *dox { match i.dox {
Some(ref dox) => { Some(ref dox) => {
try!(write!(w, "<div class='docblock'>{}</div>", try!(write!(w, "<div class='docblock'>{}</div>",
Markdown(dox.as_slice()))); Markdown(dox.as_slice())));
@ -1913,8 +1909,9 @@ fn render_impl(w: &mut fmt::Formatter, i: &clean::Impl,
fn docmeth(w: &mut fmt::Formatter, item: &clean::Item, fn docmeth(w: &mut fmt::Formatter, item: &clean::Item,
dox: bool) -> fmt::Result { dox: bool) -> fmt::Result {
try!(write!(w, "<h4 id='method.{}' class='method'><code>", try!(write!(w, "<h4 id='method.{}' class='method'>{}<code>",
*item.name.get_ref())); *item.name.get_ref(),
ConciseStability(&item.stability)));
try!(render_method(w, item)); try!(render_method(w, item));
try!(write!(w, "</code></h4>\n")); try!(write!(w, "</code></h4>\n"));
match item.doc_value() { match item.doc_value() {
@ -1926,8 +1923,8 @@ fn render_impl(w: &mut fmt::Formatter, i: &clean::Impl,
} }
} }
try!(write!(w, "<div class='methods'>")); try!(write!(w, "<div class='impl-methods'>"));
for meth in i.methods.iter() { for meth in i.impl_.methods.iter() {
try!(docmeth(w, meth, true)); try!(docmeth(w, meth, true));
} }
@ -1948,11 +1945,11 @@ fn render_impl(w: &mut fmt::Formatter, i: &clean::Impl,
// If we've implemented a trait, then also emit documentation for all // If we've implemented a trait, then also emit documentation for all
// default methods which weren't overridden in the implementation block. // default methods which weren't overridden in the implementation block.
match i.trait_ { match i.impl_.trait_ {
Some(clean::ResolvedPath { did, .. }) => { Some(clean::ResolvedPath { did, .. }) => {
try!({ try!({
match cache_key.get().unwrap().traits.find(&did) { match cache_key.get().unwrap().traits.find(&did) {
Some(t) => try!(render_default_methods(w, t, i)), Some(t) => try!(render_default_methods(w, t, &i.impl_)),
None => {} None => {}
} }
Ok(()) Ok(())

View File

@ -258,8 +258,9 @@ nav.sub {
.content .multi-column li { width: 100%; display: inline-block; } .content .multi-column li { width: 100%; display: inline-block; }
.content .method { font-size: 1em; } .content .method { font-size: 1em; }
.content .methods { margin-left: 20px; } .content .methods .docblock { margin-left: 40px; }
.content .methods .docblock { margin-left: 20px; }
.content .impl-methods .docblock { margin-left: 40px; }
nav { nav {
border-bottom: 1px solid #e0e0e0; border-bottom: 1px solid #e0e0e0;
@ -372,20 +373,29 @@ p a:hover { text-decoration: underline; }
} }
.stability { .stability {
border-left: 6px solid #000; border-left: 6px solid;
padding: 3px 6px;
border-radius: 3px; border-radius: 3px;
font-weight: 400;
padding: 4px 10px;
text-transform: lowercase;
margin-left: 14px;
} }
.stability.Deprecated { border-color: #D60027; color: #880017; } h1 .stability {
.stability.Experimental { border-color: #EC5315; color: #a53c0e; } text-transform: lowercase;
.stability.Unstable { border-color: #FFD700; color: #b39800; } font-weight: 400;
.stability.Stable { border-color: #AEC516; color: #7c8b10; } margin-left: 14px;
padding: 4px 10px;
}
.impl-methods .stability {
margin-right: 20px;
}
.stability.Deprecated { border-color: #A071A8; color: #82478C; }
.stability.Experimental { border-color: #D46D6A; color: #AA3C39; }
.stability.Unstable { border-color: #D4B16A; color: #AA8439; }
.stability.Stable { border-color: #54A759; color: #2D8632; }
.stability.Frozen { border-color: #009431; color: #007726; } .stability.Frozen { border-color: #009431; color: #007726; }
.stability.Locked { border-color: #0084B6; color: #00668c; } .stability.Locked { border-color: #0084B6; color: #00668c; }
.stability.Unmarked { border-color: #FFFFFF; }
:target { background: #FDFFD3; } :target { background: #FDFFD3; }

View File

@ -15,9 +15,12 @@ use syntax::abi;
use syntax::ast; use syntax::ast;
use syntax::ast_util; use syntax::ast_util;
use syntax::ast_map; use syntax::ast_map;
use syntax::attr;
use syntax::attr::AttrMetaMethods; use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span; use syntax::codemap::Span;
use rustc::middle::stability;
use std::gc::{Gc, GC}; use std::gc::{Gc, GC};
use core; use core;
@ -41,6 +44,14 @@ impl<'a> RustdocVisitor<'a> {
} }
} }
fn stability(&self, id: ast::NodeId) -> Option<attr::Stability> {
let tcx = match self.cx.maybe_typed {
core::Typed(ref tcx) => tcx,
core::NotTyped(_) => return None
};
stability::lookup(tcx, ast_util::local_def(id))
}
pub fn visit(&mut self, krate: &ast::Crate) { pub fn visit(&mut self, krate: &ast::Crate) {
self.attrs = krate.attrs.iter().map(|x| (*x).clone()).collect(); self.attrs = krate.attrs.iter().map(|x| (*x).clone()).collect();
@ -65,6 +76,7 @@ impl<'a> RustdocVisitor<'a> {
struct_type: struct_type, struct_type: struct_type,
name: item.ident, name: item.ident,
vis: item.vis, vis: item.vis,
stab: self.stability(item.id),
attrs: item.attrs.iter().map(|x| *x).collect(), attrs: item.attrs.iter().map(|x| *x).collect(),
generics: generics.clone(), generics: generics.clone(),
fields: sd.fields.iter().map(|x| (*x).clone()).collect(), fields: sd.fields.iter().map(|x| (*x).clone()).collect(),
@ -81,6 +93,7 @@ impl<'a> RustdocVisitor<'a> {
name: x.node.name, name: x.node.name,
attrs: x.node.attrs.iter().map(|x| *x).collect(), attrs: x.node.attrs.iter().map(|x| *x).collect(),
vis: x.node.vis, vis: x.node.vis,
stab: self.stability(x.node.id),
id: x.node.id, id: x.node.id,
kind: x.node.kind.clone(), kind: x.node.kind.clone(),
where: x.span, where: x.span,
@ -90,6 +103,7 @@ impl<'a> RustdocVisitor<'a> {
name: it.ident, name: it.ident,
variants: vars, variants: vars,
vis: it.vis, vis: it.vis,
stab: self.stability(it.id),
generics: params.clone(), generics: params.clone(),
attrs: it.attrs.iter().map(|x| *x).collect(), attrs: it.attrs.iter().map(|x| *x).collect(),
id: it.id, id: it.id,
@ -104,6 +118,7 @@ impl<'a> RustdocVisitor<'a> {
Function { Function {
id: item.id, id: item.id,
vis: item.vis, vis: item.vis,
stab: self.stability(item.id),
attrs: item.attrs.iter().map(|x| *x).collect(), attrs: item.attrs.iter().map(|x| *x).collect(),
decl: fd.clone(), decl: fd.clone(),
name: item.ident, name: item.ident,
@ -125,6 +140,7 @@ impl<'a> RustdocVisitor<'a> {
om.where_inner = m.inner; om.where_inner = m.inner;
om.attrs = attrs; om.attrs = attrs;
om.vis = vis; om.vis = vis;
om.stab = self.stability(id);
om.id = id; om.id = id;
for i in m.items.iter() { for i in m.items.iter() {
self.visit_item(&**i, &mut om); self.visit_item(&**i, &mut om);
@ -258,6 +274,7 @@ impl<'a> RustdocVisitor<'a> {
attrs: item.attrs.iter().map(|x| *x).collect(), attrs: item.attrs.iter().map(|x| *x).collect(),
where: item.span, where: item.span,
vis: item.vis, vis: item.vis,
stab: self.stability(item.id),
}; };
om.typedefs.push(t); om.typedefs.push(t);
}, },
@ -271,6 +288,7 @@ impl<'a> RustdocVisitor<'a> {
attrs: item.attrs.iter().map(|x| *x).collect(), attrs: item.attrs.iter().map(|x| *x).collect(),
where: item.span, where: item.span,
vis: item.vis, vis: item.vis,
stab: self.stability(item.id),
}; };
om.statics.push(s); om.statics.push(s);
}, },
@ -284,6 +302,7 @@ impl<'a> RustdocVisitor<'a> {
attrs: item.attrs.iter().map(|x| *x).collect(), attrs: item.attrs.iter().map(|x| *x).collect(),
where: item.span, where: item.span,
vis: item.vis, vis: item.vis,
stab: self.stability(item.id),
}; };
om.traits.push(t); om.traits.push(t);
}, },
@ -297,6 +316,7 @@ impl<'a> RustdocVisitor<'a> {
id: item.id, id: item.id,
where: item.span, where: item.span,
vis: item.vis, vis: item.vis,
stab: self.stability(item.id),
}; };
om.impls.push(i); om.impls.push(i);
}, },
@ -309,6 +329,7 @@ impl<'a> RustdocVisitor<'a> {
attrs: item.attrs.iter().map(|x| *x).collect(), attrs: item.attrs.iter().map(|x| *x).collect(),
name: item.ident, name: item.ident,
where: item.span, where: item.span,
stab: self.stability(item.id),
}) })
} }
} }