Skip to content

Commit

Permalink
rustdoc: link to cross-crate sources directly.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Nov 30, 2016
1 parent 177913b commit 9001918
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 218 deletions.
10 changes: 5 additions & 5 deletions src/librustdoc/clean/inline.rs
Expand Up @@ -115,7 +115,7 @@ fn try_inline_def(cx: &DocContext, def: Def) -> Option<Vec<clean::Item>> {
let did = def.def_id();
cx.renderinfo.borrow_mut().inlined.insert(did);
ret.push(clean::Item {
source: clean::Span::empty(),
source: tcx.def_span(did).clean(cx),
name: Some(tcx.item_name(did).to_string()),
attrs: load_attrs(cx, did),
inner: inner,
Expand Down Expand Up @@ -321,7 +321,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
clean::RegionBound(..) => unreachable!(),
},
}),
source: clean::Span::empty(),
source: tcx.def_span(did).clean(cx),
name: None,
attrs: attrs,
visibility: Some(clean::Inherited),
Expand Down Expand Up @@ -357,7 +357,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
tcx.item_type(item.def_id).clean(cx),
default,
),
source: clean::Span::empty(),
source: tcx.def_span(item.def_id).clean(cx),
attrs: clean::Attributes::default(),
visibility: None,
stability: tcx.lookup_stability(item.def_id).clean(cx),
Expand Down Expand Up @@ -404,7 +404,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
Some(clean::Item {
name: Some(item.name.clean(cx)),
inner: clean::TypedefItem(typedef, true),
source: clean::Span::empty(),
source: tcx.def_span(item.def_id).clean(cx),
attrs: clean::Attributes::default(),
visibility: None,
stability: tcx.lookup_stability(item.def_id).clean(cx),
Expand Down Expand Up @@ -442,7 +442,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
items: trait_items,
polarity: Some(polarity.clean(cx)),
}),
source: clean::Span::empty(),
source: tcx.def_span(did).clean(cx),
name: None,
attrs: attrs,
visibility: Some(clean::Inherited),
Expand Down
175 changes: 82 additions & 93 deletions src/librustdoc/clean/mod.rs
Expand Up @@ -27,11 +27,10 @@ use syntax::ptr::P;
use syntax::symbol::keywords;
use syntax_pos::{self, DUMMY_SP, Pos};

use rustc_trans::back::link;
use rustc::middle::privacy::AccessLevels;
use rustc::middle::resolve_lifetime::DefRegion::*;
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::{self, DefId, DefIndex, CRATE_DEF_INDEX};
use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::hir::print as pprust;
use rustc::ty::subst::Substs;
use rustc::ty::{self, AdtKind};
Expand All @@ -45,7 +44,6 @@ use std::rc::Rc;
use std::slice;
use std::sync::Arc;
use std::u32;
use std::env::current_dir;
use std::mem;

use core::DocContext;
Expand Down Expand Up @@ -110,19 +108,16 @@ pub struct Crate {
pub name: String,
pub src: PathBuf,
pub module: Option<Item>,
pub externs: Vec<(def_id::CrateNum, ExternalCrate)>,
pub primitives: Vec<PrimitiveType>,
pub externs: Vec<(CrateNum, ExternalCrate)>,
pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
pub access_levels: Arc<AccessLevels<DefId>>,
// These are later on moved into `CACHEKEY`, leaving the map empty.
// Only here so that they can be filtered through the rustdoc passes.
pub external_traits: FxHashMap<DefId, Trait>,
}

struct CrateNum(def_id::CrateNum);

impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
fn clean(&self, cx: &DocContext) -> Crate {
use rustc::session::config::Input;
use ::visit_lib::LibEmbargoVisitor;

{
Expand All @@ -133,83 +128,41 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {

let mut externs = Vec::new();
for cnum in cx.sess().cstore.crates() {
externs.push((cnum, CrateNum(cnum).clean(cx)));
externs.push((cnum, cnum.clean(cx)));
// Analyze doc-reachability for extern items
LibEmbargoVisitor::new(cx).visit_lib(cnum);
}
externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));

// Figure out the name of this crate
let input = &cx.input;
let name = link::find_crate_name(None, &self.attrs, input);

// Clean the crate, translating the entire libsyntax AST to one that is
// understood by rustdoc.
let mut module = self.module.clean(cx);

// Collect all inner modules which are tagged as implementations of
// primitives.
//
// Note that this loop only searches the top-level items of the crate,
// and this is intentional. If we were to search the entire crate for an
// item tagged with `#[doc(primitive)]` then we would also have to
// search the entirety of external modules for items tagged
// `#[doc(primitive)]`, which is a pretty inefficient process (decoding
// all that metadata unconditionally).
//
// In order to keep the metadata load under control, the
// `#[doc(primitive)]` feature is explicitly designed to only allow the
// primitive tags to show up as the top level items in a crate.
//
// Also note that this does not attempt to deal with modules tagged
// duplicately for the same primitive. This is handled later on when
// rendering by delegating everything to a hash map.
let mut primitives = Vec::new();
let ExternalCrate { name, src, primitives, .. } = LOCAL_CRATE.clean(cx);
{
let m = match module.inner {
ModuleItem(ref mut m) => m,
_ => unreachable!(),
};
let mut tmp = Vec::new();
for child in &mut m.items {
if !child.is_mod() {
continue;
}
let prim = match PrimitiveType::find(&child.attrs) {
Some(prim) => prim,
None => continue,
};
primitives.push(prim);
tmp.push(Item {
m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| {
Item {
source: Span::empty(),
name: Some(prim.to_url_str().to_string()),
attrs: child.attrs.clone(),
attrs: attrs.clone(),
visibility: Some(Public),
stability: None,
deprecation: None,
def_id: DefId::local(prim.to_def_index()),
def_id: def_id,
inner: PrimitiveItem(prim),
});
}
m.items.extend(tmp);
}

let src = match cx.input {
Input::File(ref path) => {
if path.is_absolute() {
path.clone()
} else {
current_dir().unwrap().join(path)
}
},
Input::Str { ref name, .. } => PathBuf::from(name.clone()),
};
}));
}

let mut access_levels = cx.access_levels.borrow_mut();
let mut external_traits = cx.external_traits.borrow_mut();

Crate {
name: name.to_string(),
name: name,
src: src,
module: Some(module),
externs: externs,
Expand All @@ -223,21 +176,78 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct ExternalCrate {
pub name: String,
pub src: PathBuf,
pub attrs: Attributes,
pub primitives: Vec<PrimitiveType>,
pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
}

impl Clean<ExternalCrate> for CrateNum {
fn clean(&self, cx: &DocContext) -> ExternalCrate {
let mut primitives = Vec::new();
let root = DefId { krate: self.0, index: CRATE_DEF_INDEX };
for item in cx.tcx.sess.cstore.item_children(root) {
let attrs = inline::load_attrs(cx, item.def.def_id());
PrimitiveType::find(&attrs).map(|prim| primitives.push(prim));
}
let root = DefId { krate: *self, index: CRATE_DEF_INDEX };
let krate_span = cx.tcx.def_span(root);
let krate_src = cx.sess().codemap().span_to_filename(krate_span);

// Collect all inner modules which are tagged as implementations of
// primitives.
//
// Note that this loop only searches the top-level items of the crate,
// and this is intentional. If we were to search the entire crate for an
// item tagged with `#[doc(primitive)]` then we would also have to
// search the entirety of external modules for items tagged
// `#[doc(primitive)]`, which is a pretty inefficient process (decoding
// all that metadata unconditionally).
//
// In order to keep the metadata load under control, the
// `#[doc(primitive)]` feature is explicitly designed to only allow the
// primitive tags to show up as the top level items in a crate.
//
// Also note that this does not attempt to deal with modules tagged
// duplicately for the same primitive. This is handled later on when
// rendering by delegating everything to a hash map.
let as_primitive = |def: Def| {
if let Def::Mod(def_id) = def {
let attrs = cx.tcx.get_attrs(def_id).clean(cx);
let mut prim = None;
for attr in attrs.lists("doc") {
if let Some(v) = attr.value_str() {
if attr.check_name("primitive") {
prim = PrimitiveType::from_str(&v.as_str());
if prim.is_some() {
break;
}
}
}
}
return prim.map(|p| (def_id, p, attrs));
}
None
};
let primitives = if root.is_local() {
cx.tcx.map.krate().module.item_ids.iter().filter_map(|&id| {
let item = cx.tcx.map.expect_item(id.id);
match item.node {
hir::ItemMod(_) => {
as_primitive(Def::Mod(cx.tcx.map.local_def_id(id.id)))
}
hir::ItemUse(ref path, hir::UseKind::Single)
if item.vis == hir::Visibility::Public => {
as_primitive(path.def).map(|(_, prim, attrs)| {
// Pretend the primitive is local.
(cx.tcx.map.local_def_id(id.id), prim, attrs)
})
}
_ => None
}
}).collect()
} else {
cx.tcx.sess.cstore.item_children(root).iter().map(|item| item.def)
.filter_map(as_primitive).collect()
};

ExternalCrate {
name: cx.sess().cstore.crate_name(self.0).to_string(),
attrs: cx.sess().cstore.item_attrs(root).clean(cx),
name: cx.tcx.crate_name(*self).to_string(),
src: PathBuf::from(krate_src),
attrs: cx.tcx.get_attrs(root).clean(cx),
primitives: primitives,
}
}
Expand Down Expand Up @@ -1460,7 +1470,7 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
deprecation: get_deprecation(cx, self.def_id),
def_id: self.def_id,
attrs: inline::load_attrs(cx, self.def_id),
source: Span::empty(),
source: cx.tcx.def_span(self.def_id).clean(cx),
inner: inner,
}
}
Expand Down Expand Up @@ -1618,19 +1628,6 @@ impl PrimitiveType {
}
}

fn find(attrs: &Attributes) -> Option<PrimitiveType> {
for attr in attrs.lists("doc") {
if let Some(v) = attr.value_str() {
if attr.check_name("primitive") {
if let ret@Some(..) = PrimitiveType::from_str(&v.as_str()) {
return ret;
}
}
}
}
None
}

pub fn as_str(&self) -> &'static str {
match *self {
PrimitiveType::Isize => "isize",
Expand Down Expand Up @@ -1658,14 +1655,6 @@ impl PrimitiveType {
pub fn to_url_str(&self) -> &'static str {
self.as_str()
}

/// Creates a rustdoc-specific node id for primitive types.
///
/// These node ids are generally never used by the AST itself.
pub fn to_def_index(&self) -> DefIndex {
let x = u32::MAX - 1 - (*self as u32);
DefIndex::new(x as usize)
}
}

impl From<ast::IntTy> for PrimitiveType {
Expand Down Expand Up @@ -1948,7 +1937,7 @@ impl<'tcx> Clean<Item> for ty::FieldDefData<'tcx, 'static> {
Item {
name: Some(self.name).clean(cx),
attrs: cx.tcx.get_attrs(self.did).clean(cx),
source: Span::empty(),
source: cx.tcx.def_span(self.did).clean(cx),
visibility: self.vis.clean(cx),
stability: get_stability(cx, self.did),
deprecation: get_deprecation(cx, self.did),
Expand Down Expand Up @@ -2115,7 +2104,7 @@ impl<'tcx> Clean<Item> for ty::VariantDefData<'tcx, 'static> {
fields_stripped: false,
fields: self.fields.iter().map(|field| {
Item {
source: Span::empty(),
source: cx.tcx.def_span(field.did).clean(cx),
name: Some(field.name.clean(cx)),
attrs: cx.tcx.get_attrs(field.did).clean(cx),
visibility: field.vis.clean(cx),
Expand All @@ -2131,7 +2120,7 @@ impl<'tcx> Clean<Item> for ty::VariantDefData<'tcx, 'static> {
Item {
name: Some(self.name.clean(cx)),
attrs: inline::load_attrs(cx, self.did),
source: Span::empty(),
source: cx.tcx.def_span(self.did).clean(cx),
visibility: Some(Inherited),
def_id: self.did,
inner: VariantItem(Variant { kind: kind }),
Expand Down
2 changes: 0 additions & 2 deletions src/librustdoc/core.rs
Expand Up @@ -45,7 +45,6 @@ pub type ExternalPaths = FxHashMap<DefId, (Vec<String>, clean::TypeKind)>;

pub struct DocContext<'a, 'tcx: 'a> {
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub input: Input,
pub populated_all_crate_impls: Cell<bool>,
// Note that external items for which `doc(hidden)` applies to are shown as
// non-reachable while local items aren't. This is because we're reusing
Expand Down Expand Up @@ -187,7 +186,6 @@ pub fn run_core(search_paths: SearchPaths,

let ctxt = DocContext {
tcx: tcx,
input: input,
populated_all_crate_impls: Cell::new(false),
access_levels: RefCell::new(access_levels),
external_traits: Default::default(),
Expand Down

0 comments on commit 9001918

Please sign in to comment.