]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/passes/propagate_doc_cfg.rs
Rollup merge of #100653 - cuviper:fptoint_sat, r=michaelwoerister,antoyo
[rust.git] / src / librustdoc / passes / propagate_doc_cfg.rs
1 //! Propagates [`#[doc(cfg(...))]`](https://github.com/rust-lang/rust/issues/43781) to child items.
2 use std::sync::Arc;
3
4 use crate::clean::cfg::Cfg;
5 use crate::clean::inline::{load_attrs, merge_attrs};
6 use crate::clean::{Crate, Item};
7 use crate::core::DocContext;
8 use crate::fold::DocFolder;
9 use crate::passes::Pass;
10
11 use rustc_hir::def_id::LocalDefId;
12
13 pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass {
14     name: "propagate-doc-cfg",
15     run: propagate_doc_cfg,
16     description: "propagates `#[doc(cfg(...))]` to child items",
17 };
18
19 pub(crate) fn propagate_doc_cfg(cr: Crate, cx: &mut DocContext<'_>) -> Crate {
20     CfgPropagator { parent_cfg: None, parent: None, cx }.fold_crate(cr)
21 }
22
23 struct CfgPropagator<'a, 'tcx> {
24     parent_cfg: Option<Arc<Cfg>>,
25     parent: Option<LocalDefId>,
26     cx: &'a mut DocContext<'tcx>,
27 }
28
29 impl<'a, 'tcx> DocFolder for CfgPropagator<'a, 'tcx> {
30     fn fold_item(&mut self, mut item: Item) -> Option<Item> {
31         let old_parent_cfg = self.parent_cfg.clone();
32
33         if item.kind.is_non_assoc() &&
34             let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) {
35             let hir = self.cx.tcx.hir();
36             let hir_id = hir.local_def_id_to_hir_id(def_id);
37             let expected_parent = hir.get_parent_item(hir_id);
38
39             // If parents are different, it means that `item` is a reexport and we need to compute
40             // the actual `cfg` by iterating through its "real" parents.
41             if self.parent != Some(expected_parent) {
42                 let mut attrs = Vec::new();
43                 for (parent_hir_id, _) in hir.parent_iter(hir_id) {
44                     if let Some(def_id) = hir.opt_local_def_id(parent_hir_id) {
45                         attrs.extend_from_slice(load_attrs(self.cx, def_id.to_def_id()));
46                     }
47                 }
48                 let (_, cfg) =
49                     merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs));
50                 item.cfg = cfg;
51             }
52         }
53         let new_cfg = match (self.parent_cfg.take(), item.cfg.take()) {
54             (None, None) => None,
55             (Some(rc), None) | (None, Some(rc)) => Some(rc),
56             (Some(mut a), Some(b)) => {
57                 let b = Arc::try_unwrap(b).unwrap_or_else(|rc| Cfg::clone(&rc));
58                 *Arc::make_mut(&mut a) &= b;
59                 Some(a)
60             }
61         };
62         self.parent_cfg = new_cfg.clone();
63         item.cfg = new_cfg;
64
65         let old_parent =
66             if let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) {
67                 self.parent.replace(def_id)
68             } else {
69                 self.parent.take()
70             };
71         let result = self.fold_item_recur(item);
72         self.parent_cfg = old_parent_cfg;
73         self.parent = old_parent;
74
75         Some(result)
76     }
77 }