about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2022-08-26 14:08:48 +0200
committerGitHub <noreply@github.com>2022-08-26 14:08:48 +0200
commit7cffb4ca63a71edbf5ecbddef9fc5a3075cf6a1a (patch)
tree90489c484a92c1557e2f6e7c4460a2d28c777da7 /src
parent378f851e95b706701af64de4c80f655b9654661c (diff)
parent2ed945407f050385b6d4c34580f9b59db02a1b68 (diff)
downloadrust-7cffb4ca63a71edbf5ecbddef9fc5a3075cf6a1a.tar.gz
rust-7cffb4ca63a71edbf5ecbddef9fc5a3075cf6a1a.zip
Rollup merge of #101006 - GuillaumeGomez:doc-cfg-reexport, r=notriddle
Fix doc cfg on reexports

Fixes #83428.

The problem was that the newly inlined item cfg propagation was not working since its real parent is different than its current one.

For the implementation, I decided to put it directly into `CfgPropagation` instead of inside `inline.rs` because I thought it would be simpler to maintain and to not forget if new kind of items are added if it's all done in one place.

r? `@notriddle`
Diffstat (limited to 'src')
-rw-r--r--src/librustdoc/clean/inline.rs2
-rw-r--r--src/librustdoc/clean/types.rs27
-rw-r--r--src/librustdoc/html/render/mod.rs9
-rw-r--r--src/librustdoc/html/render/print_item.rs2
-rw-r--r--src/librustdoc/passes/propagate_doc_cfg.rs39
-rw-r--r--src/test/rustdoc/cfg_doc_reexport.rs33
6 files changed, 104 insertions, 8 deletions
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index a7048e788b6..f367edcbf5a 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -300,7 +300,7 @@ pub(crate) fn build_impls(
 }
 
 /// `parent_module` refers to the parent of the re-export, not the original item
-fn merge_attrs(
+pub(crate) fn merge_attrs(
     cx: &mut DocContext<'_>,
     parent_module: Option<DefId>,
     old_attrs: Attrs<'_>,
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 4c39021903c..909a47d07b1 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -482,7 +482,7 @@ impl Item {
         cx: &mut DocContext<'_>,
         cfg: Option<Arc<Cfg>>,
     ) -> Item {
-        trace!("name={:?}, def_id={:?}", name, def_id);
+        trace!("name={:?}, def_id={:?} cfg={:?}", name, def_id, cfg);
 
         // Primitives and Keywords are written in the source code as private modules.
         // The modules need to be private so that nobody actually uses them, but the
@@ -801,6 +801,31 @@ impl ItemKind {
             | KeywordItem => [].iter(),
         }
     }
+
+    /// Returns `true` if this item does not appear inside an impl block.
+    pub(crate) fn is_non_assoc(&self) -> bool {
+        matches!(
+            self,
+            StructItem(_)
+                | UnionItem(_)
+                | EnumItem(_)
+                | TraitItem(_)
+                | ModuleItem(_)
+                | ExternCrateItem { .. }
+                | FunctionItem(_)
+                | TypedefItem(_)
+                | OpaqueTyItem(_)
+                | StaticItem(_)
+                | ConstantItem(_)
+                | TraitAliasItem(_)
+                | ForeignFunctionItem(_)
+                | ForeignStaticItem(_)
+                | ForeignTypeItem
+                | MacroItem(_)
+                | ProcMacroItem(_)
+                | PrimitiveItem(_)
+        )
+    }
 }
 
 #[derive(Clone, Debug)]
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index b1d2872019e..6272f47f460 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -516,7 +516,14 @@ fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option<Strin
         (cfg, _) => cfg.as_deref().cloned(),
     };
 
-    debug!("Portability {:?} - {:?} = {:?}", item.cfg, parent.and_then(|p| p.cfg.as_ref()), cfg);
+    debug!(
+        "Portability {:?} {:?} (parent: {:?}) - {:?} = {:?}",
+        item.name,
+        item.cfg,
+        parent,
+        parent.and_then(|p| p.cfg.as_ref()),
+        cfg
+    );
 
     Some(format!("<div class=\"stab portability\">{}</div>", cfg?.render_long_html()))
 }
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index a5668b318dc..912601dda20 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -477,7 +477,7 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) ->
         (cfg, _) => cfg.as_deref().cloned(),
     };
 
-    debug!("Portability {:?} - {:?} = {:?}", item.cfg, parent.cfg, cfg);
+    debug!("Portability name={:?} {:?} - {:?} = {:?}", item.name, item.cfg, parent.cfg, cfg);
     if let Some(ref cfg) = cfg {
         tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html());
     }
diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs
index 0c5d8365518..21d295bb1f8 100644
--- a/src/librustdoc/passes/propagate_doc_cfg.rs
+++ b/src/librustdoc/passes/propagate_doc_cfg.rs
@@ -2,29 +2,53 @@
 use std::sync::Arc;
 
 use crate::clean::cfg::Cfg;
+use crate::clean::inline::{load_attrs, merge_attrs};
 use crate::clean::{Crate, Item};
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::passes::Pass;
 
+use rustc_hir::def_id::LocalDefId;
+
 pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass {
     name: "propagate-doc-cfg",
     run: propagate_doc_cfg,
     description: "propagates `#[doc(cfg(...))]` to child items",
 };
 
-pub(crate) fn propagate_doc_cfg(cr: Crate, _: &mut DocContext<'_>) -> Crate {
-    CfgPropagator { parent_cfg: None }.fold_crate(cr)
+pub(crate) fn propagate_doc_cfg(cr: Crate, cx: &mut DocContext<'_>) -> Crate {
+    CfgPropagator { parent_cfg: None, parent: None, cx }.fold_crate(cr)
 }
 
-struct CfgPropagator {
+struct CfgPropagator<'a, 'tcx> {
     parent_cfg: Option<Arc<Cfg>>,
+    parent: Option<LocalDefId>,
+    cx: &'a mut DocContext<'tcx>,
 }
 
-impl DocFolder for CfgPropagator {
+impl<'a, 'tcx> DocFolder for CfgPropagator<'a, 'tcx> {
     fn fold_item(&mut self, mut item: Item) -> Option<Item> {
         let old_parent_cfg = self.parent_cfg.clone();
 
+        if item.kind.is_non_assoc() &&
+            let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) {
+            let hir = self.cx.tcx.hir();
+            let hir_id = hir.local_def_id_to_hir_id(def_id);
+            let expected_parent = hir.get_parent_item(hir_id);
+
+            // If parents are different, it means that `item` is a reexport and we need to compute
+            // the actual `cfg` by iterating through its "real" parents.
+            if self.parent != Some(expected_parent) {
+                let mut attrs = Vec::new();
+                for (parent_hir_id, _) in hir.parent_iter(hir_id) {
+                    let def_id = hir.local_def_id(parent_hir_id).to_def_id();
+                    attrs.extend_from_slice(load_attrs(self.cx, def_id));
+                }
+                let (_, cfg) =
+                    merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs));
+                item.cfg = cfg;
+            }
+        }
         let new_cfg = match (self.parent_cfg.take(), item.cfg.take()) {
             (None, None) => None,
             (Some(rc), None) | (None, Some(rc)) => Some(rc),
@@ -37,8 +61,15 @@ impl DocFolder for CfgPropagator {
         self.parent_cfg = new_cfg.clone();
         item.cfg = new_cfg;
 
+        let old_parent =
+            if let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) {
+                self.parent.replace(def_id)
+            } else {
+                self.parent.take()
+            };
         let result = self.fold_item_recur(item);
         self.parent_cfg = old_parent_cfg;
+        self.parent = old_parent;
 
         Some(result)
     }
diff --git a/src/test/rustdoc/cfg_doc_reexport.rs b/src/test/rustdoc/cfg_doc_reexport.rs
new file mode 100644
index 00000000000..addb6709db1
--- /dev/null
+++ b/src/test/rustdoc/cfg_doc_reexport.rs
@@ -0,0 +1,33 @@
+#![feature(doc_cfg)]
+#![feature(no_core)]
+
+#![crate_name = "foo"]
+#![no_core]
+
+// @has 'foo/index.html'
+// @has - '//*[@class="item-left module-item"]/*[@class="stab portability"]' 'foobar'
+// @has - '//*[@class="item-left module-item"]/*[@class="stab portability"]' 'bar'
+
+#[doc(cfg(feature = "foobar"))]
+mod imp_priv {
+    // @has 'foo/struct.BarPriv.html'
+    // @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
+    //    'Available on crate feature foobar only.'
+    pub struct BarPriv {}
+    impl BarPriv {
+        pub fn test() {}
+    }
+}
+#[doc(cfg(feature = "foobar"))]
+pub use crate::imp_priv::*;
+
+pub mod bar {
+    // @has 'foo/bar/struct.Bar.html'
+    // @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
+    //    'Available on crate feature bar only.'
+    #[doc(cfg(feature = "bar"))]
+    pub struct Bar;
+}
+
+#[doc(cfg(feature = "bar"))]
+pub use bar::Bar;