]> git.lizzy.rs Git - rust.git/commitdiff
Fix invalid associated type rendering in rustdoc
authorGuillaume Gomez <guillaume1.gomez@gmail.com>
Wed, 12 Apr 2017 16:14:54 +0000 (18:14 +0200)
committerGuillaume Gomez <guillaume1.gomez@gmail.com>
Wed, 12 Apr 2017 16:14:54 +0000 (18:14 +0200)
src/librustdoc/clean/mod.rs
src/librustdoc/html/format.rs
src/test/rustdoc/assoc-item-cast.rs [new file with mode: 0644]

index ac72d7d29a24c4813839cd5b7185544ee269b698..2511560e8726188efaeaf7400d62e2bbfc22f0c1 100644 (file)
@@ -2277,7 +2277,7 @@ fn clean(&self, cx: &DocContext) -> PathParameters {
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
 pub struct PathSegment {
     pub name: String,
-    pub params: PathParameters
+    pub params: PathParameters,
 }
 
 impl Clean<PathSegment> for hir::PathSegment {
index ffef42bc3d27ce1fe398c0d5dee6386c427a79d5..0f47265a1aa6630e3620a8da230aff5141b91e87 100644 (file)
@@ -470,10 +470,22 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
 /// rendering function with the necessary arguments for linking to a local path.
 fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
                  print_all: bool, use_absolute: bool, is_not_debug: bool) -> fmt::Result {
-    let last = path.segments.last().unwrap();
-    let rel_root = match &*path.segments[0].name {
-        "self" => Some("./".to_string()),
-        _ => None,
+    let empty = clean::PathSegment {
+                    name: String::new(),
+                    params: clean::PathParameters::Parenthesized {
+                        inputs: Vec::new(),
+                        output: None,
+                    }
+                };
+    let last = path.segments.last()
+                            .unwrap_or(&empty);
+    let rel_root = if path.segments.is_empty() {
+        None
+    } else {
+        match &*path.segments[0].name {
+            "self" => Some("./".to_string()),
+            _ => None,
+        }
     };
 
     if print_all {
@@ -487,10 +499,9 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
                         root.push_str(&seg.name);
                         root.push_str("/");
                         if is_not_debug {
-                            write!(w, "<a class=\"mod\"
-                                           href=\"{}index.html\">{}</a>::",
-                                     root,
-                                     seg.name)?;
+                            write!(w, "<a class=\"mod\" href=\"{}index.html\">{}</a>::",
+                                   root,
+                                   seg.name)?;
                         } else {
                             write!(w, "{}::", seg.name)?;
                         }
@@ -516,7 +527,8 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
                 match href(did) {
                     Some((_, _, fqp)) => format!("{}::{}",
                                                  fqp[..fqp.len()-1].join("::"),
-                                                 HRef::new(did, fqp.last().unwrap())),
+                                                 HRef::new(did, fqp.last()
+                                                                   .unwrap_or(&String::new()))),
                     None => format!("{}", HRef::new(did, &last.name)),
                 }
             } else {
@@ -528,7 +540,8 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
                 match href(did) {
                     Some((_, _, fqp)) => format!("{:?}::{:?}",
                                                  fqp[..fqp.len()-1].join("::"),
-                                                 HRef::new(did, fqp.last().unwrap())),
+                                                 HRef::new(did, fqp.last()
+                                                                   .unwrap_or(&String::new()))),
                     None => format!("{:?}", HRef::new(did, &last.name)),
                 }
             } else {
@@ -801,45 +814,65 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool,
             }
             Ok(())
         }
-        // It's pretty unsightly to look at `<A as B>::C` in output, and
-        // we've got hyperlinking on our side, so try to avoid longer
-        // notation as much as possible by making `C` a hyperlink to trait
-        // `B` to disambiguate.
-        //
-        // FIXME: this is still a lossy conversion and there should probably
-        //        be a better way of representing this in general? Most of
-        //        the ugliness comes from inlining across crates where
-        //        everything comes in as a fully resolved QPath (hard to
-        //        look at).
-        clean::QPath {
-            ref name,
-            ref self_type,
-            trait_: box clean::ResolvedPath { did, ref typarams, .. },
-        } => {
-            if f.alternate() {
-                write!(f, "{:#}::", self_type)?;
-            } else {
-                write!(f, "{}::", self_type)?;
-            }
-            let path = clean::Path::singleton(name.clone());
-            resolved_path(f, did, &path, true, use_absolute, is_not_debug)?;
-
-            // FIXME: `typarams` are not rendered, and this seems bad?
-            drop(typarams);
-            Ok(())
-        }
         clean::QPath { ref name, ref self_type, ref trait_ } => {
+            let should_show_cast = match *trait_ {
+                box clean::ResolvedPath { .. } => {
+                    let path = clean::Path::singleton(name.clone());
+                    !path.segments.is_empty() && &format!("{:#}", trait_) != "()" &&
+                    &format!("{:#}", self_type) != "Self"
+                }
+                _ => true,
+            };
             if f.alternate() {
                 if is_not_debug {
-                    write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name)
+                    if should_show_cast {
+                        write!(f, "<{:#} as {:#}>::", self_type, trait_)?
+                    } else {
+                        write!(f, "{:#}::", self_type)?
+                    }
                 } else {
-                    write!(f, "<{:#?} as {:#?}>::{}", self_type, trait_, name)
+                    if should_show_cast {
+                        write!(f, "<{:#?} as {:#?}>::", self_type, trait_)?
+                    } else {
+                        write!(f, "{:#?}::", self_type)?
+                    }
                 }
             } else {
                 if is_not_debug {
-                    write!(f, "&lt;{} as {}&gt;::{}", self_type, trait_, name)
+                    if should_show_cast {
+                        write!(f, "&lt;{} as {}&gt;::", self_type, trait_)?
+                    } else {
+                        write!(f, "{}::", self_type)?
+                    }
                 } else {
-                    write!(f, "<{:?} as {:?}>::{}", self_type, trait_, name)
+                    if should_show_cast {
+                        write!(f, "<{:?} as {:?}>::", self_type, trait_)?
+                    } else {
+                        write!(f, "{:?}::", self_type)?
+                    }
+                }
+            };
+            match *trait_ {
+                // It's pretty unsightly to look at `<A as B>::C` in output, and
+                // we've got hyperlinking on our side, so try to avoid longer
+                // notation as much as possible by making `C` a hyperlink to trait
+                // `B` to disambiguate.
+                //
+                // FIXME: this is still a lossy conversion and there should probably
+                //        be a better way of representing this in general? Most of
+                //        the ugliness comes from inlining across crates where
+                //        everything comes in as a fully resolved QPath (hard to
+                //        look at).
+                box clean::ResolvedPath { did, ref typarams, .. } => {
+                    let path = clean::Path::singleton(name.clone());
+                    resolved_path(f, did, &path, true, use_absolute, is_not_debug)?;
+
+                    // FIXME: `typarams` are not rendered, and this seems bad?
+                    drop(typarams);
+                    Ok(())
+                }
+                _ => {
+                    write!(f, "{}", name)
                 }
             }
         }
diff --git a/src/test/rustdoc/assoc-item-cast.rs b/src/test/rustdoc/assoc-item-cast.rs
new file mode 100644 (file)
index 0000000..24f31b5
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2017 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
+
+pub trait Expression {
+    type SqlType;
+}
+
+pub trait AsExpression<T> {
+    type Expression: Expression<SqlType = T>;
+    fn as_expression(self) -> Self::Expression;
+}
+
+// @has foo/type.AsExprOf.html
+// @has - '//*[@class="rust typedef"]' 'type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;'
+pub type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;