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`
This commit is contained in:
commit
7cffb4ca63
6 changed files with 104 additions and 8 deletions
|
@ -300,7 +300,7 @@ pub(crate) fn build_impls(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `parent_module` refers to the parent of the re-export, not the original item
|
/// `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<'_>,
|
cx: &mut DocContext<'_>,
|
||||||
parent_module: Option<DefId>,
|
parent_module: Option<DefId>,
|
||||||
old_attrs: Attrs<'_>,
|
old_attrs: Attrs<'_>,
|
||||||
|
|
|
@ -482,7 +482,7 @@ impl Item {
|
||||||
cx: &mut DocContext<'_>,
|
cx: &mut DocContext<'_>,
|
||||||
cfg: Option<Arc<Cfg>>,
|
cfg: Option<Arc<Cfg>>,
|
||||||
) -> Item {
|
) -> 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.
|
// 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
|
// The modules need to be private so that nobody actually uses them, but the
|
||||||
|
@ -801,6 +801,31 @@ impl ItemKind {
|
||||||
| KeywordItem => [].iter(),
|
| 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)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
|
@ -516,7 +516,14 @@ fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option<Strin
|
||||||
(cfg, _) => cfg.as_deref().cloned(),
|
(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()))
|
Some(format!("<div class=\"stab portability\">{}</div>", cfg?.render_long_html()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -477,7 +477,7 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) ->
|
||||||
(cfg, _) => cfg.as_deref().cloned(),
|
(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 {
|
if let Some(ref cfg) = cfg {
|
||||||
tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html());
|
tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html());
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,29 +2,53 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::clean::cfg::Cfg;
|
use crate::clean::cfg::Cfg;
|
||||||
|
use crate::clean::inline::{load_attrs, merge_attrs};
|
||||||
use crate::clean::{Crate, Item};
|
use crate::clean::{Crate, Item};
|
||||||
use crate::core::DocContext;
|
use crate::core::DocContext;
|
||||||
use crate::fold::DocFolder;
|
use crate::fold::DocFolder;
|
||||||
use crate::passes::Pass;
|
use crate::passes::Pass;
|
||||||
|
|
||||||
|
use rustc_hir::def_id::LocalDefId;
|
||||||
|
|
||||||
pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass {
|
pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass {
|
||||||
name: "propagate-doc-cfg",
|
name: "propagate-doc-cfg",
|
||||||
run: propagate_doc_cfg,
|
run: propagate_doc_cfg,
|
||||||
description: "propagates `#[doc(cfg(...))]` to child items",
|
description: "propagates `#[doc(cfg(...))]` to child items",
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn propagate_doc_cfg(cr: Crate, _: &mut DocContext<'_>) -> Crate {
|
pub(crate) fn propagate_doc_cfg(cr: Crate, cx: &mut DocContext<'_>) -> Crate {
|
||||||
CfgPropagator { parent_cfg: None }.fold_crate(cr)
|
CfgPropagator { parent_cfg: None, parent: None, cx }.fold_crate(cr)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CfgPropagator {
|
struct CfgPropagator<'a, 'tcx> {
|
||||||
parent_cfg: Option<Arc<Cfg>>,
|
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> {
|
fn fold_item(&mut self, mut item: Item) -> Option<Item> {
|
||||||
let old_parent_cfg = self.parent_cfg.clone();
|
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()) {
|
let new_cfg = match (self.parent_cfg.take(), item.cfg.take()) {
|
||||||
(None, None) => None,
|
(None, None) => None,
|
||||||
(Some(rc), None) | (None, Some(rc)) => Some(rc),
|
(Some(rc), None) | (None, Some(rc)) => Some(rc),
|
||||||
|
@ -37,8 +61,15 @@ impl DocFolder for CfgPropagator {
|
||||||
self.parent_cfg = new_cfg.clone();
|
self.parent_cfg = new_cfg.clone();
|
||||||
item.cfg = new_cfg;
|
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);
|
let result = self.fold_item_recur(item);
|
||||||
self.parent_cfg = old_parent_cfg;
|
self.parent_cfg = old_parent_cfg;
|
||||||
|
self.parent = old_parent;
|
||||||
|
|
||||||
Some(result)
|
Some(result)
|
||||||
}
|
}
|
||||||
|
|
33
src/test/rustdoc/cfg_doc_reexport.rs
Normal file
33
src/test/rustdoc/cfg_doc_reexport.rs
Normal file
|
@ -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;
|
Loading…
Add table
Add a link
Reference in a new issue