]> git.lizzy.rs Git - rust.git/commitdiff
rustdoc: link to cross-crate sources directly.
authorEduard-Mihai Burtescu <edy.burt@gmail.com>
Tue, 29 Nov 2016 06:15:16 +0000 (08:15 +0200)
committerEduard-Mihai Burtescu <edy.burt@gmail.com>
Wed, 30 Nov 2016 02:48:56 +0000 (04:48 +0200)
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/core.rs
src/librustdoc/html/format.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/main.js
src/test/rustdoc/issue-34274.rs
src/test/rustdoc/src-links-external.rs

index e3274611e5bff3ee30ba50c61b825865e20e7dfa..bf739abe3da0dc65134672eb5d6b3ad1b324e0db 100644 (file)
@@ -115,7 +115,7 @@ fn try_inline_def(cx: &DocContext, def: Def) -> Option<Vec<clean::Item>> {
     let did = def.def_id();
     cx.renderinfo.borrow_mut().inlined.insert(did);
     ret.push(clean::Item {
-        source: clean::Span::empty(),
+        source: tcx.def_span(did).clean(cx),
         name: Some(tcx.item_name(did).to_string()),
         attrs: load_attrs(cx, did),
         inner: inner,
@@ -321,7 +321,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
                     clean::RegionBound(..) => unreachable!(),
                 },
             }),
-            source: clean::Span::empty(),
+            source: tcx.def_span(did).clean(cx),
             name: None,
             attrs: attrs,
             visibility: Some(clean::Inherited),
@@ -357,7 +357,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
                         tcx.item_type(item.def_id).clean(cx),
                         default,
                     ),
-                    source: clean::Span::empty(),
+                    source: tcx.def_span(item.def_id).clean(cx),
                     attrs: clean::Attributes::default(),
                     visibility: None,
                     stability: tcx.lookup_stability(item.def_id).clean(cx),
@@ -404,7 +404,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
                 Some(clean::Item {
                     name: Some(item.name.clean(cx)),
                     inner: clean::TypedefItem(typedef, true),
-                    source: clean::Span::empty(),
+                    source: tcx.def_span(item.def_id).clean(cx),
                     attrs: clean::Attributes::default(),
                     visibility: None,
                     stability: tcx.lookup_stability(item.def_id).clean(cx),
@@ -442,7 +442,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
             items: trait_items,
             polarity: Some(polarity.clean(cx)),
         }),
-        source: clean::Span::empty(),
+        source: tcx.def_span(did).clean(cx),
         name: None,
         attrs: attrs,
         visibility: Some(clean::Inherited),
index e233613ee629e8844652371a4fd86ec96ec82f99..dba613ed1b6b37ea1673f71afe772ca5cc8bcb7b 100644 (file)
 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::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<Item>,
-    pub externs: Vec<(def_id::CrateNum, ExternalCrate)>,
-    pub primitives: Vec<PrimitiveType>,
+    pub externs: Vec<(CrateNum, ExternalCrate)>,
+    pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
     pub access_levels: Arc<AccessLevels<DefId>>,
     // These are later on moved into `CACHEKEY`, leaving the map empty.
     // Only here so that they can be filtered through the rustdoc passes.
     pub external_traits: FxHashMap<DefId, Trait>,
 }
 
-struct CrateNum(def_id::CrateNum);
-
 impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
     fn clean(&self, cx: &DocContext) -> Crate {
-        use rustc::session::config::Input;
         use ::visit_lib::LibEmbargoVisitor;
 
         {
@@ -133,83 +128,41 @@ fn clean(&self, cx: &DocContext) -> Crate {
 
         let mut externs = Vec::new();
         for cnum in cx.sess().cstore.crates() {
-            externs.push((cnum, CrateNum(cnum).clean(cx)));
+            externs.push((cnum, cnum.clean(cx)));
             // Analyze doc-reachability for extern items
             LibEmbargoVisitor::new(cx).visit_lib(cnum);
         }
         externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
 
-        // Figure out the name of this crate
-        let input = &cx.input;
-        let name = link::find_crate_name(None, &self.attrs, input);
-
         // Clean the crate, translating the entire libsyntax AST to one that is
         // understood by rustdoc.
         let mut module = self.module.clean(cx);
 
-        // Collect all inner modules which are tagged as implementations of
-        // primitives.
-        //
-        // Note that this loop only searches the top-level items of the crate,
-        // and this is intentional. If we were to search the entire crate for an
-        // item tagged with `#[doc(primitive)]` then we would also have to
-        // search the entirety of external modules for items tagged
-        // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
-        // all that metadata unconditionally).
-        //
-        // In order to keep the metadata load under control, the
-        // `#[doc(primitive)]` feature is explicitly designed to only allow the
-        // primitive tags to show up as the top level items in a crate.
-        //
-        // Also note that this does not attempt to deal with modules tagged
-        // duplicately for the same primitive. This is handled later on when
-        // rendering by delegating everything to a hash map.
-        let mut primitives = Vec::new();
+        let ExternalCrate { name, src, primitives, .. } = LOCAL_CRATE.clean(cx);
         {
             let m = match module.inner {
                 ModuleItem(ref mut m) => m,
                 _ => unreachable!(),
             };
-            let mut tmp = Vec::new();
-            for child in &mut m.items {
-                if !child.is_mod() {
-                    continue;
-                }
-                let prim = match PrimitiveType::find(&child.attrs) {
-                    Some(prim) => prim,
-                    None => continue,
-                };
-                primitives.push(prim);
-                tmp.push(Item {
+            m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| {
+                Item {
                     source: Span::empty(),
                     name: Some(prim.to_url_str().to_string()),
-                    attrs: child.attrs.clone(),
+                    attrs: attrs.clone(),
                     visibility: Some(Public),
                     stability: None,
                     deprecation: None,
-                    def_id: DefId::local(prim.to_def_index()),
+                    def_id: def_id,
                     inner: PrimitiveItem(prim),
-                });
-            }
-            m.items.extend(tmp);
-        }
-
-        let src = match cx.input {
-            Input::File(ref path) => {
-                if path.is_absolute() {
-                    path.clone()
-                } else {
-                    current_dir().unwrap().join(path)
                 }
-            },
-            Input::Str { ref name, .. } => PathBuf::from(name.clone()),
-        };
+            }));
+        }
 
         let mut access_levels = cx.access_levels.borrow_mut();
         let mut external_traits = cx.external_traits.borrow_mut();
 
         Crate {
-            name: name.to_string(),
+            name: name,
             src: src,
             module: Some(module),
             externs: externs,
@@ -223,21 +176,78 @@ fn clean(&self, cx: &DocContext) -> Crate {
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct ExternalCrate {
     pub name: String,
+    pub src: PathBuf,
     pub attrs: Attributes,
-    pub primitives: Vec<PrimitiveType>,
+    pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
 }
 
 impl Clean<ExternalCrate> for CrateNum {
     fn clean(&self, cx: &DocContext) -> ExternalCrate {
-        let mut primitives = Vec::new();
-        let root = DefId { krate: self.0, index: CRATE_DEF_INDEX };
-        for item in cx.tcx.sess.cstore.item_children(root) {
-            let attrs = inline::load_attrs(cx, item.def.def_id());
-            PrimitiveType::find(&attrs).map(|prim| primitives.push(prim));
-        }
+        let root = DefId { krate: *self, index: CRATE_DEF_INDEX };
+        let krate_span = cx.tcx.def_span(root);
+        let krate_src = cx.sess().codemap().span_to_filename(krate_span);
+
+        // Collect all inner modules which are tagged as implementations of
+        // primitives.
+        //
+        // Note that this loop only searches the top-level items of the crate,
+        // and this is intentional. If we were to search the entire crate for an
+        // item tagged with `#[doc(primitive)]` then we would also have to
+        // search the entirety of external modules for items tagged
+        // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
+        // all that metadata unconditionally).
+        //
+        // In order to keep the metadata load under control, the
+        // `#[doc(primitive)]` feature is explicitly designed to only allow the
+        // primitive tags to show up as the top level items in a crate.
+        //
+        // Also note that this does not attempt to deal with modules tagged
+        // duplicately for the same primitive. This is handled later on when
+        // rendering by delegating everything to a hash map.
+        let as_primitive = |def: Def| {
+            if let Def::Mod(def_id) = def {
+                let attrs = cx.tcx.get_attrs(def_id).clean(cx);
+                let mut prim = None;
+                for attr in attrs.lists("doc") {
+                    if let Some(v) = attr.value_str() {
+                        if attr.check_name("primitive") {
+                            prim = PrimitiveType::from_str(&v.as_str());
+                            if prim.is_some() {
+                                break;
+                            }
+                        }
+                    }
+                }
+                return prim.map(|p| (def_id, p, attrs));
+            }
+            None
+        };
+        let primitives = if root.is_local() {
+            cx.tcx.map.krate().module.item_ids.iter().filter_map(|&id| {
+                let item = cx.tcx.map.expect_item(id.id);
+                match item.node {
+                    hir::ItemMod(_) => {
+                        as_primitive(Def::Mod(cx.tcx.map.local_def_id(id.id)))
+                    }
+                    hir::ItemUse(ref path, hir::UseKind::Single)
+                    if item.vis == hir::Visibility::Public => {
+                        as_primitive(path.def).map(|(_, prim, attrs)| {
+                            // Pretend the primitive is local.
+                            (cx.tcx.map.local_def_id(id.id), prim, attrs)
+                        })
+                    }
+                    _ => None
+                }
+            }).collect()
+        } else {
+            cx.tcx.sess.cstore.item_children(root).iter().map(|item| item.def)
+              .filter_map(as_primitive).collect()
+        };
+
         ExternalCrate {
-            name: cx.sess().cstore.crate_name(self.0).to_string(),
-            attrs: cx.sess().cstore.item_attrs(root).clean(cx),
+            name: cx.tcx.crate_name(*self).to_string(),
+            src: PathBuf::from(krate_src),
+            attrs: cx.tcx.get_attrs(root).clean(cx),
             primitives: primitives,
         }
     }
@@ -1460,7 +1470,7 @@ fn clean(&self, cx: &DocContext) -> Item {
             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 @@ fn from_str(s: &str) -> Option<PrimitiveType> {
         }
     }
 
-    fn find(attrs: &Attributes) -> Option<PrimitiveType> {
-        for attr in attrs.lists("doc") {
-            if let Some(v) = attr.value_str() {
-                if attr.check_name("primitive") {
-                    if let ret@Some(..) = PrimitiveType::from_str(&v.as_str()) {
-                        return ret;
-                    }
-                }
-            }
-        }
-        None
-    }
-
     pub fn as_str(&self) -> &'static str {
         match *self {
             PrimitiveType::Isize => "isize",
@@ -1658,14 +1655,6 @@ pub fn as_str(&self) -> &'static str {
     pub fn to_url_str(&self) -> &'static str {
         self.as_str()
     }
-
-    /// Creates a rustdoc-specific node id for primitive types.
-    ///
-    /// These node ids are generally never used by the AST itself.
-    pub fn to_def_index(&self) -> DefIndex {
-        let x = u32::MAX - 1 - (*self as u32);
-        DefIndex::new(x as usize)
-    }
 }
 
 impl From<ast::IntTy> for PrimitiveType {
@@ -1948,7 +1937,7 @@ fn clean(&self, cx: &DocContext) -> Item {
         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 @@ fn clean(&self, cx: &DocContext) -> Item {
                     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 @@ fn clean(&self, cx: &DocContext) -> Item {
         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 }),
index 4c2487e2b42a0b855f565caf4c87562955dcc250..df25473ddd91666640bcaabc9e22a14181b1c48f 100644 (file)
@@ -45,7 +45,6 @@
 
 pub struct DocContext<'a, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    pub input: Input,
     pub populated_all_crate_impls: Cell<bool>,
     // Note that external items for which `doc(hidden)` applies to are shown as
     // non-reachable while local items aren't. This is because we're reusing
@@ -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(),
index aed41916f5c536594c73d9f557e681e36bf832af..6dc6e80dae0b81fb926e5238e145fedcb07704ce 100644 (file)
@@ -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<String>)> {
         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, "<a class='primitive' href='{}primitive.{}.html'>",
@@ -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::<String>()))
                     }
-                    (_, render::Unknown) => None,
+                    (.., render::Unknown) => None,
                 };
                 if let Some((cname, root)) = loc {
                     write!(f, "<a class='primitive' href='{}{}/primitive.{}.html'>",
index 757db81c4402196fc43e77a6547639117b591b0e..cbf93662811da6ee046cf69269cb93e0dbbc36fe 100644 (file)
@@ -55,7 +55,7 @@
 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<DefId, Vec<Implementor>>,
 
     /// 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.
-    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
     // 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 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         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 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                         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 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                         }
                         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<String> {
-        let href = if self.item.source.loline == self.item.source.hiline {
-            format!("{}", self.item.source.loline)
-        } else {
-            format!("{}-{}", self.item.source.loline, self.item.source.hiline)
-        };
+    fn src_href(&self) -> Option<String> {
+        let mut root = self.cx.root_path();
 
-        // 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 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);
-            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`.
+            if let Some(path) = self.cx.shared.local_sources.get(&path) {
+                (&self.cx.shared.layout.krate, path)
+            } else {
+                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,
+            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,
             };
-            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()))
-        }
+
+            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)
+        };
+        Some(format!("{root}src/{krate}/{path}#{lines}",
+                     root = root,
+                     krate = krate,
+                     path = path,
+                     lines = lines))
     }
 }
 
@@ -1576,10 +1553,9 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         // 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, "<a id='src-{}' class='srclink' \
-                              href='{}' title='{}'>[src]</a>",
-                       self.item.def_id.index.as_usize(), l, "goto source code")?;
+            if let Some(l) = self.src_href() {
+                write!(fmt, "<a class='srclink' href='{}' title='{}'>[src]</a>",
+                       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, "<h3 class='impl'><span class='in-band'><code>{}</code>", i.inner_impl())?;
         write!(w, "</span><span class='out-of-band'>")?;
         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>")?;
             render_stability_since_raw(w, since, outer_version)?;
-            write!(w, "<a id='src-{}' class='srclink' \
-                       href='{}' title='{}'>[src]</a>",
-                   i.impl_item.def_id.index.as_usize(), l, "goto source code")?;
+            write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a>",
+                   l, "goto source code")?;
         } else {
             render_stability_since_raw(w, since, outer_version)?;
         }
index 5ffab949d019c38afde76552f7d07b9e5d2bd861..6ea25fa1241f8c447c9e845f87dab6a1de786672 100644 (file)
         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
index 971c89b1619ed3ff907d2c182415a044f395e6ca..12f880421616f513810adc561fffd23cc84fe310 100644 (file)
@@ -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;
index e9db4f519ed979101a932cfd47628fa5ace09cbf..d3307bb4d42c1076f23e1df42d9f9c4392bafb38 100644 (file)
 // 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'