Fix missing cfg propagation for reexports

This commit is contained in:
Guillaume Gomez 2022-08-25 16:42:17 +02:00
parent 4a24f08ba4
commit 01d64f5e3e
5 changed files with 71 additions and 8 deletions

View File

@ -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<'_>,

View File

@ -482,7 +482,7 @@ pub(crate) fn from_def_id_and_attrs_and_parts(
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 @@ pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
| 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)]

View File

@ -522,7 +522,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()))
}

View File

@ -477,7 +477,7 @@ fn tag_html(class: &str, title: &str, contents: &str) -> String {
(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());
}

View File

@ -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 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
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)
}