From 2792b56a92eec4a88b2d625d4584074c3918ef6f Mon Sep 17 00:00:00 2001
From: kennytm <kennytm@gmail.com>
Date: Wed, 15 Nov 2017 17:31:23 +0800
Subject: [PATCH] Support `extern type` in rustdoc.

Fixes #45640.
---
 src/librustdoc/clean/inline.rs             |  5 ++++
 src/librustdoc/html/render.rs              | 31 ++++++++++++++++++++--
 src/librustdoc/html/static/main.js         |  4 ++-
 src/librustdoc/html/static/styles/main.css |  2 ++
 src/test/rustdoc/foreigntype.rs            | 28 +++++++++++++++++++
 5 files changed, 67 insertions(+), 3 deletions(-)
 create mode 100644 src/test/rustdoc/foreigntype.rs

diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 9fb9437e1bc9a..4c518167e088d 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -77,6 +77,11 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name)
             ret.extend(build_impls(cx, did));
             clean::EnumItem(build_enum(cx, did))
         }
+        Def::TyForeign(did) => {
+            record_extern_fqn(cx, did, clean::TypeKind::Foreign);
+            ret.extend(build_impls(cx, did));
+            clean::ForeignTypeItem
+        }
         // Never inline enum variants but leave them shown as reexports.
         Def::Variant(..) => return None,
         // Assume that enum variants and struct types are reexported next to
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 69eaf24289bfc..27a27c71bc9da 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -1257,7 +1257,7 @@ impl DocFolder for Cache {
             clean::FunctionItem(..) | clean::ModuleItem(..) |
             clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
             clean::ConstantItem(..) | clean::StaticItem(..) |
-            clean::UnionItem(..)
+            clean::UnionItem(..) | clean::ForeignTypeItem
             if !self.stripped_mod => {
                 // Reexported items mean that the same id can show up twice
                 // in the rustdoc ast that we're looking at. We know,
@@ -1292,7 +1292,7 @@ impl DocFolder for Cache {
         // Maintain the parent stack
         let orig_parent_is_trait_impl = self.parent_is_trait_impl;
         let parent_pushed = match item.inner {
-            clean::TraitItem(..) | clean::EnumItem(..) |
+            clean::TraitItem(..) | clean::EnumItem(..) | clean::ForeignTypeItem |
             clean::StructItem(..) | clean::UnionItem(..) => {
                 self.parent_stack.push(item.def_id);
                 self.parent_is_trait_impl = false;
@@ -1711,6 +1711,7 @@ impl<'a> fmt::Display for Item<'a> {
             clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?,
             clean::StaticItem(..) | clean::ForeignStaticItem(..) => write!(fmt, "Static ")?,
             clean::ConstantItem(..) => write!(fmt, "Constant ")?,
+            clean::ForeignTypeItem => write!(fmt, "Foreign Type ")?,
             _ => {
                 // We don't generate pages for any other type.
                 unreachable!();
@@ -1775,6 +1776,7 @@ impl<'a> fmt::Display for Item<'a> {
             clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) =>
                 item_static(fmt, self.cx, self.item, i),
             clean::ConstantItem(ref c) => item_constant(fmt, self.cx, self.item, c),
+            clean::ForeignTypeItem => item_foreign_type(fmt, self.cx, self.item),
             _ => {
                 // We don't generate pages for any other type.
                 unreachable!();
@@ -3429,6 +3431,21 @@ fn item_typedef(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
 }
 
+fn item_foreign_type(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item) -> fmt::Result {
+    writeln!(w, "<pre class='rust foreigntype'>extern {{")?;
+    render_attributes(w, it)?;
+    write!(
+        w,
+        "    {}type {};\n}}</pre>",
+        VisSpace(&it.visibility),
+        it.name.as_ref().unwrap(),
+    )?;
+
+    document(w, cx, it)?;
+
+    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+}
+
 impl<'a> fmt::Display for Sidebar<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         let cx = self.cx;
@@ -3446,6 +3463,7 @@ impl<'a> fmt::Display for Sidebar<'a> {
                 clean::UnionItem(..) => write!(fmt, "Union ")?,
                 clean::EnumItem(..) => write!(fmt, "Enum ")?,
                 clean::TypedefItem(..) => write!(fmt, "Type Definition ")?,
+                clean::ForeignTypeItem => write!(fmt, "Foreign Type ")?,
                 clean::ModuleItem(..) => if it.is_crate() {
                     write!(fmt, "Crate ")?;
                 } else {
@@ -3474,6 +3492,7 @@ impl<'a> fmt::Display for Sidebar<'a> {
                 clean::EnumItem(ref e) => sidebar_enum(fmt, it, e)?,
                 clean::TypedefItem(ref t, _) => sidebar_typedef(fmt, it, t)?,
                 clean::ModuleItem(ref m) => sidebar_module(fmt, it, &m.items)?,
+                clean::ForeignTypeItem => sidebar_foreign_type(fmt, it)?,
                 _ => (),
             }
         }
@@ -3897,6 +3916,14 @@ fn sidebar_module(fmt: &mut fmt::Formatter, _it: &clean::Item,
     Ok(())
 }
 
+fn sidebar_foreign_type(fmt: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
+    let sidebar = sidebar_assoc_items(it);
+    if !sidebar.is_empty() {
+        write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?;
+    }
+    Ok(())
+}
+
 impl<'a> fmt::Display for Source<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         let Source(s) = *self;
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 8d0faf261f6c9..3350a9f73876f 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -37,7 +37,8 @@
                      "associatedtype",
                      "constant",
                      "associatedconstant",
-                     "union"];
+                     "union",
+                     "foreigntype"];
 
     // On the search screen, so you remain on the last tab you opened.
     //
@@ -1445,6 +1446,7 @@
         block("trait", "Traits");
         block("fn", "Functions");
         block("type", "Type Definitions");
+        block("foreigntype", "Foreign Types");
     }
 
     window.initSidebarItems = initSidebarItems;
diff --git a/src/librustdoc/html/static/styles/main.css b/src/librustdoc/html/static/styles/main.css
index 4a4ca15170a46..cb19034bf0612 100644
--- a/src/librustdoc/html/static/styles/main.css
+++ b/src/librustdoc/html/static/styles/main.css
@@ -104,6 +104,7 @@ pre {
 .content .highlighted.method,
 .content .highlighted.tymethod { background-color: #c6afb3; }
 .content .highlighted.type { background-color: #ffc891; }
+.content .highlighted.foreigntype { background-color: #f5c4ff; }
 .content .highlighted.macro { background-color: #8ce488; }
 .content .highlighted.constant,
 .content .highlighted.static { background-color: #c3e0ff; }
@@ -112,6 +113,7 @@ pre {
 .content span.enum, .content a.enum, .block a.current.enum { color: #508157; }
 .content span.struct, .content a.struct, .block a.current.struct { color: #df3600; }
 .content span.type, .content a.type, .block a.current.type { color: #ba5d00; }
+.content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #cd00e2; }
 .content span.macro, .content a.macro, .block a.current.macro { color: #068000; }
 .content span.union, .content a.union, .block a.current.union { color: #767b27; }
 .content span.constant, .content a.constant, .block a.current.constant,
diff --git a/src/test/rustdoc/foreigntype.rs b/src/test/rustdoc/foreigntype.rs
new file mode 100644
index 0000000000000..06447ffaa753d
--- /dev/null
+++ b/src/test/rustdoc/foreigntype.rs
@@ -0,0 +1,28 @@
+// 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.
+
+#![feature(extern_types)]
+
+extern {
+    // @has foreigntype/foreigntype.ExtType.html
+    pub type ExtType;
+}
+
+impl ExtType {
+    // @has - '//a[@class="fnname"]' 'do_something'
+    pub fn do_something(&self) {}
+}
+
+pub trait Trait {}
+
+// @has foreigntype/trait.Trait.html '//a[@class="foreigntype"]' 'ExtType'
+impl Trait for ExtType {}
+
+// @has foreigntype/index.html '//a[@class="foreigntype"]' 'ExtType'