Skip to content

Commit

Permalink
rustdoc: Hyperlink cross-crate reexports
Browse files Browse the repository at this point in the history
This should improve the libcore experience quite a bit when looking at the
libstd documentation.
  • Loading branch information
alexcrichton committed May 9, 2014
1 parent aa67254 commit 1ba4971
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 124 deletions.
84 changes: 37 additions & 47 deletions src/librustdoc/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -670,15 +670,7 @@ pub enum Type {
ResolvedPath {
pub path: Path,
pub typarams: Option<Vec<TyParamBound>>,
pub id: ast::NodeId,
},
/// Same as above, but only external variants
ExternalPath {
pub path: Path,
pub typarams: Option<Vec<TyParamBound>>,
pub fqn: Vec<~str>,
pub kind: TypeKind,
pub krate: ast::CrateNum,
pub did: ast::DefId,
},
// I have no idea how to usefully use this.
TyParamBinder(ast::NodeId),
Expand Down Expand Up @@ -715,19 +707,18 @@ pub enum Type {

#[deriving(Clone, Encodable, Decodable)]
pub enum TypeKind {
TypeStruct,
TypeEnum,
TypeTrait,
TypeFunction,
TypeModule,
TypeStatic,
TypeStruct,
TypeTrait,
TypeVariant,
}

impl Clean<Type> for ast::Ty {
fn clean(&self) -> Type {
use syntax::ast::*;
debug!("cleaning type `{:?}`", self);
let ctxt = super::ctxtkey.get().unwrap();
let codemap = ctxt.sess().codemap();
debug!("span corresponds to `{}`", codemap.span_to_str(self.span));
match self.node {
TyNil => Unit,
TyPtr(ref m) => RawPointer(m.mutbl.clean(), box m.ty.clean()),
Expand Down Expand Up @@ -1153,7 +1144,7 @@ pub enum ViewPath {
// use source::*;
GlobImport(ImportSource),
// use source::{a, b, c};
ImportList(ImportSource, Vec<ViewListIdent> ),
ImportList(ImportSource, Vec<ViewListIdent>),
}

#[deriving(Clone, Encodable, Decodable)]
Expand Down Expand Up @@ -1298,48 +1289,47 @@ fn resolve_type(path: Path, tpbs: Option<Vec<TyParamBound> >,
core::NotTyped(_) => return Bool
};
debug!("searching for {:?} in defmap", id);
let d = match tycx.def_map.borrow().find(&id) {
let def = match tycx.def_map.borrow().find(&id) {
Some(&k) => k,
None => {
debug!("could not find {:?} in defmap (`{}`)", id, tycx.map.node_to_str(id));
fail!("Unexpected failure: unresolved id not in defmap (this is a bug!)")
}
None => fail!("unresolved id not in defmap")
};

let (def_id, kind) = match d {
ast::DefFn(i, _) => (i, TypeFunction),
match def {
ast::DefSelfTy(i) => return Self(i),
ast::DefTy(i) => (i, TypeEnum),
ast::DefTrait(i) => {
debug!("saw DefTrait in def_to_id");
(i, TypeTrait)
},
ast::DefPrimTy(p) => match p {
ast::TyStr => return String,
ast::TyBool => return Bool,
_ => return Primitive(p)
},
ast::DefTyParam(i, _) => return Generic(i.node),
ast::DefTyParamBinder(i) => return TyParamBinder(i),
_ => {}
};
let did = register_def(&**cx, def);
ResolvedPath { path: path, typarams: tpbs, did: did }
}

fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId {
let (did, kind) = match def {
ast::DefFn(i, _) => (i, TypeFunction),
ast::DefTy(i) => (i, TypeEnum),
ast::DefTrait(i) => (i, TypeTrait),
ast::DefStruct(i) => (i, TypeStruct),
ast::DefTyParamBinder(i) => {
debug!("found a typaram_binder, what is it? {}", i);
return TyParamBinder(i);
},
x => fail!("resolved type maps to a weird def {:?}", x),
ast::DefMod(i) => (i, TypeModule),
ast::DefStatic(i, _) => (i, TypeStatic),
ast::DefVariant(i, _, _) => (i, TypeEnum),
_ => return ast_util::def_id_of_def(def),
};
if ast_util::is_local(def_id) {
ResolvedPath{ path: path, typarams: tpbs, id: def_id.node }
} else {
let fqn = csearch::get_item_path(tycx, def_id);
let fqn = fqn.move_iter().map(|i| i.to_str()).collect();
ExternalPath {
path: path,
typarams: tpbs,
fqn: fqn,
kind: kind,
krate: def_id.krate,
}
}
if ast_util::is_local(did) { return did }
let tcx = match cx.maybe_typed {
core::Typed(ref t) => t,
core::NotTyped(_) => return did
};
let fqn = csearch::get_item_path(tcx, did);
let fqn = fqn.move_iter().map(|i| i.to_str()).collect();
debug!("recording {} => {}", did, fqn);
cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind));
return did;
}

fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
Expand All @@ -1353,7 +1343,7 @@ fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> {
let cx = super::ctxtkey.get().unwrap();
match cx.maybe_typed {
core::Typed(ref tcx) => {
tcx.def_map.borrow().find(&id).map(|&d| ast_util::def_id_of_def(d))
tcx.def_map.borrow().find(&id).map(|&def| register_def(&**cx, def))
}
core::NotTyped(_) => None
}
Expand Down
11 changes: 10 additions & 1 deletion src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use syntax;

use std::cell::RefCell;
use std::os;
use collections::HashSet;
use collections::{HashSet, HashMap};

use visit_ast::RustdocVisitor;
use clean;
Expand All @@ -31,10 +31,14 @@ pub enum MaybeTyped {
NotTyped(driver::session::Session)
}

pub type ExternalPaths = RefCell<Option<HashMap<ast::DefId,
(Vec<~str>, clean::TypeKind)>>>;

pub struct DocContext {
pub krate: ast::Crate,
pub maybe_typed: MaybeTyped,
pub src: Path,
pub external_paths: ExternalPaths,
}

impl DocContext {
Expand All @@ -49,6 +53,7 @@ impl DocContext {
pub struct CrateAnalysis {
pub exported_items: privacy::ExportedItems,
pub public_items: privacy::PublicItems,
pub external_paths: ExternalPaths,
}

/// Parses, resolves, and typechecks the given crate
Expand Down Expand Up @@ -98,9 +103,11 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<~str>)
krate: krate,
maybe_typed: Typed(ty_cx),
src: cpath.clone(),
external_paths: RefCell::new(Some(HashMap::new())),
}, CrateAnalysis {
exported_items: exported_items,
public_items: public_items,
external_paths: RefCell::new(None),
})
}

Expand All @@ -116,5 +123,7 @@ pub fn run_core(libs: HashSet<Path>, cfgs: Vec<~str>, path: &Path)
v.clean()
};

let external_paths = ctxt.external_paths.borrow_mut().take();
*analysis.external_paths.borrow_mut() = external_paths;
(krate, analysis)
}
61 changes: 19 additions & 42 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,41 +146,28 @@ impl fmt::Show for clean::Path {

/// Used when rendering a `ResolvedPath` structure. This invokes the `path`
/// rendering function with the necessary arguments for linking to a local path.
fn resolved_path(w: &mut io::Writer, id: ast::NodeId, p: &clean::Path,
fn resolved_path(w: &mut io::Writer, did: ast::DefId, p: &clean::Path,
print_all: bool) -> fmt::Result {
path(w, p, print_all,
|_cache, loc| { Some("../".repeat(loc.len())) },
|cache, loc| {
if ast_util::is_local(did) {
Some("../".repeat(loc.len()))
} else {
match *cache.extern_locations.get(&did.krate) {
render::Remote(ref s) => Some(s.clone()),
render::Local => Some("../".repeat(loc.len())),
render::Unknown => None,
}
}
},
|cache| {
match cache.paths.find(&id) {
match cache.paths.find(&did) {
None => None,
Some(&(ref fqp, shortty)) => Some((fqp.clone(), shortty))
}
})
}

/// Used when rendering an `ExternalPath` structure. Like `resolved_path` this
/// will invoke `path` with proper linking-style arguments.
fn external_path(w: &mut io::Writer, p: &clean::Path, print_all: bool,
fqn: &[~str], kind: clean::TypeKind,
krate: ast::CrateNum) -> fmt::Result {
path(w, p, print_all,
|cache, loc| {
match *cache.extern_locations.get(&krate) {
render::Remote(ref s) => Some(s.clone()),
render::Local => Some("../".repeat(loc.len())),
render::Unknown => None,
}
},
|_cache| {
Some((Vec::from_slice(fqn), match kind {
clean::TypeStruct => item_type::Struct,
clean::TypeEnum => item_type::Enum,
clean::TypeFunction => item_type::Function,
clean::TypeTrait => item_type::Trait,
}))
})
}

fn path(w: &mut io::Writer, path: &clean::Path, print_all: bool,
root: |&render::Cache, &[~str]| -> Option<~str>,
info: |&render::Cache| -> Option<(Vec<~str> , ItemType)>)
Expand Down Expand Up @@ -298,15 +285,9 @@ impl fmt::Show for clean::Type {
let m = cache_key.get().unwrap();
f.buf.write(m.typarams.get(&id).as_bytes())
}
clean::ResolvedPath{id, typarams: ref tp, path: ref path} => {
try!(resolved_path(f.buf, id, path, false));
tybounds(f.buf, tp)
}
clean::ExternalPath{path: ref path, typarams: ref tp,
fqn: ref fqn, kind, krate} => {
try!(external_path(f.buf, path, false, fqn.as_slice(), kind,
krate))
tybounds(f.buf, tp)
clean::ResolvedPath{ did, ref typarams, ref path} => {
try!(resolved_path(f.buf, did, path, false));
tybounds(f.buf, typarams)
}
clean::Self(..) => f.buf.write("Self".as_bytes()),
clean::Primitive(prim) => {
Expand Down Expand Up @@ -543,10 +524,7 @@ impl fmt::Show for clean::ViewPath {
impl fmt::Show for clean::ImportSource {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.did {
// FIXME: shouldn't be restricted to just local imports
Some(did) if ast_util::is_local(did) => {
resolved_path(f.buf, did.node, &self.path, true)
}
Some(did) => resolved_path(f.buf, did, &self.path, true),
_ => {
for (i, seg) in self.path.segments.iter().enumerate() {
if i > 0 {
Expand All @@ -563,8 +541,7 @@ impl fmt::Show for clean::ImportSource {
impl fmt::Show for clean::ViewListIdent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.source {
// FIXME: shouldn't be limited to just local imports
Some(did) if ast_util::is_local(did) => {
Some(did) => {
let path = clean::Path {
global: false,
segments: vec!(clean::PathSegment {
Expand All @@ -573,7 +550,7 @@ impl fmt::Show for clean::ViewListIdent {
types: Vec::new(),
})
};
resolved_path(f.buf, did.node, &path, false)
resolved_path(f.buf, did, &path, false)
}
_ => write!(f.buf, "{}", self.name),
}
Expand Down
Loading

0 comments on commit 1ba4971

Please sign in to comment.