about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume.gomez@huawei.com>2022-07-15 17:37:07 +0200
committerGuillaume Gomez <guillaume.gomez@huawei.com>2022-07-16 13:39:38 +0200
commit1a15c7147f90afaa64ae3ff27fcbd678e2e44a8e (patch)
treefbfd75951768038fa6490811d9c9c37daf9d8fd9
parent0ed9c64c3e63acac9bd77abce62501696c390450 (diff)
downloadrust-1a15c7147f90afaa64ae3ff27fcbd678e2e44a8e.tar.gz
rust-1a15c7147f90afaa64ae3ff27fcbd678e2e44a8e.zip
Fix rustdoc JSON inline
-rw-r--r--src/librustdoc/clean/mod.rs5
-rw-r--r--src/librustdoc/json/conversions.rs30
-rw-r--r--src/librustdoc/json/mod.rs9
-rw-r--r--src/librustdoc/visit_ast.rs4
-rw-r--r--src/rustdoc-json-types/lib.rs5
5 files changed, 46 insertions, 7 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 2c98cba90d7..d6260b8ca06 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2120,8 +2120,9 @@ fn clean_use_statement<'tcx>(
     // forcefully don't inline if this is not public or if the
     // #[doc(no_inline)] attribute is present.
     // Don't inline doc(hidden) imports so they can be stripped at a later stage.
-    let mut denied = !(visibility.is_public()
-        || (cx.render_options.document_private && is_visible_from_parent_mod))
+    let mut denied = cx.output_format.is_json()
+        || !(visibility.is_public()
+            || (cx.render_options.document_private && is_visible_from_parent_mod))
         || pub_underscore
         || attrs.iter().any(|a| {
             a.has_name(sym::doc)
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index db2ad953f6a..2598b9b0b28 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -43,7 +43,16 @@ impl JsonRenderer<'_> {
         let span = item.span(self.tcx);
         let clean::Item { name, attrs: _, kind: _, visibility, item_id, cfg: _ } = item;
         let inner = match *item.kind {
-            clean::StrippedItem(_) | clean::KeywordItem(_) => return None,
+            clean::KeywordItem(_) => return None,
+            clean::StrippedItem(ref inner) => {
+                match &**inner {
+                    // We document non-empty stripped modules as with `Module::is_stripped` set to
+                    // `true`, to prevent contained items from being orphaned for downstream users,
+                    // as JSON does no inlining.
+                    clean::ModuleItem(m) if !m.items.is_empty() => from_clean_item(item, self.tcx),
+                    _ => return None,
+                }
+            }
             _ => from_clean_item(item, self.tcx),
         };
         Some(Item {
@@ -220,7 +229,9 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
     let header = item.fn_header(tcx);
 
     match *item.kind {
-        ModuleItem(m) => ItemEnum::Module(Module { is_crate, items: ids(m.items, tcx) }),
+        ModuleItem(m) => {
+            ItemEnum::Module(Module { is_crate, items: ids(m.items, tcx), is_stripped: false })
+        }
         ImportItem(i) => ItemEnum::Import(i.into_tcx(tcx)),
         StructItem(s) => ItemEnum::Struct(s.into_tcx(tcx)),
         UnionItem(u) => ItemEnum::Union(u.into_tcx(tcx)),
@@ -257,8 +268,19 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
             bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(),
             default: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)),
         },
-        // `convert_item` early returns `None` for striped items and keywords.
-        StrippedItem(_) | KeywordItem(_) => unreachable!(),
+        // `convert_item` early returns `None` for stripped items and keywords.
+        KeywordItem(_) => unreachable!(),
+        StrippedItem(inner) => {
+            match *inner {
+                ModuleItem(m) => ItemEnum::Module(Module {
+                    is_crate,
+                    items: ids(m.items, tcx),
+                    is_stripped: true,
+                }),
+                // `convert_item` early returns `None` for stripped items we're not including
+                _ => unreachable!(),
+            }
+        }
         ExternCrateItem { ref src } => ItemEnum::ExternCrate {
             name: name.as_ref().unwrap().to_string(),
             rename: src.map(|x| x.to_string()),
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index c7251b51152..6364d00d062 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -21,6 +21,7 @@ use rustc_span::def_id::LOCAL_CRATE;
 use rustdoc_json_types as types;
 
 use crate::clean::types::{ExternalCrate, ExternalLocation};
+use crate::clean::ItemKind;
 use crate::config::RenderOptions;
 use crate::docfs::PathError;
 use crate::error::Error;
@@ -175,6 +176,14 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
     /// the hashmap because certain items (traits and types) need to have their mappings for trait
     /// implementations filled out before they're inserted.
     fn item(&mut self, item: clean::Item) -> Result<(), Error> {
+        trace!("rendering {} {:?}", item.type_(), item.name);
+
+        // Flatten items that recursively store other items. We include orphaned items from
+        // stripped modules and etc that are otherwise reachable.
+        if let ItemKind::StrippedItem(inner) = &*item.kind {
+            inner.inner_items().for_each(|i| self.item(i.clone()).unwrap());
+        }
+
         // Flatten items that recursively store other items
         item.kind.inner_items().for_each(|i| self.item(i.clone()).unwrap());
 
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index ac934f6925d..ca7a20bf368 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -190,6 +190,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
     ) -> bool {
         debug!("maybe_inline_local res: {:?}", res);
 
+        if self.cx.output_format.is_json() {
+            return false;
+        }
+
         let tcx = self.cx.tcx;
         let Some(res_did) = res.opt_def_id() else {
             return false;
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 1168a89a8b2..761e94c7ebb 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -9,7 +9,7 @@ use std::path::PathBuf;
 use serde::{Deserialize, Serialize};
 
 /// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 15;
+pub const FORMAT_VERSION: u32 = 16;
 
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
@@ -245,6 +245,9 @@ pub enum ItemEnum {
 pub struct Module {
     pub is_crate: bool,
     pub items: Vec<Id>,
+    /// If `true`, this module is not part of the public API, but it contains
+    /// items that are re-exported as public API.
+    pub is_stripped: bool,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]