Skip to content

Commit

Permalink
auto merge of #15586 : aturon/rust/stability-dashboard, r=alexcrichton
Browse files Browse the repository at this point in the history
This PR adds a crate-level dashboard summarizing the stability levels of all items for all submodules of the crate.

The information is also written as a json file, intended for consumption by pages like http://huonw.github.io/isrustfastyet/

Along the way, fixes a few bugs in stability tracking and places where rustdoc was not pulling the existing stability data.

Closes #13541
  • Loading branch information
bors committed Jul 11, 2014
2 parents 75c1fb5 + 0487e63 commit 1e40115
Show file tree
Hide file tree
Showing 8 changed files with 327 additions and 14 deletions.
4 changes: 4 additions & 0 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,10 @@ fn encode_info_for_struct(ecx: &EncodeContext,
encode_name(ebml_w, nm);
encode_type(ecx, ebml_w, node_id_to_type(tcx, id));
encode_def_id(ebml_w, local_def(id));

let stab = stability::lookup(ecx.tcx, field.id);
encode_stability(ebml_w, stab);

ebml_w.end_tag();
}
index
Expand Down
12 changes: 9 additions & 3 deletions src/librustc/middle/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
use util::nodemap::{NodeMap, DefIdMap};
use syntax::codemap::Span;
use syntax::{attr, visit};
use syntax::ast;
use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant};
use syntax::ast::{Item, Required, Provided, TraitMethod, TypeMethod, Method};
use syntax::ast::{Generics, StructDef, Ident};
use syntax::ast::{Generics, StructDef, StructField, Ident};
use syntax::ast_util::is_local;
use syntax::attr::Stability;
use syntax::visit::{FnKind, FkMethod, Visitor};
Expand Down Expand Up @@ -91,6 +92,11 @@ impl Visitor<Option<Stability>> for Annotator {
s.ctor_id.map(|id| self.annotate(id, &[], parent.clone()));
visit::walk_struct_def(self, s, parent)
}

fn visit_struct_field(&mut self, s: &StructField, parent: Option<Stability>) {
let stab = self.annotate(s.node.id, s.node.attrs.as_slice(), parent);
visit::walk_struct_field(self, s, stab)
}
}

impl Index {
Expand All @@ -102,8 +108,8 @@ impl Index {
extern_cache: DefIdMap::new()
}
};
visit::walk_crate(&mut annotator, krate,
attr::find_stability(krate.attrs.as_slice()));
let stab = annotator.annotate(ast::CRATE_NODE_ID, krate.attrs.as_slice(), None);
visit::walk_crate(&mut annotator, krate, stab);
annotator.index
}
}
Expand Down
13 changes: 8 additions & 5 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1461,12 +1461,15 @@ impl Clean<Item> for ty::VariantInfo {
name: Some(name.clean()),
attrs: Vec::new(),
visibility: Some(ast::Public),
stability: get_stability(self.id),
// FIXME: this is not accurate, we need an id for
// the specific field but we're using the id
// for the whole variant. Nothing currently
// uses this so we should be good for now.
// for the whole variant. Thus we read the
// stability from the whole variant as well.
// Struct variants are experimental and need
// more infrastructure work before we can get
// at the needed information here.
def_id: self.id,
stability: get_stability(self.id),
inner: StructFieldItem(
TypedStructField(ty.clean())
)
Expand All @@ -1482,7 +1485,7 @@ impl Clean<Item> for ty::VariantInfo {
visibility: Some(ast::Public),
def_id: self.id,
inner: VariantItem(Variant { kind: kind }),
stability: None,
stability: get_stability(self.id),
}
}
}
Expand Down Expand Up @@ -1890,7 +1893,7 @@ impl Clean<Item> for ast::ForeignItem {
source: self.span.clean(),
def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(),
stability: None,
stability: get_stability(ast_util::local_def(self.id)),
inner: inner,
}
}
Expand Down
70 changes: 70 additions & 0 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use syntax::ast;
use syntax::ast_util;

use clean;
use stability_summary::ModuleSummary;
use html::item_type;
use html::item_type::ItemType;
use html::render;
Expand Down Expand Up @@ -631,3 +632,72 @@ impl<'a> fmt::Show for ConciseStability<'a> {
}
}
}

impl fmt::Show for ModuleSummary {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt_inner<'a>(f: &mut fmt::Formatter,
context: &mut Vec<&'a str>,
m: &'a ModuleSummary)
-> fmt::Result {
let cnt = m.counts;
let tot = cnt.total();
if tot == 0 { return Ok(()) }

context.push(m.name.as_slice());
let path = context.connect("::");

// the total width of each row's stability summary, in pixels
let width = 500;

try!(write!(f, "<tr>"));
try!(write!(f, "<td class='summary'>\
<a class='summary' href='{}'>{}</a></td>",
Vec::from_slice(context.slice_from(1))
.append_one("index.html").connect("/"),
path));
try!(write!(f, "<td>"));
try!(write!(f, "<span class='summary Stable' \
style='width: {}px; display: inline-block'>&nbsp</span>",
(width * cnt.stable)/tot));
try!(write!(f, "<span class='summary Unstable' \
style='width: {}px; display: inline-block'>&nbsp</span>",
(width * cnt.unstable)/tot));
try!(write!(f, "<span class='summary Experimental' \
style='width: {}px; display: inline-block'>&nbsp</span>",
(width * cnt.experimental)/tot));
try!(write!(f, "<span class='summary Deprecated' \
style='width: {}px; display: inline-block'>&nbsp</span>",
(width * cnt.deprecated)/tot));
try!(write!(f, "<span class='summary Unmarked' \
style='width: {}px; display: inline-block'>&nbsp</span>",
(width * cnt.unmarked)/tot));
try!(write!(f, "</td></tr>"));

for submodule in m.submodules.iter() {
try!(fmt_inner(f, context, submodule));
}
context.pop();
Ok(())
}

let mut context = Vec::new();

try!(write!(f,
r"<h1 class='fqn'>Stability dashboard: crate <a class='mod' href='index.html'>{}</a></h1>
This dashboard summarizes the stability levels for all of the public modules of
the crate, according to the total number of items at each level in the module and its children:
<blockquote>
<a class='stability Stable'></a> stable,<br/>
<a class='stability Unstable'></a> unstable,<br/>
<a class='stability Experimental'></a> experimental,<br/>
<a class='stability Deprecated'></a> deprecated,<br/>
<a class='stability Unmarked'></a> unmarked
</blockquote>
The counts do not include methods or trait
implementations that are visible only through a re-exported type.",
self.name));
try!(write!(f, "<table>"))
try!(fmt_inner(f, &mut context, self));
write!(f, "</table>")
}
}
56 changes: 51 additions & 5 deletions src/librustdoc/html/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ use std::sync::Arc;

use externalfiles::ExternalHtml;

use serialize::json;
use serialize::Encodable;
use serialize::json::ToJson;
use syntax::ast;
use syntax::ast_util;
Expand All @@ -59,6 +61,7 @@ use html::item_type;
use html::layout;
use html::markdown::Markdown;
use html::markdown;
use stability_summary;

/// Major driving force in all rustdoc rendering. This contains information
/// about where in the tree-like hierarchy rendering is occurring and controls
Expand Down Expand Up @@ -249,6 +252,11 @@ pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: Path) ->

try!(mkdir(&cx.dst));

// Crawl the crate, building a summary of the stability levels. NOTE: this
// summary *must* be computed with the original `krate`; the folding below
// removes the impls from their modules.
let summary = stability_summary::build(&krate);

// Crawl the crate attributes looking for attributes which control how we're
// going to emit HTML
match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(&[])) {
Expand Down Expand Up @@ -361,7 +369,7 @@ pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: Path) ->
let krate = try!(render_sources(&mut cx, krate));

// And finally render the whole crate's documentation
cx.krate(krate)
cx.krate(krate, summary)
}

fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::IoResult<String> {
Expand Down Expand Up @@ -1045,13 +1053,34 @@ impl Context {
///
/// This currently isn't parallelized, but it'd be pretty easy to add
/// parallelization to this function.
fn krate(self, mut krate: clean::Crate) -> io::IoResult<()> {
fn krate(mut self, mut krate: clean::Crate,
stability: stability_summary::ModuleSummary) -> io::IoResult<()> {
let mut item = match krate.module.take() {
Some(i) => i,
None => return Ok(())
};
item.name = Some(krate.name);

// render stability dashboard
try!(self.recurse(stability.name.clone(), |this| {
let json_dst = &this.dst.join("stability.json");
let mut json_out = BufferedWriter::new(try!(File::create(json_dst)));
try!(stability.encode(&mut json::Encoder::new(&mut json_out)));

let title = stability.name.clone().append(" - Stability dashboard");
let page = layout::Page {
ty: "mod",
root_path: this.root_path.as_slice(),
title: title.as_slice(),
};
let html_dst = &this.dst.join("stability.html");
let mut html_out = BufferedWriter::new(try!(File::create(html_dst)));
layout::render(&mut html_out, &this.layout, &page,
&Sidebar{ cx: this, item: &item },
&stability)
}));

// render the crate documentation
let mut work = vec!((self, item));
loop {
match work.pop() {
Expand All @@ -1061,6 +1090,7 @@ impl Context {
None => break,
}
}

Ok(())
}

Expand Down Expand Up @@ -1233,6 +1263,8 @@ impl<'a> Item<'a> {
}
}



impl<'a> fmt::Show for Item<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
// Write the breadcrumb trail header for the top
Expand Down Expand Up @@ -1269,6 +1301,17 @@ impl<'a> fmt::Show for Item<'a> {
// Write stability level
try!(write!(fmt, "{}", Stability(&self.item.stability)));

// Links to out-of-band information, i.e. src and stability dashboard
try!(write!(fmt, "<span class='out-of-band'>"));

// Write stability dashboard link
match self.item.inner {
clean::ModuleItem(ref m) if m.is_crate => {
try!(write!(fmt, "<a href='stability.html'>[stability dashboard]</a> "));
}
_ => {}
};

// Write `src` tag
//
// When this item is part of a `pub use` in a downstream crate, the
Expand All @@ -1278,14 +1321,15 @@ impl<'a> fmt::Show for Item<'a> {
if self.cx.include_sources && !is_primitive {
match self.href() {
Some(l) => {
try!(write!(fmt,
"<a class='source' id='src-{}' \
href='{}'>[src]</a>",
try!(write!(fmt, "<a id='src-{}' href='{}'>[src]</a>",
self.item.def_id.node, l));
}
None => {}
}
}

try!(write!(fmt, "</span>"));

try!(write!(fmt, "</h1>\n"));

match self.item.inner {
Expand Down Expand Up @@ -1355,6 +1399,7 @@ fn document(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
fn item_module(w: &mut fmt::Formatter, cx: &Context,
item: &clean::Item, items: &[clean::Item]) -> fmt::Result {
try!(document(w, item));

let mut indices = range(0, items.len()).filter(|i| {
!ignore_private_item(&items[*i])
}).collect::<Vec<uint>>();
Expand Down Expand Up @@ -1514,6 +1559,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
}
}
}

write!(w, "</table>")
}

Expand Down
11 changes: 10 additions & 1 deletion src/librustdoc/html/static/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ nav.sub {
.docblock h2 { font-size: 1.15em; }
.docblock h3, .docblock h4, .docblock h5 { font-size: 1em; }

.content .source {
.content .out-of-band {
float: right;
font-size: 23px;
}
Expand Down Expand Up @@ -409,6 +409,15 @@ h1 .stability {
.stability.Locked { border-color: #0084B6; color: #00668c; }
.stability.Unmarked { border-color: #FFFFFF; }

.summary {
padding-right: 0px;
}
.summary.Deprecated { background-color: #A071A8; }
.summary.Experimental { background-color: #D46D6A; }
.summary.Unstable { background-color: #D4B16A; }
.summary.Stable { background-color: #54A759; }
.summary.Unmarked { background-color: #FFFFFF; }

:target { background: #FDFFD3; }

/* Code highlighting */
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub mod html {
pub mod markdown;
pub mod passes;
pub mod plugins;
pub mod stability_summary;
pub mod visit_ast;
pub mod test;
mod flock;
Expand Down
Loading

0 comments on commit 1e40115

Please sign in to comment.