From 177913b49c1f5df106c64599e649323882644dc1 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 24 Nov 2016 01:39:13 +0200 Subject: [PATCH 1/2] rustc: track the Span's of definitions across crates. --- src/librustc/hir/map/mod.rs | 59 +++++++++------------ src/librustc/middle/cstore.rs | 2 + src/librustc/ty/error.rs | 10 +--- src/librustc/ty/mod.rs | 8 +++ src/librustc_borrowck/borrowck/fragments.rs | 4 +- src/librustc_driver/pretty.rs | 6 +-- src/librustc_metadata/cstore_impl.rs | 20 ++++--- src/librustc_metadata/decoder.rs | 39 ++++++++++---- src/librustc_metadata/encoder.rs | 30 ++++++----- src/librustc_metadata/schema.rs | 14 +++-- src/librustc_trans/debuginfo/namespace.rs | 2 +- src/librustc_trans/debuginfo/utils.rs | 2 +- src/librustc_typeck/astconv.rs | 3 +- src/librustc_typeck/check/dropck.rs | 8 +-- src/librustc_typeck/check/method/suggest.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/wfcheck.rs | 15 ++---- src/librustc_typeck/check/writeback.rs | 4 +- 18 files changed, 123 insertions(+), 107 deletions(-) diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 434e34e7003..6ce6f6896df 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -760,47 +760,40 @@ impl<'ast> Map<'ast> { } } - pub fn opt_span(&self, id: NodeId) -> Option { - 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 { self.read(id); // reveals span from node - self.opt_span(id) - .unwrap_or_else(|| bug!("AstMap.span: could not find span for id {:?}", id)) + match self.find_entry(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 { 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 { node_id_to_string(self, id, true) } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index d055506a382..484e2f1535e 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -260,6 +260,7 @@ pub struct ExternCrate { pub trait CrateStore<'tcx> { // item info fn describe_def(&self, def: DefId) -> Option; + fn def_span(&self, sess: &Session, def: DefId) -> Span; fn stability(&self, def: DefId) -> Option; fn deprecation(&self, def: DefId) -> Option; fn visibility(&self, def: DefId) -> ty::Visibility; @@ -404,6 +405,7 @@ pub struct DummyCrateStore; impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // item info fn describe_def(&self, def: DefId) -> Option { bug!("describe_def") } + fn def_span(&self, sess: &Session, def: DefId) -> Span { bug!("def_span") } fn stability(&self, def: DefId) -> Option { bug!("stability") } fn deprecation(&self, def: DefId) -> Option { bug!("deprecation") } fn visibility(&self, def: DefId) -> ty::Visibility { bug!("visibility") } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 9b345c2d023..b14148cf38f 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -291,10 +291,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { expected.ty, found.ty)); - match - self.map.as_local_node_id(expected.def_id) - .and_then(|node_id| self.map.opt_span(node_id)) - { + match self.map.span_if_local(expected.def_id) { Some(span) => { db.span_note(span, "a default was defined here..."); } @@ -308,10 +305,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { expected.origin_span, "...that was applied to an unconstrained type variable here"); - match - self.map.as_local_node_id(found.def_id) - .and_then(|node_id| self.map.opt_span(node_id)) - { + match self.map.span_if_local(found.def_id) { Some(span) => { db.span_note(span, "a second default was defined here..."); } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 9a92e9e70fe..7387a48c989 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2370,6 +2370,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 { if let Some(id) = self.map.as_local_node_id(id) { self.map.name(id) diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index 515868c460d..b0a1b349854 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -496,8 +496,8 @@ fn add_fragment_siblings_for_extension<'a, 'tcx>(this: &MoveData<'tcx>, }, ref ty => { - let opt_span = origin_id.and_then(|id|tcx.map.opt_span(id)); - span_bug!(opt_span.unwrap_or(DUMMY_SP), + let span = origin_id.map_or(DUMMY_SP, |id| tcx.map.span(id)); + span_bug!(span, "type {:?} ({:?}) is not fragmentable", parent_ty, ty); } diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index f8507776651..b055b043723 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -1006,11 +1006,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, got {:?}", node); - // Point to what was found, if there's an accessible span. - match tcx.map.opt_span(nodeid) { - Some(sp) => tcx.sess.span_fatal(sp, &message), - None => tcx.sess.fatal(&message), - } + tcx.sess.span_fatal(tcx.map.span(nodeid), &message) } } } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 573b2f6d2a6..c41c3afb83e 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -32,7 +32,7 @@ use syntax::ast; use syntax::attr; use syntax::parse::new_parser_from_source_str; use syntax::symbol::Symbol; -use syntax_pos::mk_sp; +use syntax_pos::{mk_sp, Span}; use rustc::hir::svh::Svh; use rustc_back::target::Target; use rustc::hir; @@ -43,6 +43,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { 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 { self.dep_graph.read(DepNode::MetaData(def)); 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); // 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); } + 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() - .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 { - ident: ast::Ident::with_empty_ctxt(def.name), + ident: ast::Ident::with_empty_ctxt(name), id: ast::DUMMY_NODE_ID, span: local_span, imported_from: None, // FIXME - allow_internal_unstable: attr::contains_name(&def.attrs, "allow_internal_unstable"), - attrs: def.attrs, + allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"), + attrs: attrs, body: body, }) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index d5b08927a06..088364f9834 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -25,6 +25,7 @@ use rustc::middle::cstore::{InlinedItem, LinkagePreference}; use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::middle::lang_items; +use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; @@ -47,8 +48,9 @@ use syntax_pos::{self, Span, BytePos, Pos}; pub struct DecodeContext<'a, 'tcx: 'a> { opaque: opaque::Decoder<'a>, - tcx: Option>, cdata: Option<&'a CrateMetadata>, + sess: Option<&'a Session>, + tcx: Option>, from_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. pub trait Metadata<'a, 'tcx>: Copy { fn raw_bytes(self) -> &'a [u8]; - fn cdata(self) -> Option<&'a CrateMetadata> { - None - } - fn tcx(self) -> Option> { - None - } + fn cdata(self) -> Option<&'a CrateMetadata> { None } + fn sess(self) -> Option<&'a Session> { None } + fn tcx(self) -> Option> { None } fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> { let id_range = IdRange { min: NodeId::from_u32(u32::MIN), max: NodeId::from_u32(u32::MAX), }; + let tcx = self.tcx(); DecodeContext { opaque: opaque::Decoder::new(self.raw_bytes(), pos), cdata: self.cdata(), - tcx: self.tcx(), + sess: self.sess().or(tcx.map(|tcx| tcx.sess)), + tcx: tcx, from_id_range: id_range, to_id_range: id_range, 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>) { fn raw_bytes(self) -> &'a [u8] { self.0.raw_bytes() @@ -280,8 +293,8 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { let lo = BytePos::decode(self)?; let hi = BytePos::decode(self)?; - let tcx = if let Some(tcx) = self.tcx { - tcx + let sess = if let Some(sess) = self.sess { + sess } else { return Ok(syntax_pos::mk_sp(lo, hi)); }; @@ -299,7 +312,7 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { (lo, hi) }; - let imported_filemaps = self.cdata().imported_filemaps(&tcx.sess.codemap()); + let imported_filemaps = self.cdata().imported_filemaps(&sess.codemap()); let filemap = { // Optimize for the case that most spans within a translated item // originate from the same filemap. @@ -528,6 +541,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, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 4839c409335..6abc81d74dc 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -275,6 +275,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Entry { kind: EntryKind::Variant(self.lazy(&data)), visibility: enum_vis.simplify(), + span: self.lazy(&tcx.def_span(def_id)), def_key: self.encode_def_key(def_id), attributes: self.encode_attributes(&tcx.get_attrs(def_id)), children: self.lazy_seq(variant.fields.iter().map(|f| { @@ -313,6 +314,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Entry { kind: EntryKind::Mod(self.lazy(&data)), visibility: vis.simplify(), + span: self.lazy(&md.inner), def_key: self.encode_def_key(def_id), attributes: self.encode_attributes(attrs), children: self.lazy_seq(md.item_ids.iter().map(|item_id| { @@ -393,6 +395,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Entry { kind: EntryKind::Field, visibility: field.vis.simplify(), + span: self.lazy(&tcx.def_span(def_id)), def_key: self.encode_def_key(def_id), attributes: self.encode_attributes(&variant_data.fields()[field_index].attrs), children: LazySeq::empty(), @@ -426,6 +429,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Entry { kind: EntryKind::Struct(self.lazy(&data)), visibility: struct_vis.simplify(), + span: self.lazy(&tcx.def_span(def_id)), def_key: self.encode_def_key(def_id), attributes: LazySeq::empty(), children: LazySeq::empty(), @@ -492,6 +496,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Entry { kind: kind, visibility: trait_item.vis.simplify(), + span: self.lazy(&ast_item.span), def_key: self.encode_def_key(def_id), attributes: self.encode_attributes(&ast_item.attrs), children: LazySeq::empty(), @@ -580,6 +585,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Entry { kind: kind, visibility: impl_item.vis.simplify(), + span: self.lazy(&ast_item.span), def_key: self.encode_def_key(def_id), attributes: self.encode_attributes(&ast_item.attrs), children: LazySeq::empty(), @@ -743,6 +749,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Entry { kind: kind, visibility: item.vis.simplify(), + span: self.lazy(&item.span), def_key: self.encode_def_key(def_id), attributes: self.encode_attributes(&item.attrs), children: match item.node { @@ -850,18 +857,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { /// Serialize the text of exported macros 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 macro_def = MacroDef { - name: macro_def.name, - attrs: macro_def.attrs.to_vec(), - span: macro_def.span, - body: ::syntax::print::pprust::tts_to_string(¯o_def.body) - }; Entry { - kind: EntryKind::MacroDef(self.lazy(¯o_def)), + kind: EntryKind::MacroDef(self.lazy(&MacroDef { + body: ::syntax::print::pprust::tts_to_string(¯o_def.body) + })), visibility: ty::Visibility::Public, + span: self.lazy(¯o_def.span), def_key: self.encode_def_key(def_id), - attributes: LazySeq::empty(), + attributes: self.encode_attributes(¯o_def.attrs), children: LazySeq::empty(), stability: None, deprecation: None, @@ -960,6 +964,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Entry { kind: kind, visibility: nitem.vis.simplify(), + span: self.lazy(&nitem.span), def_key: self.encode_def_key(def_id), attributes: self.encode_attributes(&nitem.attrs), children: LazySeq::empty(), @@ -1038,9 +1043,11 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_anon_ty(&mut self, def_id: DefId) -> Entry<'tcx> { + let tcx = self.tcx; Entry { kind: EntryKind::Type, visibility: ty::Visibility::Public, + span: self.lazy(&tcx.def_span(def_id)), def_key: self.encode_def_key(def_id), attributes: LazySeq::empty(), children: LazySeq::empty(), @@ -1069,6 +1076,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Entry { kind: EntryKind::Closure(self.lazy(&data)), visibility: ty::Visibility::Public, + span: self.lazy(&tcx.def_span(def_id)), def_key: self.encode_def_key(def_id), attributes: self.encode_attributes(&tcx.get_attrs(def_id)), children: LazySeq::empty(), @@ -1163,11 +1171,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let all_filemaps = codemap.files.borrow(); self.lazy_seq_ref(all_filemaps.iter() .filter(|filemap| { - // No need to export empty filemaps, as they can't contain spans - // that need translation. - // Also no need to re-export imported filemaps, as any downstream + // No need to re-export imported filemaps, as any downstream // crate will import them from their original source. - !filemap.lines.borrow().is_empty() && !filemap.is_imported() + !filemap.is_imported() }) .map(|filemap| &**filemap)) } diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 32e89f64f0e..c2acb2e0d70 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -197,18 +197,11 @@ pub struct TraitImpls { pub impls: LazySeq, } -#[derive(RustcEncodable, RustcDecodable)] -pub struct MacroDef { - pub name: ast::Name, - pub attrs: Vec, - pub span: Span, - pub body: String, -} - #[derive(RustcEncodable, RustcDecodable)] pub struct Entry<'tcx> { pub kind: EntryKind<'tcx>, pub visibility: ty::Visibility, + pub span: Lazy, pub def_key: Lazy, pub attributes: LazySeq, pub children: LazySeq, @@ -257,6 +250,11 @@ pub struct ModData { pub reexports: LazySeq, } +#[derive(RustcEncodable, RustcDecodable)] +pub struct MacroDef { + pub body: String, +} + #[derive(RustcEncodable, RustcDecodable)] pub struct FnData { pub constness: hir::Constness, diff --git a/src/librustc_trans/debuginfo/namespace.rs b/src/librustc_trans/debuginfo/namespace.rs index a0477c9fc1e..521dd7530be 100644 --- a/src/librustc_trans/debuginfo/namespace.rs +++ b/src/librustc_trans/debuginfo/namespace.rs @@ -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 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 loc = span_start(ccx, span); (file_metadata(ccx, &loc.file.name, &loc.file.abs_path), loc.line as c_uint) diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs index 3cdac485fec..7cac9172a9c 100644 --- a/src/librustc_trans/debuginfo/utils.rs +++ b/src/librustc_trans/debuginfo/utils.rs @@ -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. - 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) } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index bb7b6253300..bad014df6fd 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1222,8 +1222,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.tcx().associated_items(b.def_id()).find(|item| { item.kind == ty::AssociatedKind::Type && item.name == assoc_name }) - .and_then(|item| self.tcx().map.as_local_node_id(item.def_id)) - .and_then(|node_id| self.tcx().map.opt_span(node_id)) + .and_then(|item| self.tcx().map.span_if_local(item.def_id)) }); let mut err = struct_span_err!( diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 8868d1e54f4..6fe268bdb2c 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -21,7 +21,7 @@ use rustc::traits::{self, ObligationCause, Reveal}; use util::nodemap::FxHashSet; use syntax::ast; -use syntax_pos::{self, Span}; +use syntax_pos::Span; /// check_drop_impl confirms that the Drop implementation identfied by /// `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 // 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, "should have been rejected by coherence check: {}", 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 = 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 = infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did); 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 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 // hold. diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 6598790355e..bcf18ff66fa 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -124,7 +124,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } CandidateSource::TraitSource(trait_did) => { 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, item_span, "candidate #{} is defined in the trait `{}`", diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0c4e5e4fa0d..e25b6d56112 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1754,7 +1754,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let item_predicates = self.tcx.item_predicates(def_id); 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 { // Change the predicate to refer to the type variable, // which will be the concrete type, instead of the TyAnon. diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index b6d0ff03a07..ae336a2f79e 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -188,7 +188,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { fcx.register_wf_obligation(ty, span, code.clone()); } 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.instantiate_type_scheme(span, free_substs, &method_ty); let predicates = fcx.instantiate_bounds(span, item.def_id, free_substs); @@ -581,7 +581,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 parent = tcx.item_generics(generics.parent.unwrap()); let impl_params: FxHashMap<_, _> = parent.types @@ -592,17 +592,12 @@ fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, def_id: DefId) { for method_param in &generics.types { if impl_params.contains_key(&method_param.name) { // 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 = match tcx.map.opt_span(shadow_node_id) { - Some(osp) => osp, - None => span - }; + let type_span = tcx.def_span(method_param.def_id); // The expectation here is that the original trait declaration is // local so it should be okay to just unwrap everything. - let trait_def_id = impl_params.get(&method_param.name).unwrap(); - let trait_node_id = tcx.map.as_local_node_id(*trait_def_id).unwrap(); - let trait_decl_span = tcx.map.opt_span(trait_node_id).unwrap(); + let trait_def_id = impl_params[&method_param.name]; + let trait_decl_span = tcx.def_span(trait_def_id); error_194(tcx, type_span, trait_decl_span, method_param.name); } } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 84b0303e5cf..56de75995fd 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -24,7 +24,7 @@ use rustc::util::nodemap::DefIdMap; use std::cell::Cell; use syntax::ast; -use syntax_pos::{DUMMY_SP, Span}; +use syntax_pos::Span; use rustc::hir::print::pat_to_string; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; @@ -542,7 +542,7 @@ impl<'a, 'gcx, 'tcx> ResolveReason { } ResolvingClosure(did) | ResolvingAnonTy(did) => { - tcx.map.def_id_span(did, DUMMY_SP) + tcx.def_span(did) } ResolvingDeferredObligation(span) => span } From 900191891fc5462d4ef33756a7d4d40e78e1c1cc Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 29 Nov 2016 08:15:16 +0200 Subject: [PATCH 2/2] rustdoc: link to cross-crate sources directly. --- src/librustdoc/clean/inline.rs | 10 +- src/librustdoc/clean/mod.rs | 201 ++++++++++++------------- src/librustdoc/core.rs | 2 - src/librustdoc/html/format.rs | 22 +-- src/librustdoc/html/render.rs | 166 +++++++++----------- src/librustdoc/html/static/main.js | 9 -- src/test/rustdoc/issue-34274.rs | 2 +- src/test/rustdoc/src-links-external.rs | 5 +- 8 files changed, 186 insertions(+), 231 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e3274611e5b..bf739abe3da 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -115,7 +115,7 @@ fn try_inline_def(cx: &DocContext, def: Def) -> Option> { let did = def.def_id(); cx.renderinfo.borrow_mut().inlined.insert(did); ret.push(clean::Item { - source: clean::Span::empty(), + source: tcx.def_span(did).clean(cx), name: Some(tcx.item_name(did).to_string()), attrs: load_attrs(cx, did), inner: inner, @@ -321,7 +321,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { clean::RegionBound(..) => unreachable!(), }, }), - source: clean::Span::empty(), + source: tcx.def_span(did).clean(cx), name: None, attrs: attrs, visibility: Some(clean::Inherited), @@ -357,7 +357,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { tcx.item_type(item.def_id).clean(cx), default, ), - source: clean::Span::empty(), + source: tcx.def_span(item.def_id).clean(cx), attrs: clean::Attributes::default(), visibility: None, stability: tcx.lookup_stability(item.def_id).clean(cx), @@ -404,7 +404,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { Some(clean::Item { name: Some(item.name.clean(cx)), inner: clean::TypedefItem(typedef, true), - source: clean::Span::empty(), + source: tcx.def_span(item.def_id).clean(cx), attrs: clean::Attributes::default(), visibility: None, stability: tcx.lookup_stability(item.def_id).clean(cx), @@ -442,7 +442,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { items: trait_items, polarity: Some(polarity.clean(cx)), }), - source: clean::Span::empty(), + source: tcx.def_span(did).clean(cx), name: None, attrs: attrs, visibility: Some(clean::Inherited), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e233613ee62..dba613ed1b6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -27,11 +27,10 @@ use syntax::ptr::P; use syntax::symbol::keywords; use syntax_pos::{self, DUMMY_SP, Pos}; -use rustc_trans::back::link; use rustc::middle::privacy::AccessLevels; use rustc::middle::resolve_lifetime::DefRegion::*; use rustc::hir::def::{Def, CtorKind}; -use rustc::hir::def_id::{self, DefId, DefIndex, CRATE_DEF_INDEX}; +use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::hir::print as pprust; use rustc::ty::subst::Substs; use rustc::ty::{self, AdtKind}; @@ -45,7 +44,6 @@ use std::rc::Rc; use std::slice; use std::sync::Arc; use std::u32; -use std::env::current_dir; use std::mem; use core::DocContext; @@ -110,19 +108,16 @@ pub struct Crate { pub name: String, pub src: PathBuf, pub module: Option, - pub externs: Vec<(def_id::CrateNum, ExternalCrate)>, - pub primitives: Vec, + pub externs: Vec<(CrateNum, ExternalCrate)>, + pub primitives: Vec<(DefId, PrimitiveType, Attributes)>, pub access_levels: Arc>, // These are later on moved into `CACHEKEY`, leaving the map empty. // Only here so that they can be filtered through the rustdoc passes. pub external_traits: FxHashMap, } -struct CrateNum(def_id::CrateNum); - impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { fn clean(&self, cx: &DocContext) -> Crate { - use rustc::session::config::Input; use ::visit_lib::LibEmbargoVisitor; { @@ -133,20 +128,65 @@ impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { let mut externs = Vec::new(); for cnum in cx.sess().cstore.crates() { - externs.push((cnum, CrateNum(cnum).clean(cx))); + externs.push((cnum, cnum.clean(cx))); // Analyze doc-reachability for extern items LibEmbargoVisitor::new(cx).visit_lib(cnum); } externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); - // Figure out the name of this crate - let input = &cx.input; - let name = link::find_crate_name(None, &self.attrs, input); - // Clean the crate, translating the entire libsyntax AST to one that is // understood by rustdoc. let mut module = self.module.clean(cx); + 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 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 // primitives. // @@ -164,80 +204,50 @@ impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { // Also note that this does not attempt to deal with modules tagged // duplicately for the same primitive. This is handled later on when // rendering by delegating everything to a hash map. - let mut primitives = Vec::new(); - { - let m = match module.inner { - ModuleItem(ref mut m) => m, - _ => unreachable!(), - }; - let mut tmp = Vec::new(); - for child in &mut m.items { - if !child.is_mod() { - continue; + let as_primitive = |def: Def| { + if let Def::Mod(def_id) = def { + let attrs = cx.tcx.get_attrs(def_id).clean(cx); + let mut prim = None; + for attr in attrs.lists("doc") { + if let Some(v) = attr.value_str() { + if attr.check_name("primitive") { + prim = PrimitiveType::from_str(&v.as_str()); + if prim.is_some() { + break; + } + } + } } - let prim = match PrimitiveType::find(&child.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), - }); + return prim.map(|p| (def_id, p, attrs)); } - m.items.extend(tmp); - } - - let src = match cx.input { - Input::File(ref path) => { - if path.is_absolute() { - path.clone() - } else { - current_dir().unwrap().join(path) + None + }; + let primitives = if root.is_local() { + cx.tcx.map.krate().module.item_ids.iter().filter_map(|&id| { + let item = cx.tcx.map.expect_item(id.id); + match item.node { + hir::ItemMod(_) => { + as_primitive(Def::Mod(cx.tcx.map.local_def_id(id.id))) + } + hir::ItemUse(ref path, hir::UseKind::Single) + if item.vis == hir::Visibility::Public => { + as_primitive(path.def).map(|(_, prim, attrs)| { + // Pretend the primitive is local. + (cx.tcx.map.local_def_id(id.id), prim, attrs) + }) + } + _ => None } - }, - Input::Str { ref name, .. } => PathBuf::from(name.clone()), + }).collect() + } 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, -} - -impl Clean 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 { - name: cx.sess().cstore.crate_name(self.0).to_string(), - attrs: cx.sess().cstore.item_attrs(root).clean(cx), + name: cx.tcx.crate_name(*self).to_string(), + src: PathBuf::from(krate_src), + attrs: cx.tcx.get_attrs(root).clean(cx), primitives: primitives, } } @@ -1460,7 +1470,7 @@ impl<'tcx> Clean for ty::AssociatedItem { deprecation: get_deprecation(cx, self.def_id), def_id: self.def_id, attrs: inline::load_attrs(cx, self.def_id), - source: Span::empty(), + source: cx.tcx.def_span(self.def_id).clean(cx), inner: inner, } } @@ -1618,19 +1628,6 @@ impl PrimitiveType { } } - fn find(attrs: &Attributes) -> Option { - for attr in attrs.lists("doc") { - if let Some(v) = attr.value_str() { - if attr.check_name("primitive") { - if let ret@Some(..) = PrimitiveType::from_str(&v.as_str()) { - return ret; - } - } - } - } - None - } - pub fn as_str(&self) -> &'static str { match *self { PrimitiveType::Isize => "isize", @@ -1658,14 +1655,6 @@ impl PrimitiveType { pub fn to_url_str(&self) -> &'static str { self.as_str() } - - /// Creates a rustdoc-specific node id for primitive types. - /// - /// These node ids are generally never used by the AST itself. - pub fn to_def_index(&self) -> DefIndex { - let x = u32::MAX - 1 - (*self as u32); - DefIndex::new(x as usize) - } } impl From for PrimitiveType { @@ -1948,7 +1937,7 @@ impl<'tcx> Clean for ty::FieldDefData<'tcx, 'static> { Item { name: Some(self.name).clean(cx), attrs: cx.tcx.get_attrs(self.did).clean(cx), - source: Span::empty(), + source: cx.tcx.def_span(self.did).clean(cx), visibility: self.vis.clean(cx), stability: get_stability(cx, self.did), deprecation: get_deprecation(cx, self.did), @@ -2115,7 +2104,7 @@ impl<'tcx> Clean for ty::VariantDefData<'tcx, 'static> { fields_stripped: false, fields: self.fields.iter().map(|field| { Item { - source: Span::empty(), + source: cx.tcx.def_span(field.did).clean(cx), name: Some(field.name.clean(cx)), attrs: cx.tcx.get_attrs(field.did).clean(cx), visibility: field.vis.clean(cx), @@ -2131,7 +2120,7 @@ impl<'tcx> Clean for ty::VariantDefData<'tcx, 'static> { Item { name: Some(self.name.clean(cx)), attrs: inline::load_attrs(cx, self.did), - source: Span::empty(), + source: cx.tcx.def_span(self.did).clean(cx), visibility: Some(Inherited), def_id: self.did, inner: VariantItem(Variant { kind: kind }), diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 4c2487e2b42..df25473ddd9 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -45,7 +45,6 @@ pub type ExternalPaths = FxHashMap, clean::TypeKind)>; pub struct DocContext<'a, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - pub input: Input, pub populated_all_crate_impls: Cell, // 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 @@ -187,7 +186,6 @@ pub fn run_core(search_paths: SearchPaths, let ctxt = DocContext { tcx: tcx, - input: input, populated_all_crate_impls: Cell::new(false), access_levels: RefCell::new(access_levels), external_traits: Default::default(), diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index aed41916f5c..6dc6e80dae0 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -18,7 +18,7 @@ use std::fmt; use std::iter::repeat; -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::hir::def_id::DefId; use syntax::abi::Abi; use rustc::hir; @@ -403,9 +403,9 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec)> { None => match cache.external_paths.get(&did) { Some(&(ref fqp, shortty)) => { (fqp, shortty, match cache.extern_locations[&did.krate] { - (_, render::Remote(ref s)) => s.to_string(), - (_, render::Local) => repeat("../").take(loc.len()).collect(), - (_, render::Unknown) => return None, + (.., render::Remote(ref s)) => s.to_string(), + (.., render::Local) => repeat("../").take(loc.len()).collect(), + (.., render::Unknown) => return None, }) } None => return None, @@ -479,7 +479,7 @@ fn primitive_link(f: &mut fmt::Formatter, let mut needs_termination = false; if !f.alternate() { 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 = if len == 0 {0} else {len - 1}; write!(f, "", @@ -487,14 +487,16 @@ fn primitive_link(f: &mut fmt::Formatter, prim.to_url_str())?; needs_termination = true; } - Some(&cnum) => { - let loc = match m.extern_locations[&cnum] { - (ref cname, render::Remote(ref s)) => Some((cname, s.to_string())), - (ref cname, render::Local) => { + Some(&def_id) => { + let loc = match m.extern_locations[&def_id.krate] { + (ref cname, _, render::Remote(ref s)) => { + Some((cname, s.to_string())) + } + (ref cname, _, render::Local) => { let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len()); Some((cname, repeat("../").take(len).collect::())) } - (_, render::Unknown) => None, + (.., render::Unknown) => None, }; if let Some((cname, root)) = loc { write!(f, "", diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 757db81c440..cbf93662811 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -55,7 +55,7 @@ use externalfiles::ExternalHtml; use serialize::json::{ToJson, Json, as_json}; use syntax::{abi, ast}; 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::stability; use rustc::hir; @@ -241,10 +241,10 @@ pub struct Cache { pub implementors: FxHashMap>, /// Cache of where external crate documentation can be found. - pub extern_locations: FxHashMap, + pub extern_locations: FxHashMap, /// Cache of where documentation for primitives can be found. - pub primitive_locations: FxHashMap, + pub primitive_locations: FxHashMap, // 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 @@ -523,8 +523,13 @@ pub fn run(mut krate: clean::Crate, // Cache where all our extern crates are located 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))); + let did = DefId { krate: n, index: CRATE_DEF_INDEX }; 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 // reverse topological order. - for &(n, ref e) in krate.externs.iter().rev() { - for &prim in &e.primitives { - cache.primitive_locations.insert(prim, n); + for &(_, ref e) in krate.externs.iter().rev() { + for &(def_id, prim, _) in &e.primitives { + cache.primitive_locations.insert(prim, def_id); } } - for &prim in &krate.primitives { - cache.primitive_locations.insert(prim, LOCAL_CRATE); + for &(def_id, prim, _) in &krate.primitives { + cache.primitive_locations.insert(prim, def_id); } cache.stack.push(krate.name.clone()); @@ -875,6 +880,8 @@ impl<'a> DocFolder for SourceCollector<'a> { if self.scx.include_sources // skip all invalid spans && item.source.filename != "" + // skip non-local items + && item.def_id.is_local() // Macros from other libraries get special filenames which we can // safely ignore. && !(item.source.filename.starts_with("<") @@ -1127,13 +1134,15 @@ impl DocFolder for Cache { true } ref t => { - match t.primitive_type() { - Some(prim) => { - let did = DefId::local(prim.to_def_index()); + let prim_did = t.primitive_type().and_then(|t| { + self.primitive_locations.get(&t).cloned() + }); + match prim_did { + Some(did) => { self.parent_stack.push(did); true } - _ => false, + None => false, } } } @@ -1158,10 +1167,7 @@ impl DocFolder for Cache { } ref t => { t.primitive_type().and_then(|t| { - self.primitive_locations.get(&t).map(|n| { - let id = t.to_def_index(); - DefId { krate: *n, index: id } - }) + self.primitive_locations.get(&t).cloned() }) } } @@ -1439,79 +1445,50 @@ impl<'a> Item<'a> { /// If `None` is returned, then a source link couldn't be generated. This /// may happen, for example, with externally inlined items where the source /// of their crate documentation isn't known. - fn href(&self) -> Option { - let href = if self.item.source.loline == self.item.source.hiline { + fn src_href(&self) -> Option { + 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) } else { format!("{}-{}", self.item.source.loline, self.item.source.hiline) }; - - // 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, - 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())) - } + Some(format!("{root}src/{krate}/{path}#{lines}", + root = root, + krate = krate, + path = path, + lines = lines)) } } @@ -1576,10 +1553,9 @@ impl<'a> fmt::Display for Item<'a> { // this page, and this link will be auto-clicked. The `id` attribute is // used to find the link to auto-click. if self.cx.shared.include_sources && !self.item.is_primitive() { - if let Some(l) = self.href() { - write!(fmt, "[src]", - self.item.def_id.index.as_usize(), l, "goto source code")?; + if let Some(l) = self.src_href() { + write!(fmt, "[src]", + 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) } else { if let Some(prim) = target.primitive_type() { - if let Some(c) = cache().primitive_locations.get(&prim) { - let did = DefId { krate: *c, index: prim.to_def_index() }; + if let Some(&did) = cache().primitive_locations.get(&prim) { 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, "

{}", i.inner_impl())?; write!(w, "")?; 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, "
")?; render_stability_since_raw(w, since, outer_version)?; - write!(w, "[src]", - i.impl_item.def_id.index.as_usize(), l, "goto source code")?; + write!(w, "[src]", + l, "goto source code")?; } else { render_stability_since_raw(w, since, outer_version)?; } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 5ffab949d01..6ea25fa1241 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -923,15 +923,6 @@ 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) { if (sectionIsCollapsed) { // button will expand the section diff --git a/src/test/rustdoc/issue-34274.rs b/src/test/rustdoc/issue-34274.rs index 971c89b1619..12f88042161 100644 --- a/src/test/rustdoc/issue-34274.rs +++ b/src/test/rustdoc/issue-34274.rs @@ -16,5 +16,5 @@ 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; diff --git a/src/test/rustdoc/src-links-external.rs b/src/test/rustdoc/src-links-external.rs index e9db4f519ed..d3307bb4d42 100644 --- a/src/test/rustdoc/src-links-external.rs +++ b/src/test/rustdoc/src-links-external.rs @@ -11,12 +11,13 @@ // aux-build:src-links-external.rs // build-aux-docs // ignore-cross-compile +// ignore-tidy-linelength #![crate_name = "foo"] 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; -// @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'