Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustdoc: Support associated types #19174

Merged
merged 2 commits into from
Nov 25, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 37 additions & 3 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ pub enum ItemEnum {
ForeignStaticItem(Static),
MacroItem(Macro),
PrimitiveItem(PrimitiveType),
AssociatedTypeItem,
AssociatedTypeItem(TyParam),
}

#[deriving(Clone, Encodable, Decodable)]
Expand Down Expand Up @@ -982,6 +982,8 @@ impl Clean<Type> for ast::PolyTraitRef {
}
}

/// An item belonging to a trait, whether a method or associated. Could be named
/// TraitItem except that's already taken by an exported enum variant.
#[deriving(Clone, Encodable, Decodable)]
pub enum TraitMethod {
RequiredMethod(Item),
Expand All @@ -1002,6 +1004,12 @@ impl TraitMethod {
_ => false,
}
}
pub fn is_type(&self) -> bool {
match self {
&TypeTraitItem(..) => true,
_ => false,
}
}
pub fn item<'a>(&'a self) -> &'a Item {
match *self {
RequiredMethod(ref item) => item,
Expand Down Expand Up @@ -1127,6 +1135,11 @@ pub enum Type {
mutability: Mutability,
type_: Box<Type>,
},
QPath {
name: String,
self_type: Box<Type>,
trait_: Box<Type>
},
// region, raw, other boxes, mutable
}

Expand Down Expand Up @@ -1252,6 +1265,7 @@ impl Clean<Type> for ast::Ty {
TyProc(ref c) => Proc(box c.clean(cx)),
TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
TyParen(ref ty) => ty.clean(cx),
TyQPath(ref qp) => qp.clean(cx),
ref x => panic!("Unimplemented type {}", x),
}
}
Expand Down Expand Up @@ -1354,6 +1368,16 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
}
}

impl Clean<Type> for ast::QPath {
fn clean(&self, cx: &DocContext) -> Type {
Type::QPath {
name: self.item_name.clean(cx),
self_type: box self.self_type.clean(cx),
trait_: box self.trait_ref.clean(cx)
}
}
}

#[deriving(Clone, Encodable, Decodable)]
pub enum StructField {
HiddenStructField, // inserted later by strip passes
Expand Down Expand Up @@ -2211,7 +2235,7 @@ impl Clean<Item> for ast::AssociatedType {
source: self.ty_param.span.clean(cx),
name: Some(self.ty_param.ident.clean(cx)),
attrs: self.attrs.clean(cx),
inner: AssociatedTypeItem,
inner: AssociatedTypeItem(self.ty_param.clean(cx)),
visibility: None,
def_id: ast_util::local_def(self.ty_param.id),
stability: None,
Expand All @@ -2225,7 +2249,17 @@ impl Clean<Item> for ty::AssociatedType {
source: DUMMY_SP.clean(cx),
name: Some(self.name.clean(cx)),
attrs: Vec::new(),
inner: AssociatedTypeItem,
// FIXME(#18048): this is wrong, but cross-crate associated types are broken
// anyway, for the time being.
inner: AssociatedTypeItem(TyParam {
name: self.name.clean(cx),
did: ast::DefId {
krate: 0,
node: ast::DUMMY_NODE_ID
},
bounds: vec![],
default: None
}),
visibility: None,
def_id: self.def_id,
stability: None,
Expand Down
6 changes: 4 additions & 2 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,8 @@ pub struct Stability<'a>(pub &'a Option<clean::Stability>);
pub struct ConciseStability<'a>(pub &'a Option<clean::Stability>);
/// Wrapper struct for emitting a where clause from Generics.
pub struct WhereClause<'a>(pub &'a clean::Generics);

/// Wrapper struct for emitting type parameter bounds.
struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]);
pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]);

impl VisSpace {
pub fn get(&self) -> Option<ast::Visibility> {
Expand Down Expand Up @@ -486,6 +485,9 @@ impl fmt::Show for clean::Type {
}
}
}
clean::QPath { ref name, ref self_type, ref trait_ } => {
write!(f, "&lt;{} as {}&gt;::{}", self_type, trait_, name)
}
clean::Unique(..) => {
panic!("should have been cleaned")
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/html/item_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ pub fn shortty(item: &clean::Item) -> ItemType {
clean::ForeignStaticItem(..) => ForeignStatic,
clean::MacroItem(..) => Macro,
clean::PrimitiveItem(..) => Primitive,
clean::AssociatedTypeItem => AssociatedType,
clean::AssociatedTypeItem(..) => AssociatedType,
}
}

92 changes: 65 additions & 27 deletions src/librustdoc/html/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ use clean;
use doctree;
use fold::DocFolder;
use html::format::{VisSpace, Method, FnStyleSpace, MutableSpace, Stability};
use html::format::{ConciseStability, WhereClause};
use html::format::{ConciseStability, TyParamBounds, WhereClause};
use html::highlight;
use html::item_type::{ItemType, shortty};
use html::item_type;
Expand Down Expand Up @@ -1685,27 +1685,23 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
t.generics,
bounds,
WhereClause(&t.generics)));
let required = t.items.iter()
.filter(|m| {
match **m {
clean::RequiredMethod(_) => true,
_ => false,
}
})
.collect::<Vec<&clean::TraitMethod>>();
let provided = t.items.iter()
.filter(|m| {
match **m {
clean::ProvidedMethod(_) => true,
_ => false,
}
})
.collect::<Vec<&clean::TraitMethod>>();

let types = t.items.iter().filter(|m| m.is_type()).collect::<Vec<_>>();
let required = t.items.iter().filter(|m| m.is_req()).collect::<Vec<_>>();
let provided = t.items.iter().filter(|m| m.is_def()).collect::<Vec<_>>();

if t.items.len() == 0 {
try!(write!(w, "{{ }}"));
} else {
try!(write!(w, "{{\n"));
for t in types.iter() {
try!(write!(w, " "));
try!(render_method(w, t.item()));
try!(write!(w, ";\n"));
}
if types.len() > 0 && required.len() > 0 {
try!(w.write("\n".as_bytes()));
}
for m in required.iter() {
try!(write!(w, " "));
try!(render_method(w, m.item()));
Expand Down Expand Up @@ -1738,6 +1734,17 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
Ok(())
}

if types.len() > 0 {
try!(write!(w, "
<h2 id='associated-types'>Associated Types</h2>
<div class='methods'>
"));
for t in types.iter() {
try!(trait_item(w, *t));
}
try!(write!(w, "</div>"));
}

// Output the documentation for each function individually
if required.len() > 0 {
try!(write!(w, "
Expand Down Expand Up @@ -1792,7 +1799,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
}

fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result {
fn fun(w: &mut fmt::Formatter, it: &clean::Item, fn_style: ast::FnStyle,
fn method(w: &mut fmt::Formatter, it: &clean::Item, fn_style: ast::FnStyle,
g: &clean::Generics, selfty: &clean::SelfTy,
d: &clean::FnDecl) -> fmt::Result {
write!(w, "{}fn <a href='#{ty}.{name}' class='fnname'>{name}</a>\
Expand All @@ -1807,14 +1814,28 @@ fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result {
decl = Method(selfty, d),
where_clause = WhereClause(g))
}
fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item,
typ: &clean::TyParam) -> fmt::Result {
try!(write!(w, "type {}", it.name.as_ref().unwrap()));
if typ.bounds.len() > 0 {
try!(write!(w, ": {}", TyParamBounds(&*typ.bounds)))
}
if let Some(ref default) = typ.default {
try!(write!(w, " = {}", default));
}
Ok(())
}
match meth.inner {
clean::TyMethodItem(ref m) => {
fun(w, meth, m.fn_style, &m.generics, &m.self_, &m.decl)
method(w, meth, m.fn_style, &m.generics, &m.self_, &m.decl)
}
clean::MethodItem(ref m) => {
fun(w, meth, m.fn_style, &m.generics, &m.self_, &m.decl)
method(w, meth, m.fn_style, &m.generics, &m.self_, &m.decl)
}
_ => unreachable!()
clean::AssociatedTypeItem(ref typ) => {
assoc_type(w, meth, typ)
}
_ => panic!("render_method called on non-method")
}
}

Expand Down Expand Up @@ -2071,11 +2092,26 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {

fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item, dox: bool)
-> fmt::Result {
try!(write!(w, "<h4 id='method.{}' class='method'>{}<code>",
*item.name.as_ref().unwrap(),
ConciseStability(&item.stability)));
try!(render_method(w, item));
try!(write!(w, "</code></h4>\n"));
match item.inner {
clean::MethodItem(..) | clean::TyMethodItem(..) => {
try!(write!(w, "<h4 id='method.{}' class='{}'>{}<code>",
*item.name.as_ref().unwrap(),
shortty(item),
ConciseStability(&item.stability)));
try!(render_method(w, item));
try!(write!(w, "</code></h4>\n"));
}
clean::TypedefItem(ref tydef) => {
let name = item.name.as_ref().unwrap();
try!(write!(w, "<h4 id='assoc_type.{}' class='{}'>{}<code>",
*name,
shortty(item),
ConciseStability(&item.stability)));
try!(write!(w, "type {} = {}", name, tydef.type_));
try!(write!(w, "</code></h4>\n"));
}
_ => panic!("can't make docs for trait item with name {}", item.name)
}
match item.doc_value() {
Some(s) if dox => {
try!(write!(w, "<div class='docblock'>{}</div>", Markdown(s)));
Expand All @@ -2085,7 +2121,7 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
}
}

try!(write!(w, "<div class='impl-methods'>"));
try!(write!(w, "<div class='impl-items'>"));
for trait_item in i.impl_.items.iter() {
try!(doctraititem(w, trait_item, true));
}
Expand All @@ -2107,6 +2143,8 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {

// If we've implemented a trait, then also emit documentation for all
// default methods which weren't overridden in the implementation block.
// FIXME: this also needs to be done for associated types, whenever defaults
// for them work.
match i.impl_.trait_ {
Some(clean::ResolvedPath { did, .. }) => {
try!({
Expand Down
13 changes: 7 additions & 6 deletions src/librustdoc/html/static/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ h2 {
h3 {
font-size: 1.3em;
}
h1, h2, h3:not(.impl):not(.method), h4:not(.method) {
h1, h2, h3:not(.impl):not(.method):not(.type), h4:not(.method):not(.type) {
color: black;
font-weight: 500;
margin: 20px 0 15px 0;
Expand All @@ -94,15 +94,15 @@ h1.fqn {
border-bottom: 1px dashed #D5D5D5;
margin-top: 0;
}
h2, h3:not(.impl):not(.method), h4:not(.method) {
h2, h3:not(.impl):not(.method):not(.type), h4:not(.method):not(.type) {
border-bottom: 1px solid #DDDDDD;
}
h3.impl, h3.method, h4.method {
h3.impl, h3.method, h4.method, h3.type, h4.type {
font-weight: 600;
margin-top: 10px;
margin-bottom: 10px;
}
h3.impl, h3.method {
h3.impl, h3.method, h3.type {
margin-top: 15px;
}
h1, h2, h3, h4, section.sidebar, a.source, .search-input, .content table :not(code)>a, .collapse-toggle {
Expand Down Expand Up @@ -235,6 +235,7 @@ nav.sub {
.content .highlighted.fn { background-color: #c6afb3; }
.content .highlighted.method { background-color: #c6afb3; }
.content .highlighted.tymethod { background-color: #c6afb3; }
.content .highlighted.type { background-color: #c6afb3; }
.content .highlighted.ffi { background-color: #c6afb3; }

.docblock.short.nowrap {
Expand Down Expand Up @@ -307,7 +308,7 @@ nav.sub {
}
.content .methods .docblock { margin-left: 40px; }

.content .impl-methods .docblock { margin-left: 40px; }
.content .impl-items .docblock { margin-left: 40px; }

nav {
border-bottom: 1px solid #e0e0e0;
Expand Down Expand Up @@ -442,7 +443,7 @@ h1 .stability {
padding: 4px 10px;
}

.impl-methods .stability, .methods .stability {
.impl-items .stability, .methods .stability {
margin-right: 20px;
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#![crate_type = "rlib"]

#![allow(unknown_features)]
#![feature(globs, macro_rules, phase, slicing_syntax, tuple_indexing)]
#![feature(globs, if_let, macro_rules, phase, slicing_syntax, tuple_indexing)]

extern crate arena;
extern crate getopts;
Expand Down