]> git.lizzy.rs Git - rust.git/commitdiff
Special-case handling of impl blocks
authorGuillaume Gomez <guillaume.gomez@huawei.com>
Fri, 27 Jan 2023 19:32:50 +0000 (20:32 +0100)
committerGuillaume Gomez <guillaume.gomez@huawei.com>
Fri, 27 Jan 2023 19:33:42 +0000 (20:33 +0100)
src/librustdoc/passes/strip_hidden.rs
src/librustdoc/visit_ast.rs

index cfd2171395cebf1e39c6eafac5e02cbc61b970e1..8c733ddefc0a5a1efe02dd3d95647f85533a297b 100644 (file)
@@ -59,57 +59,74 @@ fn set_is_in_hidden_item_and_fold(&mut self, is_in_hidden_item: bool, i: Item) -
         self.is_in_hidden_item = prev;
         ret
     }
+
+    /// In case `i` is a non-hidden impl block, then we special-case it by changing the value
+    /// of `is_in_hidden_item` to `true` because the impl children inherit its visibility.
+    fn recurse_in_impl(&mut self, i: Item) -> Item {
+        let prev = mem::replace(&mut self.is_in_hidden_item, false);
+        let ret = self.fold_item_recur(i);
+        self.is_in_hidden_item = prev;
+        ret
+    }
 }
 
 impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         let has_doc_hidden = i.attrs.lists(sym::doc).has_word(sym::hidden);
-        let mut is_hidden = self.is_in_hidden_item || has_doc_hidden;
-        if !is_hidden && i.inline_stmt_id.is_none() {
-            // We don't need to check if it's coming from a reexport since the reexport itself was
-            // already checked.
-            is_hidden = i
-                .item_id
-                .as_def_id()
-                .and_then(|def_id| def_id.as_local())
-                .map(|def_id| inherits_doc_hidden(self.tcx, def_id))
-                .unwrap_or(false);
+        let is_impl = matches!(*i.kind, clean::ImplItem(..));
+        let mut is_hidden = has_doc_hidden;
+        if !is_impl {
+            is_hidden = self.is_in_hidden_item || has_doc_hidden;
+            if !is_hidden && i.inline_stmt_id.is_none() {
+                // We don't need to check if it's coming from a reexport since the reexport itself was
+                // already checked.
+                is_hidden = i
+                    .item_id
+                    .as_def_id()
+                    .and_then(|def_id| def_id.as_local())
+                    .map(|def_id| inherits_doc_hidden(self.tcx, def_id))
+                    .unwrap_or(false);
+            }
         }
-        if is_hidden {
-            debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name);
-            // Use a dedicated hidden item for fields, variants, and modules.
-            // We need to keep private fields and variants, so that the docs
-            // can show a placeholder "// some variants omitted". We need to keep
-            // private modules, because they can contain impl blocks, and impl
-            // block privacy is inherited from the type and trait, not from the
-            // module it's defined in. Both of these are marked "stripped," and
-            // not included in the final docs, but since they still have an effect
-            // on the final doc, cannot be completely removed from the Clean IR.
-            return match *i.kind {
-                clean::StructFieldItem(..) | clean::ModuleItem(..) | clean::VariantItem(..) => {
-                    // We need to recurse into stripped modules to
-                    // strip things like impl methods but when doing so
-                    // we must not add any items to the `retained` set.
-                    let old = mem::replace(&mut self.update_retained, false);
-                    let ret = strip_item(self.set_is_in_hidden_item_and_fold(true, i));
-                    self.update_retained = old;
-                    Some(ret)
-                }
-                _ => {
-                    let ret = self.set_is_in_hidden_item_and_fold(true, i);
-                    if has_doc_hidden {
-                        // If the item itself has `#[doc(hidden)]`, then we simply remove it.
-                        None
-                    } else {
-                        // However if it's a "descendant" of a `#[doc(hidden)]` item, then we strip it.
-                        Some(strip_item(ret))
-                    }
-                }
-            };
+        if !is_hidden {
+            if self.update_retained {
+                self.retained.insert(i.item_id);
+            }
+            return Some(if is_impl {
+                self.recurse_in_impl(i)
+            } else {
+                self.set_is_in_hidden_item_and_fold(false, i)
+            });
         }
-        if self.update_retained {
-            self.retained.insert(i.item_id);
+        debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name);
+        // Use a dedicated hidden item for fields, variants, and modules.
+        // We need to keep private fields and variants, so that the docs
+        // can show a placeholder "// some variants omitted". We need to keep
+        // private modules, because they can contain impl blocks, and impl
+        // block privacy is inherited from the type and trait, not from the
+        // module it's defined in. Both of these are marked "stripped," and
+        // not included in the final docs, but since they still have an effect
+        // on the final doc, cannot be completely removed from the Clean IR.
+        match *i.kind {
+            clean::StructFieldItem(..) | clean::ModuleItem(..) | clean::VariantItem(..) => {
+                // We need to recurse into stripped modules to
+                // strip things like impl methods but when doing so
+                // we must not add any items to the `retained` set.
+                let old = mem::replace(&mut self.update_retained, false);
+                let ret = strip_item(self.set_is_in_hidden_item_and_fold(true, i));
+                self.update_retained = old;
+                Some(ret)
+            }
+            _ => {
+                let ret = self.set_is_in_hidden_item_and_fold(true, i);
+                if has_doc_hidden {
+                    // If the item itself has `#[doc(hidden)]`, then we simply remove it.
+                    None
+                } else {
+                    // However if it's a "descendant" of a `#[doc(hidden)]` item, then we strip it.
+                    Some(strip_item(ret))
+                }
+            }
         }
-        Some(self.set_is_in_hidden_item_and_fold(is_hidden, i))
     }
 }
index 2d2afb83f9dd8b7b4cdfc68827d198d11f787568..088cb3f339492be74fc4e8091b5693f7e2427fdc 100644 (file)
@@ -55,11 +55,21 @@ fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec<Symbol> {
     std::iter::once(crate_name).chain(relative).collect()
 }
 
-pub(crate) fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut node: LocalDefId) -> bool {
-    while let Some(id) = tcx.opt_local_parent(node) {
-        node = id;
-        if tcx.is_doc_hidden(node.to_def_id()) {
+pub(crate) fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut def_id: LocalDefId) -> bool {
+    let hir = tcx.hir();
+    while let Some(id) = tcx.opt_local_parent(def_id) {
+        def_id = id;
+        if tcx.is_doc_hidden(def_id.to_def_id()) {
             return true;
+        } else if let Some(node) = hir.find_by_def_id(def_id) &&
+            matches!(
+                node,
+                hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }),
+            )
+        {
+            // `impl` blocks stand a bit on their own: unless they have `#[doc(hidden)]` directly
+            // on them, they don't inherit it from the parent context.
+            return false;
         }
     }
     false