about summary refs log tree commit diff
diff options
context:
space:
mode:
authormitaa <mitaa.ceb@gmail.com>2016-03-10 03:29:46 +0100
committermitaa <mitaa.ceb@gmail.com>2016-03-10 03:29:46 +0100
commita20e6bb1627f8669b334e673740f78e435cd0321 (patch)
treef3825fc32fd7bd26183e1ded8a50868668bf4e86
parentae7fca1e1f5d74bf88ffacaf339b28d8c73f8c4f (diff)
downloadrust-a20e6bb1627f8669b334e673740f78e435cd0321.tar.gz
rust-a20e6bb1627f8669b334e673740f78e435cd0321.zip
Consider `doc(hidden)` for crate-local inlining
-rw-r--r--src/librustdoc/visit_ast.rs42
-rw-r--r--src/test/rustdoc/inline_local/issue-28537.rs27
2 files changed, 63 insertions, 6 deletions
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 7a3adc157c2..4c03abac9e8 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -26,6 +26,7 @@ use rustc::middle::stability;
 use rustc_front::hir;
 
 use core;
+use clean::{Clean, Attributes};
 use doctree::*;
 
 // looks to me like the first two of these are actually
@@ -182,7 +183,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                        please_inline: bool) -> Option<hir::ViewPath_> {
         match path {
             hir::ViewPathSimple(dst, base) => {
-                if self.resolve_id(id, Some(dst), false, om, please_inline) {
+                if self.maybe_inline_local(id, Some(dst), false, om, please_inline) {
                     None
                 } else {
                     Some(hir::ViewPathSimple(dst, base))
@@ -190,7 +191,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             }
             hir::ViewPathList(p, paths) => {
                 let mine = paths.into_iter().filter(|path| {
-                    !self.resolve_id(path.node.id(), None, false, om,
+                    !self.maybe_inline_local(path.node.id(), None, false, om,
                                      please_inline)
                 }).collect::<hir::HirVec<hir::PathListItem>>();
 
@@ -201,9 +202,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 }
             }
 
-            // these are feature gated anyway
             hir::ViewPathGlob(base) => {
-                if self.resolve_id(id, None, true, om, please_inline) {
+                if self.maybe_inline_local(id, None, true, om, please_inline) {
                     None
                 } else {
                     Some(hir::ViewPathGlob(base))
@@ -213,8 +213,32 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
 
     }
 
-    fn resolve_id(&mut self, id: ast::NodeId, renamed: Option<ast::Name>,
+    /// Tries to resolve the target of a `pub use` statement and inlines the
+    /// target if it is defined locally and would not be documented otherwise,
+    /// or when it is specifically requested with `please_inline`.
+    /// (the latter is the case when the import is marked `doc(inline)`)
+    ///
+    /// Cross-crate inlining occurs later on during crate cleaning
+    /// and follows different rules.
+    ///
+    /// Returns true if the target has been inlined.
+    fn maybe_inline_local(&mut self, id: ast::NodeId, renamed: Option<ast::Name>,
                   glob: bool, om: &mut Module, please_inline: bool) -> bool {
+
+        fn inherits_doc_hidden(cx: &core::DocContext, mut node: ast::NodeId) -> bool {
+            while let Some(id) = cx.map.get_enclosing_scope(node) {
+                node = id;
+                let attrs = cx.map.attrs(node).clean(cx);
+                if attrs.list_def("doc").has_word("hidden") {
+                    return true;
+                }
+                if node == ast::CRATE_NODE_ID {
+                    break;
+                }
+            }
+            false
+        }
+
         let tcx = match self.cx.tcx_opt() {
             Some(tcx) => tcx,
             None => return false
@@ -226,9 +250,15 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         let analysis = match self.analysis {
             Some(analysis) => analysis, None => return false
         };
-        if !please_inline && analysis.access_levels.is_public(def) {
+
+        let is_private = !analysis.access_levels.is_public(def);
+        let is_hidden = inherits_doc_hidden(self.cx, def_node_id);
+
+        // Only inline if requested or if the item would otherwise be stripped
+        if !please_inline && !is_private && !is_hidden {
             return false
         }
+
         if !self.view_item_stack.insert(def_node_id) { return false }
 
         let ret = match tcx.map.get(def_node_id) {
diff --git a/src/test/rustdoc/inline_local/issue-28537.rs b/src/test/rustdoc/inline_local/issue-28537.rs
new file mode 100644
index 00000000000..b38e104b7b4
--- /dev/null
+++ b/src/test/rustdoc/inline_local/issue-28537.rs
@@ -0,0 +1,27 @@
+// Copyright 2016 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.
+
+#[doc(hidden)]
+pub mod foo {
+    pub struct Foo;
+}
+
+mod bar {
+    pub use self::bar::Bar;
+    mod bar {
+        pub struct Bar;
+    }
+}
+
+// @has issue_28537/struct.Foo.html
+pub use foo::Foo;
+
+// @has issue_28537/struct.Bar.html
+pub use self::bar::Bar;