about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2018-03-28 17:32:15 +0200
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2018-03-29 13:43:55 +0200
commit561e8efb7d221cc2f9274f3756cdf4c30556ae4b (patch)
treebe21b6791b4809e55d03d2e615a1d121cbfc3bdc
parentbcffdf1b6da161eecd761eb4a3ef703ff05c33f6 (diff)
downloadrust-561e8efb7d221cc2f9274f3756cdf4c30556ae4b.tar.gz
rust-561e8efb7d221cc2f9274f3756cdf4c30556ae4b.zip
Add primitive intra-links
-rw-r--r--src/librustdoc/clean/mod.rs85
-rw-r--r--src/test/rustdoc/primitive-link.rs19
2 files changed, 91 insertions, 13 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 42c9d9e52f3..62e5f730cae 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -19,6 +19,7 @@ pub use self::SelfTy::*;
 pub use self::FunctionRetTy::*;
 pub use self::Visibility::*;
 
+use syntax;
 use syntax::abi::Abi;
 use syntax::ast::{self, AttrStyle};
 use syntax::attr;
@@ -64,6 +65,7 @@ use std::u32;
 use core::{self, DocContext};
 use doctree;
 use visit_ast;
+use html::render::{cache, ExternalLocation};
 use html::item_type::ItemType;
 use html::markdown::markdown_links;
 
@@ -346,7 +348,7 @@ impl Item {
     }
 
     pub fn links(&self) -> Vec<(String, String)> {
-        self.attrs.links()
+        self.attrs.links(&self.def_id.krate)
     }
 
     pub fn is_crate(&self) -> bool {
@@ -697,7 +699,7 @@ pub struct Attributes {
     pub cfg: Option<Rc<Cfg>>,
     pub span: Option<syntax_pos::Span>,
     /// map from Rust paths to resolved defs and potential URL fragments
-    pub links: Vec<(String, DefId, Option<String>)>,
+    pub links: Vec<(String, Option<DefId>, Option<String>)>,
 }
 
 impl Attributes {
@@ -869,17 +871,41 @@ impl Attributes {
     /// Get links as a vector
     ///
     /// Cache must be populated before call
-    pub fn links(&self) -> Vec<(String, String)> {
+    pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> {
         use html::format::href;
         self.links.iter().filter_map(|&(ref s, did, ref fragment)| {
-            if let Some((mut href, ..)) = href(did) {
-                if let Some(ref fragment) = *fragment {
-                    href.push_str("#");
-                    href.push_str(fragment);
+            match did {
+                Some(did) => {
+                    if let Some((mut href, ..)) = href(did) {
+                        if let Some(ref fragment) = *fragment {
+                            href.push_str("#");
+                            href.push_str(fragment);
+                        }
+                        Some((s.clone(), href))
+                    } else {
+                        None
+                    }
+                }
+                None => {
+                    if let Some(ref fragment) = *fragment {
+                        let cache = cache();
+                        let url = match cache.extern_locations.get(krate) {
+                            Some(&(_, ref src, ExternalLocation::Local)) =>
+                                src.to_str().expect("invalid file path"),
+                            Some(&(_, _, ExternalLocation::Remote(ref s))) => s,
+                            Some(&(_, _, ExternalLocation::Unknown)) | None =>
+                                "https://doc.rust-lang.org/nightly",
+                        };
+                        // This is a primitive so the url is done "by hand".
+                        Some((s.clone(),
+                              format!("{}{}std/primitive.{}.html",
+                                      url,
+                                      if !url.ends_with('/') { "/" } else { "" },
+                                      fragment)))
+                    } else {
+                        panic!("This isn't a primitive?!");
+                    }
                 }
-                Some((s.clone(), href))
-            } else {
-                None
             }
         }).collect()
     }
@@ -959,6 +985,34 @@ fn handle_variant(cx: &DocContext, def: Def) -> Result<(Def, Option<String>), ()
     Ok((parent_def, Some(format!("{}.v", variant.name))))
 }
 
+const PRIMITIVES: &[(&str, Def)] = &[
+    ("u8",    Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U8))),
+    ("u16",   Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U16))),
+    ("u32",   Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U32))),
+    ("u64",   Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U64))),
+    ("u128",  Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U128))),
+    ("usize", Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::Usize))),
+    ("i8",    Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I8))),
+    ("i16",   Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I16))),
+    ("i32",   Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I32))),
+    ("i64",   Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I64))),
+    ("i128",  Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I128))),
+    ("isize", Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::Isize))),
+    ("f32",   Def::PrimTy(hir::PrimTy::TyFloat(syntax::ast::FloatTy::F32))),
+    ("f64",   Def::PrimTy(hir::PrimTy::TyFloat(syntax::ast::FloatTy::F64))),
+    ("str",   Def::PrimTy(hir::PrimTy::TyStr)),
+    ("bool",  Def::PrimTy(hir::PrimTy::TyBool)),
+    ("char",  Def::PrimTy(hir::PrimTy::TyChar)),
+];
+
+fn is_primitive(path_str: &str, is_val: bool) -> Option<Def> {
+    if is_val {
+        None
+    } else {
+        PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1)
+    }
+}
+
 /// Resolve a given string as a path, along with whether or not it is
 /// in the value namespace. Also returns an optional URL fragment in the case
 /// of variants and methods
@@ -987,6 +1041,8 @@ fn resolve(cx: &DocContext, path_str: &str, is_val: bool) -> Result<(Def, Option
             if value != is_val {
                 return Err(())
             }
+        } else if let Some(prim) = is_primitive(path_str, is_val) {
+            return Ok((prim, Some(path_str.to_owned())))
         } else {
             // If resolution failed, it may still be a method
             // because methods are not handled by the resolver
@@ -1051,7 +1107,6 @@ fn resolve(cx: &DocContext, path_str: &str, is_val: bool) -> Result<(Def, Option
             }
             _ => Err(())
         }
-
     } else {
         Err(())
     }
@@ -1218,8 +1273,12 @@ impl Clean<Attributes> for [ast::Attribute] {
                     }
                 };
 
-                let id = register_def(cx, def);
-                attrs.links.push((ori_link, id, fragment));
+                if let Def::PrimTy(_) = def {
+                    attrs.links.push((ori_link, None, fragment));
+                } else {
+                    let id = register_def(cx, def);
+                    attrs.links.push((ori_link, Some(id), fragment));
+                }
             }
 
             cx.sess().abort_if_errors();
diff --git a/src/test/rustdoc/primitive-link.rs b/src/test/rustdoc/primitive-link.rs
new file mode 100644
index 00000000000..b0cf8acc7c0
--- /dev/null
+++ b/src/test/rustdoc/primitive-link.rs
@@ -0,0 +1,19 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "foo"]
+
+// ignore-tidy-linelength
+
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.u32.html"]' 'u32'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i64.html"]' 'i64'
+
+/// It contains [`u32`] and [i64].
+pub struct Foo;