rustdoc: link to cross-crate sources directly.
This commit is contained in:
@@ -115,7 +115,7 @@ fn try_inline_def(cx: &DocContext, def: Def) -> Option<Vec<clean::Item>> {
|
|||||||
let did = def.def_id();
|
let did = def.def_id();
|
||||||
cx.renderinfo.borrow_mut().inlined.insert(did);
|
cx.renderinfo.borrow_mut().inlined.insert(did);
|
||||||
ret.push(clean::Item {
|
ret.push(clean::Item {
|
||||||
source: clean::Span::empty(),
|
source: tcx.def_span(did).clean(cx),
|
||||||
name: Some(tcx.item_name(did).to_string()),
|
name: Some(tcx.item_name(did).to_string()),
|
||||||
attrs: load_attrs(cx, did),
|
attrs: load_attrs(cx, did),
|
||||||
inner: inner,
|
inner: inner,
|
||||||
@@ -321,7 +321,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
|
|||||||
clean::RegionBound(..) => unreachable!(),
|
clean::RegionBound(..) => unreachable!(),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
source: clean::Span::empty(),
|
source: tcx.def_span(did).clean(cx),
|
||||||
name: None,
|
name: None,
|
||||||
attrs: attrs,
|
attrs: attrs,
|
||||||
visibility: Some(clean::Inherited),
|
visibility: Some(clean::Inherited),
|
||||||
@@ -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),
|
tcx.item_type(item.def_id).clean(cx),
|
||||||
default,
|
default,
|
||||||
),
|
),
|
||||||
source: clean::Span::empty(),
|
source: tcx.def_span(item.def_id).clean(cx),
|
||||||
attrs: clean::Attributes::default(),
|
attrs: clean::Attributes::default(),
|
||||||
visibility: None,
|
visibility: None,
|
||||||
stability: tcx.lookup_stability(item.def_id).clean(cx),
|
stability: tcx.lookup_stability(item.def_id).clean(cx),
|
||||||
@@ -404,7 +404,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
|
|||||||
Some(clean::Item {
|
Some(clean::Item {
|
||||||
name: Some(item.name.clean(cx)),
|
name: Some(item.name.clean(cx)),
|
||||||
inner: clean::TypedefItem(typedef, true),
|
inner: clean::TypedefItem(typedef, true),
|
||||||
source: clean::Span::empty(),
|
source: tcx.def_span(item.def_id).clean(cx),
|
||||||
attrs: clean::Attributes::default(),
|
attrs: clean::Attributes::default(),
|
||||||
visibility: None,
|
visibility: None,
|
||||||
stability: tcx.lookup_stability(item.def_id).clean(cx),
|
stability: tcx.lookup_stability(item.def_id).clean(cx),
|
||||||
@@ -442,7 +442,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
|
|||||||
items: trait_items,
|
items: trait_items,
|
||||||
polarity: Some(polarity.clean(cx)),
|
polarity: Some(polarity.clean(cx)),
|
||||||
}),
|
}),
|
||||||
source: clean::Span::empty(),
|
source: tcx.def_span(did).clean(cx),
|
||||||
name: None,
|
name: None,
|
||||||
attrs: attrs,
|
attrs: attrs,
|
||||||
visibility: Some(clean::Inherited),
|
visibility: Some(clean::Inherited),
|
||||||
|
|||||||
@@ -27,11 +27,10 @@ use syntax::ptr::P;
|
|||||||
use syntax::symbol::keywords;
|
use syntax::symbol::keywords;
|
||||||
use syntax_pos::{self, DUMMY_SP, Pos};
|
use syntax_pos::{self, DUMMY_SP, Pos};
|
||||||
|
|
||||||
use rustc_trans::back::link;
|
|
||||||
use rustc::middle::privacy::AccessLevels;
|
use rustc::middle::privacy::AccessLevels;
|
||||||
use rustc::middle::resolve_lifetime::DefRegion::*;
|
use rustc::middle::resolve_lifetime::DefRegion::*;
|
||||||
use rustc::hir::def::{Def, CtorKind};
|
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::hir::print as pprust;
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::Substs;
|
||||||
use rustc::ty::{self, AdtKind};
|
use rustc::ty::{self, AdtKind};
|
||||||
@@ -45,7 +44,6 @@ use std::rc::Rc;
|
|||||||
use std::slice;
|
use std::slice;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::u32;
|
use std::u32;
|
||||||
use std::env::current_dir;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use core::DocContext;
|
use core::DocContext;
|
||||||
@@ -110,19 +108,16 @@ pub struct Crate {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub src: PathBuf,
|
pub src: PathBuf,
|
||||||
pub module: Option<Item>,
|
pub module: Option<Item>,
|
||||||
pub externs: Vec<(def_id::CrateNum, ExternalCrate)>,
|
pub externs: Vec<(CrateNum, ExternalCrate)>,
|
||||||
pub primitives: Vec<PrimitiveType>,
|
pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
|
||||||
pub access_levels: Arc<AccessLevels<DefId>>,
|
pub access_levels: Arc<AccessLevels<DefId>>,
|
||||||
// These are later on moved into `CACHEKEY`, leaving the map empty.
|
// These are later on moved into `CACHEKEY`, leaving the map empty.
|
||||||
// Only here so that they can be filtered through the rustdoc passes.
|
// Only here so that they can be filtered through the rustdoc passes.
|
||||||
pub external_traits: FxHashMap<DefId, Trait>,
|
pub external_traits: FxHashMap<DefId, Trait>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CrateNum(def_id::CrateNum);
|
|
||||||
|
|
||||||
impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
|
||||||
fn clean(&self, cx: &DocContext) -> Crate {
|
fn clean(&self, cx: &DocContext) -> Crate {
|
||||||
use rustc::session::config::Input;
|
|
||||||
use ::visit_lib::LibEmbargoVisitor;
|
use ::visit_lib::LibEmbargoVisitor;
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -133,20 +128,65 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
|
|||||||
|
|
||||||
let mut externs = Vec::new();
|
let mut externs = Vec::new();
|
||||||
for cnum in cx.sess().cstore.crates() {
|
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
|
// Analyze doc-reachability for extern items
|
||||||
LibEmbargoVisitor::new(cx).visit_lib(cnum);
|
LibEmbargoVisitor::new(cx).visit_lib(cnum);
|
||||||
}
|
}
|
||||||
externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
|
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
|
// Clean the crate, translating the entire libsyntax AST to one that is
|
||||||
// understood by rustdoc.
|
// understood by rustdoc.
|
||||||
let mut module = self.module.clean(cx);
|
let mut module = self.module.clean(cx);
|
||||||
|
|
||||||
|
let ExternalCrate { name, src, primitives, .. } = LOCAL_CRATE.clean(cx);
|
||||||
|
{
|
||||||
|
let m = match module.inner {
|
||||||
|
ModuleItem(ref mut m) => m,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| {
|
||||||
|
Item {
|
||||||
|
source: Span::empty(),
|
||||||
|
name: Some(prim.to_url_str().to_string()),
|
||||||
|
attrs: attrs.clone(),
|
||||||
|
visibility: Some(Public),
|
||||||
|
stability: None,
|
||||||
|
deprecation: None,
|
||||||
|
def_id: def_id,
|
||||||
|
inner: PrimitiveItem(prim),
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut access_levels = cx.access_levels.borrow_mut();
|
||||||
|
let mut external_traits = cx.external_traits.borrow_mut();
|
||||||
|
|
||||||
|
Crate {
|
||||||
|
name: name,
|
||||||
|
src: src,
|
||||||
|
module: Some(module),
|
||||||
|
externs: externs,
|
||||||
|
primitives: primitives,
|
||||||
|
access_levels: Arc::new(mem::replace(&mut access_levels, Default::default())),
|
||||||
|
external_traits: mem::replace(&mut external_traits, Default::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||||
|
pub struct ExternalCrate {
|
||||||
|
pub name: String,
|
||||||
|
pub src: PathBuf,
|
||||||
|
pub attrs: Attributes,
|
||||||
|
pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clean<ExternalCrate> for CrateNum {
|
||||||
|
fn clean(&self, cx: &DocContext) -> ExternalCrate {
|
||||||
|
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
|
// Collect all inner modules which are tagged as implementations of
|
||||||
// primitives.
|
// primitives.
|
||||||
//
|
//
|
||||||
@@ -164,80 +204,50 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
|
|||||||
// Also note that this does not attempt to deal with modules tagged
|
// Also note that this does not attempt to deal with modules tagged
|
||||||
// duplicately for the same primitive. This is handled later on when
|
// duplicately for the same primitive. This is handled later on when
|
||||||
// rendering by delegating everything to a hash map.
|
// rendering by delegating everything to a hash map.
|
||||||
let mut primitives = Vec::new();
|
let as_primitive = |def: Def| {
|
||||||
{
|
if let Def::Mod(def_id) = def {
|
||||||
let m = match module.inner {
|
let attrs = cx.tcx.get_attrs(def_id).clean(cx);
|
||||||
ModuleItem(ref mut m) => m,
|
let mut prim = None;
|
||||||
_ => unreachable!(),
|
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 mut tmp = Vec::new();
|
let primitives = if root.is_local() {
|
||||||
for child in &mut m.items {
|
cx.tcx.map.krate().module.item_ids.iter().filter_map(|&id| {
|
||||||
if !child.is_mod() {
|
let item = cx.tcx.map.expect_item(id.id);
|
||||||
continue;
|
match item.node {
|
||||||
|
hir::ItemMod(_) => {
|
||||||
|
as_primitive(Def::Mod(cx.tcx.map.local_def_id(id.id)))
|
||||||
}
|
}
|
||||||
let prim = match PrimitiveType::find(&child.attrs) {
|
hir::ItemUse(ref path, hir::UseKind::Single)
|
||||||
Some(prim) => prim,
|
if item.vis == hir::Visibility::Public => {
|
||||||
None => continue,
|
as_primitive(path.def).map(|(_, prim, attrs)| {
|
||||||
};
|
// Pretend the primitive is local.
|
||||||
primitives.push(prim);
|
(cx.tcx.map.local_def_id(id.id), prim, attrs)
|
||||||
tmp.push(Item {
|
})
|
||||||
source: Span::empty(),
|
|
||||||
name: Some(prim.to_url_str().to_string()),
|
|
||||||
attrs: child.attrs.clone(),
|
|
||||||
visibility: Some(Public),
|
|
||||||
stability: None,
|
|
||||||
deprecation: None,
|
|
||||||
def_id: DefId::local(prim.to_def_index()),
|
|
||||||
inner: PrimitiveItem(prim),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
m.items.extend(tmp);
|
_ => None
|
||||||
}
|
}
|
||||||
|
}).collect()
|
||||||
let src = match cx.input {
|
|
||||||
Input::File(ref path) => {
|
|
||||||
if path.is_absolute() {
|
|
||||||
path.clone()
|
|
||||||
} else {
|
} else {
|
||||||
current_dir().unwrap().join(path)
|
cx.tcx.sess.cstore.item_children(root).iter().map(|item| item.def)
|
||||||
}
|
.filter_map(as_primitive).collect()
|
||||||
},
|
|
||||||
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(),
|
|
||||||
src: src,
|
|
||||||
module: Some(module),
|
|
||||||
externs: externs,
|
|
||||||
primitives: primitives,
|
|
||||||
access_levels: Arc::new(mem::replace(&mut access_levels, Default::default())),
|
|
||||||
external_traits: mem::replace(&mut external_traits, Default::default()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
|
||||||
pub struct ExternalCrate {
|
|
||||||
pub name: String,
|
|
||||||
pub attrs: Attributes,
|
|
||||||
pub primitives: Vec<PrimitiveType>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
ExternalCrate {
|
ExternalCrate {
|
||||||
name: cx.sess().cstore.crate_name(self.0).to_string(),
|
name: cx.tcx.crate_name(*self).to_string(),
|
||||||
attrs: cx.sess().cstore.item_attrs(root).clean(cx),
|
src: PathBuf::from(krate_src),
|
||||||
|
attrs: cx.tcx.get_attrs(root).clean(cx),
|
||||||
primitives: primitives,
|
primitives: primitives,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1460,7 +1470,7 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
|
|||||||
deprecation: get_deprecation(cx, self.def_id),
|
deprecation: get_deprecation(cx, self.def_id),
|
||||||
def_id: self.def_id,
|
def_id: self.def_id,
|
||||||
attrs: inline::load_attrs(cx, 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,
|
inner: inner,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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 {
|
pub fn as_str(&self) -> &'static str {
|
||||||
match *self {
|
match *self {
|
||||||
PrimitiveType::Isize => "isize",
|
PrimitiveType::Isize => "isize",
|
||||||
@@ -1658,14 +1655,6 @@ impl PrimitiveType {
|
|||||||
pub fn to_url_str(&self) -> &'static str {
|
pub fn to_url_str(&self) -> &'static str {
|
||||||
self.as_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 {
|
impl From<ast::IntTy> for PrimitiveType {
|
||||||
@@ -1948,7 +1937,7 @@ impl<'tcx> Clean<Item> for ty::FieldDefData<'tcx, 'static> {
|
|||||||
Item {
|
Item {
|
||||||
name: Some(self.name).clean(cx),
|
name: Some(self.name).clean(cx),
|
||||||
attrs: cx.tcx.get_attrs(self.did).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),
|
visibility: self.vis.clean(cx),
|
||||||
stability: get_stability(cx, self.did),
|
stability: get_stability(cx, self.did),
|
||||||
deprecation: get_deprecation(cx, self.did),
|
deprecation: get_deprecation(cx, self.did),
|
||||||
@@ -2115,7 +2104,7 @@ impl<'tcx> Clean<Item> for ty::VariantDefData<'tcx, 'static> {
|
|||||||
fields_stripped: false,
|
fields_stripped: false,
|
||||||
fields: self.fields.iter().map(|field| {
|
fields: self.fields.iter().map(|field| {
|
||||||
Item {
|
Item {
|
||||||
source: Span::empty(),
|
source: cx.tcx.def_span(field.did).clean(cx),
|
||||||
name: Some(field.name.clean(cx)),
|
name: Some(field.name.clean(cx)),
|
||||||
attrs: cx.tcx.get_attrs(field.did).clean(cx),
|
attrs: cx.tcx.get_attrs(field.did).clean(cx),
|
||||||
visibility: field.vis.clean(cx),
|
visibility: field.vis.clean(cx),
|
||||||
@@ -2131,7 +2120,7 @@ impl<'tcx> Clean<Item> for ty::VariantDefData<'tcx, 'static> {
|
|||||||
Item {
|
Item {
|
||||||
name: Some(self.name.clean(cx)),
|
name: Some(self.name.clean(cx)),
|
||||||
attrs: inline::load_attrs(cx, self.did),
|
attrs: inline::load_attrs(cx, self.did),
|
||||||
source: Span::empty(),
|
source: cx.tcx.def_span(self.did).clean(cx),
|
||||||
visibility: Some(Inherited),
|
visibility: Some(Inherited),
|
||||||
def_id: self.did,
|
def_id: self.did,
|
||||||
inner: VariantItem(Variant { kind: kind }),
|
inner: VariantItem(Variant { kind: kind }),
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ pub type ExternalPaths = FxHashMap<DefId, (Vec<String>, clean::TypeKind)>;
|
|||||||
|
|
||||||
pub struct DocContext<'a, 'tcx: 'a> {
|
pub struct DocContext<'a, 'tcx: 'a> {
|
||||||
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
pub input: Input,
|
|
||||||
pub populated_all_crate_impls: Cell<bool>,
|
pub populated_all_crate_impls: Cell<bool>,
|
||||||
// Note that external items for which `doc(hidden)` applies to are shown as
|
// 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
|
// non-reachable while local items aren't. This is because we're reusing
|
||||||
@@ -187,7 +186,6 @@ pub fn run_core(search_paths: SearchPaths,
|
|||||||
|
|
||||||
let ctxt = DocContext {
|
let ctxt = DocContext {
|
||||||
tcx: tcx,
|
tcx: tcx,
|
||||||
input: input,
|
|
||||||
populated_all_crate_impls: Cell::new(false),
|
populated_all_crate_impls: Cell::new(false),
|
||||||
access_levels: RefCell::new(access_levels),
|
access_levels: RefCell::new(access_levels),
|
||||||
external_traits: Default::default(),
|
external_traits: Default::default(),
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
|
|
||||||
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
|
use rustc::hir::def_id::DefId;
|
||||||
use syntax::abi::Abi;
|
use syntax::abi::Abi;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
|
|
||||||
@@ -403,9 +403,9 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
|
|||||||
None => match cache.external_paths.get(&did) {
|
None => match cache.external_paths.get(&did) {
|
||||||
Some(&(ref fqp, shortty)) => {
|
Some(&(ref fqp, shortty)) => {
|
||||||
(fqp, shortty, match cache.extern_locations[&did.krate] {
|
(fqp, shortty, match cache.extern_locations[&did.krate] {
|
||||||
(_, render::Remote(ref s)) => s.to_string(),
|
(.., render::Remote(ref s)) => s.to_string(),
|
||||||
(_, render::Local) => repeat("../").take(loc.len()).collect(),
|
(.., render::Local) => repeat("../").take(loc.len()).collect(),
|
||||||
(_, render::Unknown) => return None,
|
(.., render::Unknown) => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
None => return None,
|
None => return None,
|
||||||
@@ -479,7 +479,7 @@ fn primitive_link(f: &mut fmt::Formatter,
|
|||||||
let mut needs_termination = false;
|
let mut needs_termination = false;
|
||||||
if !f.alternate() {
|
if !f.alternate() {
|
||||||
match m.primitive_locations.get(&prim) {
|
match m.primitive_locations.get(&prim) {
|
||||||
Some(&LOCAL_CRATE) => {
|
Some(&def_id) if def_id.is_local() => {
|
||||||
let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
|
let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
|
||||||
let len = if len == 0 {0} else {len - 1};
|
let len = if len == 0 {0} else {len - 1};
|
||||||
write!(f, "<a class='primitive' href='{}primitive.{}.html'>",
|
write!(f, "<a class='primitive' href='{}primitive.{}.html'>",
|
||||||
@@ -487,14 +487,16 @@ fn primitive_link(f: &mut fmt::Formatter,
|
|||||||
prim.to_url_str())?;
|
prim.to_url_str())?;
|
||||||
needs_termination = true;
|
needs_termination = true;
|
||||||
}
|
}
|
||||||
Some(&cnum) => {
|
Some(&def_id) => {
|
||||||
let loc = match m.extern_locations[&cnum] {
|
let loc = match m.extern_locations[&def_id.krate] {
|
||||||
(ref cname, render::Remote(ref s)) => Some((cname, s.to_string())),
|
(ref cname, _, render::Remote(ref s)) => {
|
||||||
(ref cname, render::Local) => {
|
Some((cname, s.to_string()))
|
||||||
|
}
|
||||||
|
(ref cname, _, render::Local) => {
|
||||||
let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
|
let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
|
||||||
Some((cname, repeat("../").take(len).collect::<String>()))
|
Some((cname, repeat("../").take(len).collect::<String>()))
|
||||||
}
|
}
|
||||||
(_, render::Unknown) => None,
|
(.., render::Unknown) => None,
|
||||||
};
|
};
|
||||||
if let Some((cname, root)) = loc {
|
if let Some((cname, root)) = loc {
|
||||||
write!(f, "<a class='primitive' href='{}{}/primitive.{}.html'>",
|
write!(f, "<a class='primitive' href='{}{}/primitive.{}.html'>",
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ use externalfiles::ExternalHtml;
|
|||||||
use serialize::json::{ToJson, Json, as_json};
|
use serialize::json::{ToJson, Json, as_json};
|
||||||
use syntax::{abi, ast};
|
use syntax::{abi, ast};
|
||||||
use syntax::feature_gate::UnstableFeatures;
|
use syntax::feature_gate::UnstableFeatures;
|
||||||
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
|
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
|
||||||
use rustc::middle::privacy::AccessLevels;
|
use rustc::middle::privacy::AccessLevels;
|
||||||
use rustc::middle::stability;
|
use rustc::middle::stability;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
@@ -241,10 +241,10 @@ pub struct Cache {
|
|||||||
pub implementors: FxHashMap<DefId, Vec<Implementor>>,
|
pub implementors: FxHashMap<DefId, Vec<Implementor>>,
|
||||||
|
|
||||||
/// Cache of where external crate documentation can be found.
|
/// Cache of where external crate documentation can be found.
|
||||||
pub extern_locations: FxHashMap<CrateNum, (String, ExternalLocation)>,
|
pub extern_locations: FxHashMap<CrateNum, (String, PathBuf, ExternalLocation)>,
|
||||||
|
|
||||||
/// Cache of where documentation for primitives can be found.
|
/// Cache of where documentation for primitives can be found.
|
||||||
pub primitive_locations: FxHashMap<clean::PrimitiveType, CrateNum>,
|
pub primitive_locations: FxHashMap<clean::PrimitiveType, DefId>,
|
||||||
|
|
||||||
// Note that external items for which `doc(hidden)` applies to are shown as
|
// 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
|
// non-reachable while local items aren't. This is because we're reusing
|
||||||
@@ -523,8 +523,13 @@ pub fn run(mut krate: clean::Crate,
|
|||||||
|
|
||||||
// Cache where all our extern crates are located
|
// Cache where all our extern crates are located
|
||||||
for &(n, ref e) in &krate.externs {
|
for &(n, ref e) in &krate.externs {
|
||||||
cache.extern_locations.insert(n, (e.name.clone(),
|
let src_root = match Path::new(&e.src).parent() {
|
||||||
|
Some(p) => p.to_path_buf(),
|
||||||
|
None => PathBuf::new(),
|
||||||
|
};
|
||||||
|
cache.extern_locations.insert(n, (e.name.clone(), src_root,
|
||||||
extern_location(e, &cx.dst)));
|
extern_location(e, &cx.dst)));
|
||||||
|
|
||||||
let did = DefId { krate: n, index: CRATE_DEF_INDEX };
|
let did = DefId { krate: n, index: CRATE_DEF_INDEX };
|
||||||
cache.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module));
|
cache.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module));
|
||||||
}
|
}
|
||||||
@@ -533,13 +538,13 @@ pub fn run(mut krate: clean::Crate,
|
|||||||
//
|
//
|
||||||
// Favor linking to as local extern as possible, so iterate all crates in
|
// Favor linking to as local extern as possible, so iterate all crates in
|
||||||
// reverse topological order.
|
// reverse topological order.
|
||||||
for &(n, ref e) in krate.externs.iter().rev() {
|
for &(_, ref e) in krate.externs.iter().rev() {
|
||||||
for &prim in &e.primitives {
|
for &(def_id, prim, _) in &e.primitives {
|
||||||
cache.primitive_locations.insert(prim, n);
|
cache.primitive_locations.insert(prim, def_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for &prim in &krate.primitives {
|
for &(def_id, prim, _) in &krate.primitives {
|
||||||
cache.primitive_locations.insert(prim, LOCAL_CRATE);
|
cache.primitive_locations.insert(prim, def_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.stack.push(krate.name.clone());
|
cache.stack.push(krate.name.clone());
|
||||||
@@ -875,6 +880,8 @@ impl<'a> DocFolder for SourceCollector<'a> {
|
|||||||
if self.scx.include_sources
|
if self.scx.include_sources
|
||||||
// skip all invalid spans
|
// skip all invalid spans
|
||||||
&& item.source.filename != ""
|
&& item.source.filename != ""
|
||||||
|
// skip non-local items
|
||||||
|
&& item.def_id.is_local()
|
||||||
// Macros from other libraries get special filenames which we can
|
// Macros from other libraries get special filenames which we can
|
||||||
// safely ignore.
|
// safely ignore.
|
||||||
&& !(item.source.filename.starts_with("<")
|
&& !(item.source.filename.starts_with("<")
|
||||||
@@ -1127,13 +1134,15 @@ impl DocFolder for Cache {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
ref t => {
|
ref t => {
|
||||||
match t.primitive_type() {
|
let prim_did = t.primitive_type().and_then(|t| {
|
||||||
Some(prim) => {
|
self.primitive_locations.get(&t).cloned()
|
||||||
let did = DefId::local(prim.to_def_index());
|
});
|
||||||
|
match prim_did {
|
||||||
|
Some(did) => {
|
||||||
self.parent_stack.push(did);
|
self.parent_stack.push(did);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
_ => false,
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1158,10 +1167,7 @@ impl DocFolder for Cache {
|
|||||||
}
|
}
|
||||||
ref t => {
|
ref t => {
|
||||||
t.primitive_type().and_then(|t| {
|
t.primitive_type().and_then(|t| {
|
||||||
self.primitive_locations.get(&t).map(|n| {
|
self.primitive_locations.get(&t).cloned()
|
||||||
let id = t.to_def_index();
|
|
||||||
DefId { krate: *n, index: id }
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1439,79 +1445,50 @@ impl<'a> Item<'a> {
|
|||||||
/// If `None` is returned, then a source link couldn't be generated. This
|
/// If `None` is returned, then a source link couldn't be generated. This
|
||||||
/// may happen, for example, with externally inlined items where the source
|
/// may happen, for example, with externally inlined items where the source
|
||||||
/// of their crate documentation isn't known.
|
/// of their crate documentation isn't known.
|
||||||
fn href(&self) -> Option<String> {
|
fn src_href(&self) -> Option<String> {
|
||||||
let href = if self.item.source.loline == self.item.source.hiline {
|
let mut root = self.cx.root_path();
|
||||||
|
|
||||||
|
let cache = cache();
|
||||||
|
let mut path = String::new();
|
||||||
|
let (krate, path) = if self.item.def_id.is_local() {
|
||||||
|
let path = PathBuf::from(&self.item.source.filename);
|
||||||
|
if let Some(path) = self.cx.shared.local_sources.get(&path) {
|
||||||
|
(&self.cx.shared.layout.krate, path)
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let (krate, src_root) = match cache.extern_locations.get(&self.item.def_id.krate) {
|
||||||
|
Some(&(ref name, ref src, Local)) => (name, src),
|
||||||
|
Some(&(ref name, ref src, Remote(ref s))) => {
|
||||||
|
root = s.to_string();
|
||||||
|
(name, src)
|
||||||
|
}
|
||||||
|
Some(&(_, _, Unknown)) | None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let file = Path::new(&self.item.source.filename);
|
||||||
|
clean_srcpath(&src_root, file, false, |component| {
|
||||||
|
path.push_str(component);
|
||||||
|
path.push('/');
|
||||||
|
});
|
||||||
|
let mut fname = file.file_name().expect("source has no filename")
|
||||||
|
.to_os_string();
|
||||||
|
fname.push(".html");
|
||||||
|
path.push_str(&fname.to_string_lossy());
|
||||||
|
(krate, &path)
|
||||||
|
};
|
||||||
|
|
||||||
|
let lines = if self.item.source.loline == self.item.source.hiline {
|
||||||
format!("{}", self.item.source.loline)
|
format!("{}", self.item.source.loline)
|
||||||
} else {
|
} else {
|
||||||
format!("{}-{}", self.item.source.loline, self.item.source.hiline)
|
format!("{}-{}", self.item.source.loline, self.item.source.hiline)
|
||||||
};
|
};
|
||||||
|
Some(format!("{root}src/{krate}/{path}#{lines}",
|
||||||
// First check to see if this is an imported macro source. In this case
|
|
||||||
// we need to handle it specially as cross-crate inlined macros have...
|
|
||||||
// odd locations!
|
|
||||||
let imported_macro_from = match self.item.inner {
|
|
||||||
clean::MacroItem(ref m) => m.imported_from.as_ref(),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
if let Some(krate) = imported_macro_from {
|
|
||||||
let cache = cache();
|
|
||||||
let root = cache.extern_locations.values().find(|&&(ref n, _)| {
|
|
||||||
*krate == *n
|
|
||||||
}).map(|l| &l.1);
|
|
||||||
let root = match root {
|
|
||||||
Some(&Remote(ref s)) => s.to_string(),
|
|
||||||
Some(&Local) => self.cx.root_path(),
|
|
||||||
None | Some(&Unknown) => return None,
|
|
||||||
};
|
|
||||||
Some(format!("{root}/{krate}/macro.{name}.html?gotomacrosrc=1",
|
|
||||||
root = root,
|
root = root,
|
||||||
krate = krate,
|
krate = krate,
|
||||||
name = self.item.name.as_ref().unwrap()))
|
|
||||||
|
|
||||||
// If this item is part of the local crate, then we're guaranteed to
|
|
||||||
// know the span, so we plow forward and generate a proper url. The url
|
|
||||||
// has anchors for the line numbers that we're linking to.
|
|
||||||
} else if self.item.def_id.is_local() {
|
|
||||||
let path = PathBuf::from(&self.item.source.filename);
|
|
||||||
self.cx.shared.local_sources.get(&path).map(|path| {
|
|
||||||
format!("{root}src/{krate}/{path}#{href}",
|
|
||||||
root = self.cx.root_path(),
|
|
||||||
krate = self.cx.shared.layout.krate,
|
|
||||||
path = path,
|
path = path,
|
||||||
href = href)
|
lines = lines))
|
||||||
})
|
|
||||||
// If this item is not part of the local crate, then things get a little
|
|
||||||
// trickier. We don't actually know the span of the external item, but
|
|
||||||
// we know that the documentation on the other end knows the span!
|
|
||||||
//
|
|
||||||
// In this case, we generate a link to the *documentation* for this type
|
|
||||||
// in the original crate. There's an extra URL parameter which says that
|
|
||||||
// we want to go somewhere else, and the JS on the destination page will
|
|
||||||
// pick it up and instantly redirect the browser to the source code.
|
|
||||||
//
|
|
||||||
// If we don't know where the external documentation for this crate is
|
|
||||||
// located, then we return `None`.
|
|
||||||
} else {
|
|
||||||
let cache = cache();
|
|
||||||
let external_path = match cache.external_paths.get(&self.item.def_id) {
|
|
||||||
Some(&(ref path, _)) => path,
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
let mut path = match cache.extern_locations.get(&self.item.def_id.krate) {
|
|
||||||
Some(&(_, Remote(ref s))) => s.to_string(),
|
|
||||||
Some(&(_, Local)) => self.cx.root_path(),
|
|
||||||
Some(&(_, Unknown)) => return None,
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
for item in &external_path[..external_path.len() - 1] {
|
|
||||||
path.push_str(item);
|
|
||||||
path.push_str("/");
|
|
||||||
}
|
|
||||||
Some(format!("{path}{file}?gotosrc={goto}",
|
|
||||||
path = path,
|
|
||||||
file = item_path(self.item.type_(), external_path.last().unwrap()),
|
|
||||||
goto = self.item.def_id.index.as_usize()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1576,10 +1553,9 @@ impl<'a> fmt::Display for Item<'a> {
|
|||||||
// this page, and this link will be auto-clicked. The `id` attribute is
|
// this page, and this link will be auto-clicked. The `id` attribute is
|
||||||
// used to find the link to auto-click.
|
// used to find the link to auto-click.
|
||||||
if self.cx.shared.include_sources && !self.item.is_primitive() {
|
if self.cx.shared.include_sources && !self.item.is_primitive() {
|
||||||
if let Some(l) = self.href() {
|
if let Some(l) = self.src_href() {
|
||||||
write!(fmt, "<a id='src-{}' class='srclink' \
|
write!(fmt, "<a class='srclink' href='{}' title='{}'>[src]</a>",
|
||||||
href='{}' title='{}'>[src]</a>",
|
l, "goto source code")?;
|
||||||
self.item.def_id.index.as_usize(), l, "goto source code")?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2781,8 +2757,7 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl,
|
|||||||
render_assoc_items(w, cx, container_item, did, what)
|
render_assoc_items(w, cx, container_item, did, what)
|
||||||
} else {
|
} else {
|
||||||
if let Some(prim) = target.primitive_type() {
|
if let Some(prim) = target.primitive_type() {
|
||||||
if let Some(c) = cache().primitive_locations.get(&prim) {
|
if let Some(&did) = cache().primitive_locations.get(&prim) {
|
||||||
let did = DefId { krate: *c, index: prim.to_def_index() };
|
|
||||||
render_assoc_items(w, cx, container_item, did, what)?;
|
render_assoc_items(w, cx, container_item, did, what)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2796,12 +2771,11 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
|
|||||||
write!(w, "<h3 class='impl'><span class='in-band'><code>{}</code>", i.inner_impl())?;
|
write!(w, "<h3 class='impl'><span class='in-band'><code>{}</code>", i.inner_impl())?;
|
||||||
write!(w, "</span><span class='out-of-band'>")?;
|
write!(w, "</span><span class='out-of-band'>")?;
|
||||||
let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]);
|
let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]);
|
||||||
if let Some(l) = (Item { item: &i.impl_item, cx: cx }).href() {
|
if let Some(l) = (Item { item: &i.impl_item, cx: cx }).src_href() {
|
||||||
write!(w, "<div class='ghost'></div>")?;
|
write!(w, "<div class='ghost'></div>")?;
|
||||||
render_stability_since_raw(w, since, outer_version)?;
|
render_stability_since_raw(w, since, outer_version)?;
|
||||||
write!(w, "<a id='src-{}' class='srclink' \
|
write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a>",
|
||||||
href='{}' title='{}'>[src]</a>",
|
l, "goto source code")?;
|
||||||
i.impl_item.def_id.index.as_usize(), l, "goto source code")?;
|
|
||||||
} else {
|
} else {
|
||||||
render_stability_since_raw(w, since, outer_version)?;
|
render_stability_since_raw(w, since, outer_version)?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -923,15 +923,6 @@
|
|||||||
window.register_implementors(window.pending_implementors);
|
window.register_implementors(window.pending_implementors);
|
||||||
}
|
}
|
||||||
|
|
||||||
// See documentation in html/render.rs for what this is doing.
|
|
||||||
var query = getQueryStringParams();
|
|
||||||
if (query['gotosrc']) {
|
|
||||||
window.location = $('#src-' + query['gotosrc']).attr('href');
|
|
||||||
}
|
|
||||||
if (query['gotomacrosrc']) {
|
|
||||||
window.location = $('.srclink').attr('href');
|
|
||||||
}
|
|
||||||
|
|
||||||
function labelForToggleButton(sectionIsCollapsed) {
|
function labelForToggleButton(sectionIsCollapsed) {
|
||||||
if (sectionIsCollapsed) {
|
if (sectionIsCollapsed) {
|
||||||
// button will expand the section
|
// button will expand the section
|
||||||
|
|||||||
@@ -16,5 +16,5 @@
|
|||||||
|
|
||||||
extern crate issue_34274;
|
extern crate issue_34274;
|
||||||
|
|
||||||
// @has foo/fn.extern_c_fn.html '//a/@href' '../issue_34274/fn.extern_c_fn.html?gotosrc='
|
// @has foo/fn.extern_c_fn.html '//a/@href' '../src/issue_34274/issue-34274.rs.html#12'
|
||||||
pub use issue_34274::extern_c_fn;
|
pub use issue_34274::extern_c_fn;
|
||||||
|
|||||||
@@ -11,12 +11,13 @@
|
|||||||
// aux-build:src-links-external.rs
|
// aux-build:src-links-external.rs
|
||||||
// build-aux-docs
|
// build-aux-docs
|
||||||
// ignore-cross-compile
|
// ignore-cross-compile
|
||||||
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
#![crate_name = "foo"]
|
#![crate_name = "foo"]
|
||||||
|
|
||||||
extern crate src_links_external;
|
extern crate src_links_external;
|
||||||
|
|
||||||
// @has foo/bar/index.html '//a/@href' '../src_links_external/index.html?gotosrc='
|
// @has foo/bar/index.html '//a/@href' '../../src/src_links_external/src-links-external.rs.html#11'
|
||||||
pub use src_links_external as bar;
|
pub use src_links_external as bar;
|
||||||
|
|
||||||
// @has foo/bar/struct.Foo.html '//a/@href' '../src_links_external/struct.Foo.html?gotosrc='
|
// @has foo/bar/struct.Foo.html '//a/@href' '../../src/src_links_external/src-links-external.rs.html#11'
|
||||||
|
|||||||
Reference in New Issue
Block a user