about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume.gomez@huawei.com>2022-10-27 21:48:34 +0200
committerGuillaume Gomez <guillaume.gomez@huawei.com>2022-10-29 11:43:29 +0200
commitf0234f1976564c541d6aa1f04312e5acc22b2f3e (patch)
tree8ede7770c0f57250346d3de54a684cf72d123243
parent607878d069267e1402ad792c9331b426e4c6d0f9 (diff)
downloadrust-f0234f1976564c541d6aa1f04312e5acc22b2f3e.tar.gz
rust-f0234f1976564c541d6aa1f04312e5acc22b2f3e.zip
Add missing impl blocks for item reexported from private mod in JSON output
-rw-r--r--src/librustdoc/passes/stripper.rs30
1 files changed, 25 insertions, 5 deletions
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index f293a6fcc6d..89efddf76ef 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -1,9 +1,11 @@
 //! A collection of utility functions for the `strip_*` passes.
 use rustc_hir::def_id::DefId;
 use rustc_middle::middle::privacy::EffectiveVisibilities;
+use rustc_span::symbol::sym;
+
 use std::mem;
 
-use crate::clean::{self, Item, ItemId, ItemIdSet};
+use crate::clean::{self, Item, ItemId, ItemIdSet, NestedAttributesExt};
 use crate::fold::{strip_item, DocFolder};
 use crate::formats::cache::Cache;
 
@@ -151,6 +153,22 @@ pub(crate) struct ImplStripper<'a> {
     pub(crate) document_private: bool,
 }
 
+impl<'a> ImplStripper<'a> {
+    #[inline]
+    fn should_keep_impl(&self, item: &Item, for_def_id: DefId) -> bool {
+        if !for_def_id.is_local() || self.retained.contains(&for_def_id.into()) {
+            true
+        } else if self.is_json_output {
+            // If the "for" item is exported and the impl block isn't `#[doc(hidden)]`, then we
+            // need to keep it.
+            self.cache.access_levels.is_exported(for_def_id)
+                && !item.attrs.lists(sym::doc).has_word(sym::hidden)
+        } else {
+            false
+        }
+    }
+}
+
 impl<'a> DocFolder for ImplStripper<'a> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         if let clean::ImplItem(ref imp) = *i.kind {
@@ -178,15 +196,17 @@ impl<'a> DocFolder for ImplStripper<'a> {
                     return None;
                 }
             }
+            // Because we don't inline in `maybe_inline_local` if the output format is JSON,
+            // we need to make a special check for JSON output: we want to keep it unless it has
+            // a `#[doc(hidden)]` attribute if the `for_` type is exported.
             if let Some(did) = imp.for_.def_id(self.cache) {
-                if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into())
-                {
+                if !imp.for_.is_assoc_ty() && !self.should_keep_impl(&i, did) {
                     debug!("ImplStripper: impl item for stripped type; removing");
                     return None;
                 }
             }
             if let Some(did) = imp.trait_.as_ref().map(|t| t.def_id()) {
-                if did.is_local() && !self.retained.contains(&did.into()) {
+                if !self.should_keep_impl(&i, did) {
                     debug!("ImplStripper: impl item for stripped trait; removing");
                     return None;
                 }
@@ -194,7 +214,7 @@ impl<'a> DocFolder for ImplStripper<'a> {
             if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
                 for typaram in generics {
                     if let Some(did) = typaram.def_id(self.cache) {
-                        if did.is_local() && !self.retained.contains(&did.into()) {
+                        if !self.should_keep_impl(&i, did) {
                             debug!(
                                 "ImplStripper: stripped item in trait's generics; removing impl"
                             );