rustdoc: Don't inline all impls all at once

Right now whenever rustdoc inlines a struct or enum from another crate it ends
up inlining *all* `impl` items found in the other crate at the same time. The
rationale for this was to discover all trait impls which are otherwise not
probed for. This unfortunately picks up a lot of impls of public traits for
private types, causing lots of broken links.

This commit instead hoards all of those inlined impls into a temporary storage
location which is then selectively drawn from whenever we inline a new type.
This should ensure that we still inline all relevant impls while avoiding all
private ones.
This commit is contained in:
Alex Crichton 2016-03-08 11:20:16 -08:00
parent 8aa268e731
commit e9cb96a56a
4 changed files with 30 additions and 6 deletions

View File

@ -222,7 +222,8 @@ fn build_type(cx: &DocContext, tcx: &TyCtxt, did: DefId) -> clean::ItemEnum {
}, false)
}
pub fn build_impls(cx: &DocContext, tcx: &TyCtxt,
pub fn build_impls(cx: &DocContext,
tcx: &TyCtxt,
did: DefId) -> Vec<clean::Item> {
tcx.populate_inherent_implementations_for_type_if_necessary(did);
let mut impls = Vec::new();
@ -241,10 +242,12 @@ pub fn build_impls(cx: &DocContext, tcx: &TyCtxt,
// Primarily, the impls will be used to populate the documentation for this
// type being inlined, but impls can also be used when generating
// documentation for primitives (no way to find those specifically).
if cx.populated_crate_impls.borrow_mut().insert(did.krate) {
if !cx.all_crate_impls.borrow_mut().contains_key(&did.krate) {
let mut impls = Vec::new();
for item in tcx.sess.cstore.crate_top_level_items(did.krate) {
populate_impls(cx, tcx, item.def, &mut impls);
}
cx.all_crate_impls.borrow_mut().insert(did.krate, impls);
fn populate_impls(cx: &DocContext, tcx: &TyCtxt,
def: cstore::DefLike,
@ -266,6 +269,20 @@ pub fn build_impls(cx: &DocContext, tcx: &TyCtxt,
}
}
let mut candidates = cx.all_crate_impls.borrow_mut();
let candidates = candidates.get_mut(&did.krate).unwrap();
for i in (0..candidates.len()).rev() {
let remove = match candidates[i].inner {
clean::ImplItem(ref i) => {
i.for_.def_id() == Some(did) || i.for_.primitive_type().is_some()
}
_ => continue,
};
if remove {
impls.push(candidates.swap_remove(i));
}
}
return impls;
}

View File

@ -1499,6 +1499,13 @@ impl Type {
_ => None,
}
}
fn def_id(&self) -> Option<DefId> {
match *self {
ResolvedPath { did, .. } => Some(did),
_ => None,
}
}
}
impl PrimitiveType {

View File

@ -56,7 +56,7 @@ pub struct DocContext<'a, 'tcx: 'a> {
pub external_traits: RefCell<Option<HashMap<DefId, clean::Trait>>>,
pub external_typarams: RefCell<Option<HashMap<DefId, String>>>,
pub inlined: RefCell<Option<HashSet<DefId>>>,
pub populated_crate_impls: RefCell<HashSet<ast::CrateNum>>,
pub all_crate_impls: RefCell<HashMap<ast::CrateNum, Vec<clean::Item>>>,
pub deref_trait_did: Cell<Option<DefId>>,
}
@ -179,7 +179,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
external_typarams: RefCell::new(Some(HashMap::new())),
external_paths: RefCell::new(Some(HashMap::new())),
inlined: RefCell::new(Some(HashSet::new())),
populated_crate_impls: RefCell::new(HashSet::new()),
all_crate_impls: RefCell::new(HashMap::new()),
deref_trait_did: Cell::new(None),
};
debug!("crate: {:?}", ctxt.map.krate());

View File

@ -11,7 +11,7 @@
#![allow(deprecated)]
use std::cell::{RefCell, Cell};
use std::collections::{HashSet, HashMap};
use std::collections::HashMap;
use std::dynamic_lib::DynamicLibrary;
use std::env;
use std::ffi::OsString;
@ -114,7 +114,7 @@ pub fn run(input: &str,
external_traits: RefCell::new(None),
external_typarams: RefCell::new(None),
inlined: RefCell::new(None),
populated_crate_impls: RefCell::new(HashSet::new()),
all_crate_impls: RefCell::new(HashMap::new()),
deref_trait_did: Cell::new(None),
};