Auto merge of #37954 - eddyb:rustdoc-2, r=alexcrichton

rustdoc: link to cross-crate sources directly.

Fixes #37684 by implementing proper support for getting the `Span` of definitions across crates.
In rustdoc this is used to generate direct links to the original source instead of fragile redirects.

This functionality could be expanded further for making error reporting code more uniform and seamless across crates, although at the moment there is no actual source to print, only file/line/column information.

Closes #37870 which is also "fixes" #37684 by throwing away the builtin macro docs from libcore.
After this lands, #37727 could be reverted, although it doesn't matter much either way.
This commit is contained in:
bors 2016-11-30 07:46:00 +00:00
commit 3abaf43f77
26 changed files with 309 additions and 338 deletions

View File

@ -760,47 +760,40 @@ impl<'ast> Map<'ast> {
} }
} }
pub fn opt_span(&self, id: NodeId) -> Option<Span> {
let sp = match self.find(id) {
Some(NodeItem(item)) => item.span,
Some(NodeForeignItem(foreign_item)) => foreign_item.span,
Some(NodeTraitItem(trait_method)) => trait_method.span,
Some(NodeImplItem(ref impl_item)) => impl_item.span,
Some(NodeVariant(variant)) => variant.span,
Some(NodeField(field)) => field.span,
Some(NodeExpr(expr)) => expr.span,
Some(NodeStmt(stmt)) => stmt.span,
Some(NodeTy(ty)) => ty.span,
Some(NodeTraitRef(tr)) => tr.path.span,
Some(NodeLocal(pat)) => pat.span,
Some(NodePat(pat)) => pat.span,
Some(NodeBlock(block)) => block.span,
Some(NodeStructCtor(_)) => self.expect_item(self.get_parent(id)).span,
Some(NodeTyParam(ty_param)) => ty_param.span,
Some(NodeVisibility(&Visibility::Restricted { ref path, .. })) => path.span,
_ => return None,
};
Some(sp)
}
pub fn span(&self, id: NodeId) -> Span { pub fn span(&self, id: NodeId) -> Span {
self.read(id); // reveals span from node self.read(id); // reveals span from node
self.opt_span(id) match self.find_entry(id) {
.unwrap_or_else(|| bug!("AstMap.span: could not find span for id {:?}", id)) Some(EntryItem(_, item)) => item.span,
Some(EntryForeignItem(_, foreign_item)) => foreign_item.span,
Some(EntryTraitItem(_, trait_method)) => trait_method.span,
Some(EntryImplItem(_, impl_item)) => impl_item.span,
Some(EntryVariant(_, variant)) => variant.span,
Some(EntryField(_, field)) => field.span,
Some(EntryExpr(_, expr)) => expr.span,
Some(EntryStmt(_, stmt)) => stmt.span,
Some(EntryTy(_, ty)) => ty.span,
Some(EntryTraitRef(_, tr)) => tr.path.span,
Some(EntryLocal(_, pat)) => pat.span,
Some(EntryPat(_, pat)) => pat.span,
Some(EntryBlock(_, block)) => block.span,
Some(EntryStructCtor(_, _)) => self.expect_item(self.get_parent(id)).span,
Some(EntryLifetime(_, lifetime)) => lifetime.span,
Some(EntryTyParam(_, ty_param)) => ty_param.span,
Some(EntryVisibility(_, &Visibility::Restricted { ref path, .. })) => path.span,
Some(EntryVisibility(_, v)) => bug!("unexpected Visibility {:?}", v),
Some(RootCrate) => self.krate().span,
Some(RootInlinedParent(parent)) => parent.body.span,
Some(NotPresent) | None => {
bug!("hir::map::Map::span: id not in map: {:?}", id)
}
}
} }
pub fn span_if_local(&self, id: DefId) -> Option<Span> { pub fn span_if_local(&self, id: DefId) -> Option<Span> {
self.as_local_node_id(id).map(|id| self.span(id)) self.as_local_node_id(id).map(|id| self.span(id))
} }
pub fn def_id_span(&self, def_id: DefId, fallback: Span) -> Span {
if let Some(node_id) = self.as_local_node_id(def_id) {
self.opt_span(node_id).unwrap_or(fallback)
} else {
fallback
}
}
pub fn node_to_string(&self, id: NodeId) -> String { pub fn node_to_string(&self, id: NodeId) -> String {
node_id_to_string(self, id, true) node_id_to_string(self, id, true)
} }

View File

@ -260,6 +260,7 @@ pub struct ExternCrate {
pub trait CrateStore<'tcx> { pub trait CrateStore<'tcx> {
// item info // item info
fn describe_def(&self, def: DefId) -> Option<Def>; fn describe_def(&self, def: DefId) -> Option<Def>;
fn def_span(&self, sess: &Session, def: DefId) -> Span;
fn stability(&self, def: DefId) -> Option<attr::Stability>; fn stability(&self, def: DefId) -> Option<attr::Stability>;
fn deprecation(&self, def: DefId) -> Option<attr::Deprecation>; fn deprecation(&self, def: DefId) -> Option<attr::Deprecation>;
fn visibility(&self, def: DefId) -> ty::Visibility; fn visibility(&self, def: DefId) -> ty::Visibility;
@ -404,6 +405,7 @@ pub struct DummyCrateStore;
impl<'tcx> CrateStore<'tcx> for DummyCrateStore { impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
// item info // item info
fn describe_def(&self, def: DefId) -> Option<Def> { bug!("describe_def") } fn describe_def(&self, def: DefId) -> Option<Def> { bug!("describe_def") }
fn def_span(&self, sess: &Session, def: DefId) -> Span { bug!("def_span") }
fn stability(&self, def: DefId) -> Option<attr::Stability> { bug!("stability") } fn stability(&self, def: DefId) -> Option<attr::Stability> { bug!("stability") }
fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> { bug!("deprecation") } fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> { bug!("deprecation") }
fn visibility(&self, def: DefId) -> ty::Visibility { bug!("visibility") } fn visibility(&self, def: DefId) -> ty::Visibility { bug!("visibility") }

View File

@ -283,10 +283,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
expected.ty, expected.ty,
found.ty)); found.ty));
match match self.map.span_if_local(expected.def_id) {
self.map.as_local_node_id(expected.def_id)
.and_then(|node_id| self.map.opt_span(node_id))
{
Some(span) => { Some(span) => {
db.span_note(span, "a default was defined here..."); db.span_note(span, "a default was defined here...");
} }
@ -300,10 +297,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
expected.origin_span, expected.origin_span,
"...that was applied to an unconstrained type variable here"); "...that was applied to an unconstrained type variable here");
match match self.map.span_if_local(found.def_id) {
self.map.as_local_node_id(found.def_id)
.and_then(|node_id| self.map.opt_span(node_id))
{
Some(span) => { Some(span) => {
db.span_note(span, "a second default was defined here..."); db.span_note(span, "a second default was defined here...");
} }

View File

@ -2360,6 +2360,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
} }
} }
pub fn def_span(self, def_id: DefId) -> Span {
if let Some(id) = self.map.as_local_node_id(def_id) {
self.map.span(id)
} else {
self.sess.cstore.def_span(&self.sess, def_id)
}
}
pub fn item_name(self, id: DefId) -> ast::Name { pub fn item_name(self, id: DefId) -> ast::Name {
if let Some(id) = self.map.as_local_node_id(id) { if let Some(id) = self.map.as_local_node_id(id) {
self.map.name(id) self.map.name(id)

View File

@ -496,8 +496,8 @@ fn add_fragment_siblings_for_extension<'a, 'tcx>(this: &MoveData<'tcx>,
}, },
ref ty => { ref ty => {
let opt_span = origin_id.and_then(|id|tcx.map.opt_span(id)); let span = origin_id.map_or(DUMMY_SP, |id| tcx.map.span(id));
span_bug!(opt_span.unwrap_or(DUMMY_SP), span_bug!(span,
"type {:?} ({:?}) is not fragmentable", "type {:?} ({:?}) is not fragmentable",
parent_ty, ty); parent_ty, ty);
} }

View File

@ -1006,11 +1006,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
got {:?}", got {:?}",
node); node);
// Point to what was found, if there's an accessible span. tcx.sess.span_fatal(tcx.map.span(nodeid), &message)
match tcx.map.opt_span(nodeid) {
Some(sp) => tcx.sess.span_fatal(sp, &message),
None => tcx.sess.fatal(&message),
}
} }
} }
} }

View File

@ -32,7 +32,7 @@ use syntax::ast;
use syntax::attr; use syntax::attr;
use syntax::parse::new_parser_from_source_str; use syntax::parse::new_parser_from_source_str;
use syntax::symbol::Symbol; use syntax::symbol::Symbol;
use syntax_pos::mk_sp; use syntax_pos::{mk_sp, Span};
use rustc::hir::svh::Svh; use rustc::hir::svh::Svh;
use rustc_back::target::Target; use rustc_back::target::Target;
use rustc::hir; use rustc::hir;
@ -43,6 +43,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
self.get_crate_data(def.krate).get_def(def.index) self.get_crate_data(def.krate).get_def(def.index)
} }
fn def_span(&self, sess: &Session, def: DefId) -> Span {
self.dep_graph.read(DepNode::MetaData(def));
self.get_crate_data(def.krate).get_span(def.index, sess)
}
fn stability(&self, def: DefId) -> Option<attr::Stability> { fn stability(&self, def: DefId) -> Option<attr::Stability> {
self.dep_graph.read(DepNode::MetaData(def)); self.dep_graph.read(DepNode::MetaData(def));
self.get_crate_data(def.krate).get_stability(def.index) self.get_crate_data(def.krate).get_stability(def.index)
@ -383,20 +388,23 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
let local_span = mk_sp(lo, parser.prev_span.hi); let local_span = mk_sp(lo, parser.prev_span.hi);
// Mark the attrs as used // Mark the attrs as used
for attr in &def.attrs { let attrs = data.get_item_attrs(id.index);
for attr in &attrs {
attr::mark_used(attr); attr::mark_used(attr);
} }
let name = data.def_key(id.index).disambiguated_data.data
.get_opt_name().expect("no name in load_macro");
sess.imported_macro_spans.borrow_mut() sess.imported_macro_spans.borrow_mut()
.insert(local_span, (def.name.as_str().to_string(), def.span)); .insert(local_span, (name.to_string(), data.get_span(id.index, sess)));
LoadedMacro::MacroRules(ast::MacroDef { LoadedMacro::MacroRules(ast::MacroDef {
ident: ast::Ident::with_empty_ctxt(def.name), ident: ast::Ident::with_empty_ctxt(name),
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
span: local_span, span: local_span,
imported_from: None, // FIXME imported_from: None, // FIXME
allow_internal_unstable: attr::contains_name(&def.attrs, "allow_internal_unstable"), allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
attrs: def.attrs, attrs: attrs,
body: body, body: body,
}) })
} }

View File

@ -25,6 +25,7 @@ use rustc::middle::cstore::{InlinedItem, LinkagePreference};
use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def::{self, Def, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::middle::lang_items; use rustc::middle::lang_items;
use rustc::session::Session;
use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::Substs; use rustc::ty::subst::Substs;
@ -47,8 +48,9 @@ use syntax_pos::{self, Span, BytePos, Pos};
pub struct DecodeContext<'a, 'tcx: 'a> { pub struct DecodeContext<'a, 'tcx: 'a> {
opaque: opaque::Decoder<'a>, opaque: opaque::Decoder<'a>,
tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
cdata: Option<&'a CrateMetadata>, cdata: Option<&'a CrateMetadata>,
sess: Option<&'a Session>,
tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
from_id_range: IdRange, from_id_range: IdRange,
to_id_range: IdRange, to_id_range: IdRange,
@ -61,22 +63,21 @@ pub struct DecodeContext<'a, 'tcx: 'a> {
/// Abstract over the various ways one can create metadata decoders. /// Abstract over the various ways one can create metadata decoders.
pub trait Metadata<'a, 'tcx>: Copy { pub trait Metadata<'a, 'tcx>: Copy {
fn raw_bytes(self) -> &'a [u8]; fn raw_bytes(self) -> &'a [u8];
fn cdata(self) -> Option<&'a CrateMetadata> { fn cdata(self) -> Option<&'a CrateMetadata> { None }
None fn sess(self) -> Option<&'a Session> { None }
} fn tcx(self) -> Option<TyCtxt<'a, 'tcx, 'tcx>> { None }
fn tcx(self) -> Option<TyCtxt<'a, 'tcx, 'tcx>> {
None
}
fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> { fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> {
let id_range = IdRange { let id_range = IdRange {
min: NodeId::from_u32(u32::MIN), min: NodeId::from_u32(u32::MIN),
max: NodeId::from_u32(u32::MAX), max: NodeId::from_u32(u32::MAX),
}; };
let tcx = self.tcx();
DecodeContext { DecodeContext {
opaque: opaque::Decoder::new(self.raw_bytes(), pos), opaque: opaque::Decoder::new(self.raw_bytes(), pos),
cdata: self.cdata(), cdata: self.cdata(),
tcx: self.tcx(), sess: self.sess().or(tcx.map(|tcx| tcx.sess)),
tcx: tcx,
from_id_range: id_range, from_id_range: id_range,
to_id_range: id_range, to_id_range: id_range,
last_filemap_index: 0, last_filemap_index: 0,
@ -104,6 +105,18 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadata {
} }
} }
impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, &'a Session) {
fn raw_bytes(self) -> &'a [u8] {
self.0.raw_bytes()
}
fn cdata(self) -> Option<&'a CrateMetadata> {
Some(self.0)
}
fn sess(self) -> Option<&'a Session> {
Some(&self.1)
}
}
impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'a, 'tcx, 'tcx>) { impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'a, 'tcx, 'tcx>) {
fn raw_bytes(self) -> &'a [u8] { fn raw_bytes(self) -> &'a [u8] {
self.0.raw_bytes() self.0.raw_bytes()
@ -280,8 +293,8 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
let lo = BytePos::decode(self)?; let lo = BytePos::decode(self)?;
let hi = BytePos::decode(self)?; let hi = BytePos::decode(self)?;
let tcx = if let Some(tcx) = self.tcx { let sess = if let Some(sess) = self.sess {
tcx sess
} else { } else {
return Ok(syntax_pos::mk_sp(lo, hi)); return Ok(syntax_pos::mk_sp(lo, hi));
}; };
@ -299,7 +312,7 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
(lo, hi) (lo, hi)
}; };
let imported_filemaps = self.cdata().imported_filemaps(&tcx.sess.codemap()); let imported_filemaps = self.cdata().imported_filemaps(&sess.codemap());
let filemap = { let filemap = {
// Optimize for the case that most spans within a translated item // Optimize for the case that most spans within a translated item
// originate from the same filemap. // originate from the same filemap.
@ -537,6 +550,10 @@ impl<'a, 'tcx> CrateMetadata {
} }
} }
pub fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
self.entry(index).span.decode((self, sess))
}
pub fn get_trait_def(&self, pub fn get_trait_def(&self,
item_id: DefIndex, item_id: DefIndex,
tcx: TyCtxt<'a, 'tcx, 'tcx>) tcx: TyCtxt<'a, 'tcx, 'tcx>)

View File

@ -275,6 +275,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
Entry { Entry {
kind: EntryKind::Variant(self.lazy(&data)), kind: EntryKind::Variant(self.lazy(&data)),
visibility: enum_vis.simplify(), visibility: enum_vis.simplify(),
span: self.lazy(&tcx.def_span(def_id)),
def_key: self.encode_def_key(def_id), def_key: self.encode_def_key(def_id),
attributes: self.encode_attributes(&tcx.get_attrs(def_id)), attributes: self.encode_attributes(&tcx.get_attrs(def_id)),
children: self.lazy_seq(variant.fields.iter().map(|f| { children: self.lazy_seq(variant.fields.iter().map(|f| {
@ -313,6 +314,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
Entry { Entry {
kind: EntryKind::Mod(self.lazy(&data)), kind: EntryKind::Mod(self.lazy(&data)),
visibility: vis.simplify(), visibility: vis.simplify(),
span: self.lazy(&md.inner),
def_key: self.encode_def_key(def_id), def_key: self.encode_def_key(def_id),
attributes: self.encode_attributes(attrs), attributes: self.encode_attributes(attrs),
children: self.lazy_seq(md.item_ids.iter().map(|item_id| { children: self.lazy_seq(md.item_ids.iter().map(|item_id| {
@ -393,6 +395,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
Entry { Entry {
kind: EntryKind::Field, kind: EntryKind::Field,
visibility: field.vis.simplify(), visibility: field.vis.simplify(),
span: self.lazy(&tcx.def_span(def_id)),
def_key: self.encode_def_key(def_id), def_key: self.encode_def_key(def_id),
attributes: self.encode_attributes(&variant_data.fields()[field_index].attrs), attributes: self.encode_attributes(&variant_data.fields()[field_index].attrs),
children: LazySeq::empty(), children: LazySeq::empty(),
@ -426,6 +429,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
Entry { Entry {
kind: EntryKind::Struct(self.lazy(&data)), kind: EntryKind::Struct(self.lazy(&data)),
visibility: struct_vis.simplify(), visibility: struct_vis.simplify(),
span: self.lazy(&tcx.def_span(def_id)),
def_key: self.encode_def_key(def_id), def_key: self.encode_def_key(def_id),
attributes: LazySeq::empty(), attributes: LazySeq::empty(),
children: LazySeq::empty(), children: LazySeq::empty(),
@ -492,6 +496,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
Entry { Entry {
kind: kind, kind: kind,
visibility: trait_item.vis.simplify(), visibility: trait_item.vis.simplify(),
span: self.lazy(&ast_item.span),
def_key: self.encode_def_key(def_id), def_key: self.encode_def_key(def_id),
attributes: self.encode_attributes(&ast_item.attrs), attributes: self.encode_attributes(&ast_item.attrs),
children: LazySeq::empty(), children: LazySeq::empty(),
@ -580,6 +585,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
Entry { Entry {
kind: kind, kind: kind,
visibility: impl_item.vis.simplify(), visibility: impl_item.vis.simplify(),
span: self.lazy(&ast_item.span),
def_key: self.encode_def_key(def_id), def_key: self.encode_def_key(def_id),
attributes: self.encode_attributes(&ast_item.attrs), attributes: self.encode_attributes(&ast_item.attrs),
children: LazySeq::empty(), children: LazySeq::empty(),
@ -743,6 +749,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
Entry { Entry {
kind: kind, kind: kind,
visibility: item.vis.simplify(), visibility: item.vis.simplify(),
span: self.lazy(&item.span),
def_key: self.encode_def_key(def_id), def_key: self.encode_def_key(def_id),
attributes: self.encode_attributes(&item.attrs), attributes: self.encode_attributes(&item.attrs),
children: match item.node { children: match item.node {
@ -850,18 +857,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
/// Serialize the text of exported macros /// Serialize the text of exported macros
fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef) -> Entry<'tcx> { fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef) -> Entry<'tcx> {
let def_id = self.tcx.map.local_def_id(macro_def.id); let def_id = self.tcx.map.local_def_id(macro_def.id);
let macro_def = MacroDef {
name: macro_def.name,
attrs: macro_def.attrs.to_vec(),
span: macro_def.span,
body: ::syntax::print::pprust::tts_to_string(&macro_def.body)
};
Entry { Entry {
kind: EntryKind::MacroDef(self.lazy(&macro_def)), kind: EntryKind::MacroDef(self.lazy(&MacroDef {
body: ::syntax::print::pprust::tts_to_string(&macro_def.body)
})),
visibility: ty::Visibility::Public, visibility: ty::Visibility::Public,
span: self.lazy(&macro_def.span),
def_key: self.encode_def_key(def_id), def_key: self.encode_def_key(def_id),
attributes: LazySeq::empty(), attributes: self.encode_attributes(&macro_def.attrs),
children: LazySeq::empty(), children: LazySeq::empty(),
stability: None, stability: None,
deprecation: None, deprecation: None,
@ -960,6 +964,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
Entry { Entry {
kind: kind, kind: kind,
visibility: nitem.vis.simplify(), visibility: nitem.vis.simplify(),
span: self.lazy(&nitem.span),
def_key: self.encode_def_key(def_id), def_key: self.encode_def_key(def_id),
attributes: self.encode_attributes(&nitem.attrs), attributes: self.encode_attributes(&nitem.attrs),
children: LazySeq::empty(), children: LazySeq::empty(),
@ -1038,9 +1043,11 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
impl<'a, 'tcx> EncodeContext<'a, 'tcx> { impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn encode_info_for_anon_ty(&mut self, def_id: DefId) -> Entry<'tcx> { fn encode_info_for_anon_ty(&mut self, def_id: DefId) -> Entry<'tcx> {
let tcx = self.tcx;
Entry { Entry {
kind: EntryKind::Type, kind: EntryKind::Type,
visibility: ty::Visibility::Public, visibility: ty::Visibility::Public,
span: self.lazy(&tcx.def_span(def_id)),
def_key: self.encode_def_key(def_id), def_key: self.encode_def_key(def_id),
attributes: LazySeq::empty(), attributes: LazySeq::empty(),
children: LazySeq::empty(), children: LazySeq::empty(),
@ -1069,6 +1076,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
Entry { Entry {
kind: EntryKind::Closure(self.lazy(&data)), kind: EntryKind::Closure(self.lazy(&data)),
visibility: ty::Visibility::Public, visibility: ty::Visibility::Public,
span: self.lazy(&tcx.def_span(def_id)),
def_key: self.encode_def_key(def_id), def_key: self.encode_def_key(def_id),
attributes: self.encode_attributes(&tcx.get_attrs(def_id)), attributes: self.encode_attributes(&tcx.get_attrs(def_id)),
children: LazySeq::empty(), children: LazySeq::empty(),
@ -1163,11 +1171,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let all_filemaps = codemap.files.borrow(); let all_filemaps = codemap.files.borrow();
self.lazy_seq_ref(all_filemaps.iter() self.lazy_seq_ref(all_filemaps.iter()
.filter(|filemap| { .filter(|filemap| {
// No need to export empty filemaps, as they can't contain spans // No need to re-export imported filemaps, as any downstream
// that need translation.
// Also no need to re-export imported filemaps, as any downstream
// crate will import them from their original source. // crate will import them from their original source.
!filemap.lines.borrow().is_empty() && !filemap.is_imported() !filemap.is_imported()
}) })
.map(|filemap| &**filemap)) .map(|filemap| &**filemap))
} }

View File

@ -197,18 +197,11 @@ pub struct TraitImpls {
pub impls: LazySeq<DefIndex>, pub impls: LazySeq<DefIndex>,
} }
#[derive(RustcEncodable, RustcDecodable)]
pub struct MacroDef {
pub name: ast::Name,
pub attrs: Vec<ast::Attribute>,
pub span: Span,
pub body: String,
}
#[derive(RustcEncodable, RustcDecodable)] #[derive(RustcEncodable, RustcDecodable)]
pub struct Entry<'tcx> { pub struct Entry<'tcx> {
pub kind: EntryKind<'tcx>, pub kind: EntryKind<'tcx>,
pub visibility: ty::Visibility, pub visibility: ty::Visibility,
pub span: Lazy<Span>,
pub def_key: Lazy<hir::map::DefKey>, pub def_key: Lazy<hir::map::DefKey>,
pub attributes: LazySeq<ast::Attribute>, pub attributes: LazySeq<ast::Attribute>,
pub children: LazySeq<DefIndex>, pub children: LazySeq<DefIndex>,
@ -257,6 +250,11 @@ pub struct ModData {
pub reexports: LazySeq<def::Export>, pub reexports: LazySeq<def::Export>,
} }
#[derive(RustcEncodable, RustcDecodable)]
pub struct MacroDef {
pub body: String,
}
#[derive(RustcEncodable, RustcDecodable)] #[derive(RustcEncodable, RustcDecodable)]
pub struct FnData { pub struct FnData {
pub constness: hir::Constness, pub constness: hir::Constness,

View File

@ -69,7 +69,7 @@ pub fn item_namespace(ccx: &CrateContext, def_id: DefId) -> DIScope {
}; };
let namespace_name = CString::new(namespace_name.as_bytes()).unwrap(); let namespace_name = CString::new(namespace_name.as_bytes()).unwrap();
let span = ccx.tcx().map.def_id_span(def_id, DUMMY_SP); let span = ccx.tcx().def_span(def_id);
let (file, line) = if span != DUMMY_SP { let (file, line) = if span != DUMMY_SP {
let loc = span_start(ccx, span); let loc = span_start(ccx, span);
(file_metadata(ccx, &loc.file.name, &loc.file.abs_path), loc.line as c_uint) (file_metadata(ccx, &loc.file.name, &loc.file.abs_path), loc.line as c_uint)

View File

@ -79,7 +79,7 @@ pub fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: DefId)
}); });
// Try to get some span information, if we have an inlined item. // Try to get some span information, if we have an inlined item.
let definition_span = cx.tcx().map.def_id_span(def_id, syntax_pos::DUMMY_SP); let definition_span = cx.tcx().def_span(def_id);
(containing_scope, definition_span) (containing_scope, definition_span)
} }

View File

@ -1227,8 +1227,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
self.tcx().associated_items(b.def_id()).find(|item| { self.tcx().associated_items(b.def_id()).find(|item| {
item.kind == ty::AssociatedKind::Type && item.name == assoc_name item.kind == ty::AssociatedKind::Type && item.name == assoc_name
}) })
.and_then(|item| self.tcx().map.as_local_node_id(item.def_id)) .and_then(|item| self.tcx().map.span_if_local(item.def_id))
.and_then(|node_id| self.tcx().map.opt_span(node_id))
}); });
let mut err = struct_span_err!( let mut err = struct_span_err!(

View File

@ -21,7 +21,7 @@ use rustc::traits::{self, ObligationCause, Reveal};
use util::nodemap::FxHashSet; use util::nodemap::FxHashSet;
use syntax::ast; use syntax::ast;
use syntax_pos::{self, Span}; use syntax_pos::Span;
/// check_drop_impl confirms that the Drop implementation identfied by /// check_drop_impl confirms that the Drop implementation identfied by
/// `drop_impl_did` is not any more specialized than the type it is /// `drop_impl_did` is not any more specialized than the type it is
@ -59,7 +59,7 @@ pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()>
_ => { _ => {
// Destructors only work on nominal types. This was // Destructors only work on nominal types. This was
// already checked by coherence, so we can panic here. // already checked by coherence, so we can panic here.
let span = ccx.tcx.map.def_id_span(drop_impl_did, syntax_pos::DUMMY_SP); let span = ccx.tcx.def_span(drop_impl_did);
span_bug!(span, span_bug!(span,
"should have been rejected by coherence check: {}", "should have been rejected by coherence check: {}",
dtor_self_type); dtor_self_type);
@ -88,7 +88,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
let named_type = tcx.item_type(self_type_did); let named_type = tcx.item_type(self_type_did);
let named_type = named_type.subst(tcx, &infcx.parameter_environment.free_substs); let named_type = named_type.subst(tcx, &infcx.parameter_environment.free_substs);
let drop_impl_span = tcx.map.def_id_span(drop_impl_did, syntax_pos::DUMMY_SP); let drop_impl_span = tcx.def_span(drop_impl_did);
let fresh_impl_substs = let fresh_impl_substs =
infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did); infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did);
let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs); let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs);
@ -173,7 +173,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
let self_type_node_id = tcx.map.as_local_node_id(self_type_did).unwrap(); let self_type_node_id = tcx.map.as_local_node_id(self_type_did).unwrap();
let drop_impl_span = tcx.map.def_id_span(drop_impl_did, syntax_pos::DUMMY_SP); let drop_impl_span = tcx.def_span(drop_impl_did);
// We can assume the predicates attached to struct/enum definition // We can assume the predicates attached to struct/enum definition
// hold. // hold.

View File

@ -124,7 +124,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
} }
CandidateSource::TraitSource(trait_did) => { CandidateSource::TraitSource(trait_did) => {
let item = self.associated_item(trait_did, item_name).unwrap(); let item = self.associated_item(trait_did, item_name).unwrap();
let item_span = self.tcx.map.def_id_span(item.def_id, span); let item_span = self.tcx.def_span(item.def_id);
span_note!(err, span_note!(err,
item_span, item_span,
"candidate #{} is defined in the trait `{}`", "candidate #{} is defined in the trait `{}`",

View File

@ -1755,7 +1755,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let item_predicates = self.tcx.item_predicates(def_id); let item_predicates = self.tcx.item_predicates(def_id);
let bounds = item_predicates.instantiate(self.tcx, substs); let bounds = item_predicates.instantiate(self.tcx, substs);
let span = self.tcx.map.def_id_span(def_id, codemap::DUMMY_SP); let span = self.tcx.def_span(def_id);
for predicate in bounds.predicates { for predicate in bounds.predicates {
// Change the predicate to refer to the type variable, // Change the predicate to refer to the type variable,
// which will be the concrete type, instead of the TyAnon. // which will be the concrete type, instead of the TyAnon.

View File

@ -183,7 +183,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
fcx.register_wf_obligation(ty, span, code.clone()); fcx.register_wf_obligation(ty, span, code.clone());
} }
ty::AssociatedKind::Method => { ty::AssociatedKind::Method => {
reject_shadowing_type_parameters(fcx.tcx, span, item.def_id); reject_shadowing_type_parameters(fcx.tcx, item.def_id);
let method_ty = fcx.tcx.item_type(item.def_id); let method_ty = fcx.tcx.item_type(item.def_id);
let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method_ty); let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method_ty);
let predicates = fcx.instantiate_bounds(span, item.def_id, free_substs); let predicates = fcx.instantiate_bounds(span, item.def_id, free_substs);
@ -576,7 +576,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
} }
} }
fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, def_id: DefId) { fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) {
let generics = tcx.item_generics(def_id); let generics = tcx.item_generics(def_id);
let parent = tcx.item_generics(generics.parent.unwrap()); let parent = tcx.item_generics(generics.parent.unwrap());
let impl_params: FxHashMap<_, _> = parent.types let impl_params: FxHashMap<_, _> = parent.types
@ -587,17 +587,12 @@ fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, def_id: DefId) {
for method_param in &generics.types { for method_param in &generics.types {
if impl_params.contains_key(&method_param.name) { if impl_params.contains_key(&method_param.name) {
// Tighten up the span to focus on only the shadowing type // Tighten up the span to focus on only the shadowing type
let shadow_node_id = tcx.map.as_local_node_id(method_param.def_id).unwrap(); let type_span = tcx.def_span(method_param.def_id);
let type_span = match tcx.map.opt_span(shadow_node_id) {
Some(osp) => osp,
None => span
};
// The expectation here is that the original trait declaration is // The expectation here is that the original trait declaration is
// local so it should be okay to just unwrap everything. // local so it should be okay to just unwrap everything.
let trait_def_id = impl_params.get(&method_param.name).unwrap(); let trait_def_id = impl_params[&method_param.name];
let trait_node_id = tcx.map.as_local_node_id(*trait_def_id).unwrap(); let trait_decl_span = tcx.def_span(trait_def_id);
let trait_decl_span = tcx.map.opt_span(trait_node_id).unwrap();
error_194(tcx, type_span, trait_decl_span, method_param.name); error_194(tcx, type_span, trait_decl_span, method_param.name);
} }
} }

View File

@ -24,7 +24,7 @@ use rustc::util::nodemap::DefIdMap;
use std::cell::Cell; use std::cell::Cell;
use syntax::ast; use syntax::ast;
use syntax_pos::{DUMMY_SP, Span}; use syntax_pos::Span;
use rustc::hir::print::pat_to_string; use rustc::hir::print::pat_to_string;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
@ -542,7 +542,7 @@ impl<'a, 'gcx, 'tcx> ResolveReason {
} }
ResolvingClosure(did) | ResolvingClosure(did) |
ResolvingAnonTy(did) => { ResolvingAnonTy(did) => {
tcx.map.def_id_span(did, DUMMY_SP) tcx.def_span(did)
} }
ResolvingDeferredObligation(span) => span ResolvingDeferredObligation(span) => span
} }

View File

@ -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),

View File

@ -27,12 +27,11 @@ 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::middle::lang_items; use rustc::middle::lang_items;
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};
@ -46,7 +45,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;
@ -111,19 +109,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;
{ {
@ -134,20 +129,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.
// //
@ -165,80 +205,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() {
let mut tmp = Vec::new(); if attr.check_name("primitive") {
for child in &mut m.items { prim = PrimitiveType::from_str(&v.as_str());
if !child.is_mod() { if prim.is_some() {
continue; break;
}
}
}
} }
let prim = match PrimitiveType::find(&child.attrs) { return prim.map(|p| (def_id, p, attrs));
Some(prim) => prim,
None => continue,
};
primitives.push(prim);
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
} };
let primitives = if root.is_local() {
let src = match cx.input { cx.tcx.map.krate().module.item_ids.iter().filter_map(|&id| {
Input::File(ref path) => { let item = cx.tcx.map.expect_item(id.id);
if path.is_absolute() { match item.node {
path.clone() hir::ItemMod(_) => {
} else { as_primitive(Def::Mod(cx.tcx.map.local_def_id(id.id)))
current_dir().unwrap().join(path) }
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()
Input::Str { ref name, .. } => PathBuf::from(name.clone()), } else {
cx.tcx.sess.cstore.item_children(root).iter().map(|item| item.def)
.filter_map(as_primitive).collect()
}; };
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,
} }
} }
@ -1438,7 +1448,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,
} }
} }
@ -1596,19 +1606,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",
@ -1636,14 +1633,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 {
@ -1943,7 +1932,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),
@ -2110,7 +2099,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),
@ -2126,7 +2115,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 }),

View File

@ -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(),

View File

@ -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'>",

View File

@ -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 root = root,
// we need to handle it specially as cross-crate inlined macros have... krate = krate,
// odd locations! path = path,
let imported_macro_from = match self.item.inner { lines = lines))
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,
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,
href = href)
})
// 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)?;
} }

View File

@ -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

View File

@ -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;

View File

@ -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'