rustdoc/passes/
propagate_doc_cfg.rs1use rustc_hir::Attribute;
4use rustc_hir::attrs::{AttributeKind, DocAttribute};
5
6use crate::clean::inline::{load_attrs, merge_attrs};
7use crate::clean::{CfgInfo, Crate, Item, ItemKind};
8use crate::core::DocContext;
9use crate::fold::DocFolder;
10use crate::passes::Pass;
11
12pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass {
13 name: "propagate-doc-cfg",
14 run: Some(propagate_doc_cfg),
15 description: "propagates `#[doc(cfg(...))]` to child items",
16};
17
18pub(crate) fn propagate_doc_cfg(cr: Crate, cx: &mut DocContext<'_>) -> Crate {
19 if cx.tcx.features().doc_cfg() {
20 CfgPropagator { cx, cfg_info: CfgInfo::default() }.fold_crate(cr)
21 } else {
22 cr
23 }
24}
25
26struct CfgPropagator<'a, 'tcx> {
27 cx: &'a mut DocContext<'tcx>,
28 cfg_info: CfgInfo,
29}
30
31fn add_only_cfg_attributes(attrs: &mut Vec<Attribute>, new_attrs: &[Attribute]) {
34 for attr in new_attrs {
35 if let Attribute::Parsed(AttributeKind::Doc(d)) = attr
36 && !d.cfg.is_empty()
37 {
38 let mut new_attr = DocAttribute::default();
39 new_attr.cfg = d.cfg.clone();
40 attrs.push(Attribute::Parsed(AttributeKind::Doc(Box::new(new_attr))));
41 } else if let Attribute::Parsed(AttributeKind::CfgTrace(..)) = attr {
42 attrs.push(attr.clone());
44 }
45 }
46}
47
48impl CfgPropagator<'_, '_> {
49 fn merge_with_parent_attributes(&mut self, item: &mut Item) {
52 let mut attrs = Vec::new();
53 if matches!(item.kind, ItemKind::ImplItem(_))
58 && let Some(mut next_def_id) = item.item_id.as_local_def_id()
59 {
60 while let Some(parent_def_id) = self.cx.tcx.opt_local_parent(next_def_id) {
61 let x = load_attrs(self.cx, parent_def_id.to_def_id());
62 add_only_cfg_attributes(&mut attrs, x);
63 next_def_id = parent_def_id;
64 }
65 }
66
67 let (_, cfg) = merge_attrs(
68 self.cx,
69 item.attrs.other_attrs.as_slice(),
70 Some((&attrs, None)),
71 &mut self.cfg_info,
72 );
73 item.inner.cfg = cfg;
74 }
75}
76
77impl DocFolder for CfgPropagator<'_, '_> {
78 fn fold_item(&mut self, mut item: Item) -> Option<Item> {
79 let old_cfg_info = self.cfg_info.clone();
80
81 self.merge_with_parent_attributes(&mut item);
82
83 let result = self.fold_item_recur(item);
84 self.cfg_info = old_cfg_info;
85
86 Some(result)
87 }
88}