rust/src/librustdoc/fold.rs
Alex Crichton c746c503f0 rustdoc: Fill in external trait methods
This commit alters rustdoc to crawl the metadata of upstream libraries in order
to fill in default methods for traits implemented in downstream crates. This,
for example, documents the `insert` function on hash maps.

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

While not perfect, it appears that presenting this documentation through rustdoc
is much better than nothing, so I wanted to land this to allow iteration on it
later on.
2014-05-22 09:46:22 -07:00

103 lines
4.0 KiB
Rust

// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use clean::*;
use std::iter::Extendable;
use std::mem::{replace, swap};
pub trait DocFolder {
fn fold_item(&mut self, item: Item) -> Option<Item> {
self.fold_item_recur(item)
}
/// don't override!
fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
let Item { attrs, name, source, visibility, def_id, inner } = item;
let inner = inner;
let inner = match inner {
StructItem(mut i) => {
let mut foo = Vec::new(); swap(&mut foo, &mut i.fields);
let num_fields = foo.len();
i.fields.extend(foo.move_iter().filter_map(|x| self.fold_item(x)));
i.fields_stripped |= num_fields != i.fields.len();
StructItem(i)
},
ModuleItem(i) => {
ModuleItem(self.fold_mod(i))
},
EnumItem(mut i) => {
let mut foo = Vec::new(); swap(&mut foo, &mut i.variants);
let num_variants = foo.len();
i.variants.extend(foo.move_iter().filter_map(|x| self.fold_item(x)));
i.variants_stripped |= num_variants != i.variants.len();
EnumItem(i)
},
TraitItem(mut i) => {
fn vtrm<T: DocFolder>(this: &mut T, trm: TraitMethod) -> Option<TraitMethod> {
match trm {
Required(it) => {
match this.fold_item(it) {
Some(x) => return Some(Required(x)),
None => return None,
}
},
Provided(it) => {
match this.fold_item(it) {
Some(x) => return Some(Provided(x)),
None => return None,
}
},
}
}
let mut foo = Vec::new(); swap(&mut foo, &mut i.methods);
i.methods.extend(foo.move_iter().filter_map(|x| vtrm(self, x)));
TraitItem(i)
},
ImplItem(mut i) => {
let mut foo = Vec::new(); swap(&mut foo, &mut i.methods);
i.methods.extend(foo.move_iter().filter_map(|x| self.fold_item(x)));
ImplItem(i)
},
VariantItem(i) => {
let i2 = i.clone(); // this clone is small
match i.kind {
StructVariant(mut j) => {
let mut foo = Vec::new(); swap(&mut foo, &mut j.fields);
let num_fields = foo.len();
let c = |x| self.fold_item(x);
j.fields.extend(foo.move_iter().filter_map(c));
j.fields_stripped |= num_fields != j.fields.len();
VariantItem(Variant {kind: StructVariant(j), ..i2})
},
_ => VariantItem(i2)
}
},
x => x
};
Some(Item { attrs: attrs, name: name, source: source, inner: inner,
visibility: visibility, def_id: def_id })
}
fn fold_mod(&mut self, m: Module) -> Module {
Module {
is_crate: m.is_crate,
items: m.items.move_iter().filter_map(|i| self.fold_item(i)).collect()
}
}
fn fold_crate(&mut self, mut c: Crate) -> Crate {
c.module = match replace(&mut c.module, None) {
Some(module) => self.fold_item(module), None => None
};
return c;
}
}