mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
89 lines
3.0 KiB
Rust
89 lines
3.0 KiB
Rust
//! Propagates [`#[doc(cfg(...))]`](https://github.com/rust-lang/rust/issues/43781) to child items.
|
|
|
|
use rustc_hir::Attribute;
|
|
use rustc_hir::attrs::{AttributeKind, DocAttribute};
|
|
|
|
use crate::clean::inline::{load_attrs, merge_attrs};
|
|
use crate::clean::{CfgInfo, Crate, Item, ItemKind};
|
|
use crate::core::DocContext;
|
|
use crate::fold::DocFolder;
|
|
use crate::passes::Pass;
|
|
|
|
pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass {
|
|
name: "propagate-doc-cfg",
|
|
run: Some(propagate_doc_cfg),
|
|
description: "propagates `#[doc(cfg(...))]` to child items",
|
|
};
|
|
|
|
pub(crate) fn propagate_doc_cfg(cr: Crate, cx: &mut DocContext<'_>) -> Crate {
|
|
if cx.tcx.features().doc_cfg() {
|
|
CfgPropagator { cx, cfg_info: CfgInfo::default() }.fold_crate(cr)
|
|
} else {
|
|
cr
|
|
}
|
|
}
|
|
|
|
struct CfgPropagator<'a, 'tcx> {
|
|
cx: &'a mut DocContext<'tcx>,
|
|
cfg_info: CfgInfo,
|
|
}
|
|
|
|
/// This function goes through the attributes list (`new_attrs`) and extract the `cfg` tokens from
|
|
/// it and put them into `attrs`.
|
|
fn add_only_cfg_attributes(attrs: &mut Vec<Attribute>, new_attrs: &[Attribute]) {
|
|
for attr in new_attrs {
|
|
if let Attribute::Parsed(AttributeKind::Doc(d)) = attr
|
|
&& !d.cfg.is_empty()
|
|
{
|
|
let mut new_attr = DocAttribute::default();
|
|
new_attr.cfg = d.cfg.clone();
|
|
attrs.push(Attribute::Parsed(AttributeKind::Doc(Box::new(new_attr))));
|
|
} else if let Attribute::Parsed(AttributeKind::CfgTrace(..)) = attr {
|
|
// If it's a `cfg()` attribute, we keep it.
|
|
attrs.push(attr.clone());
|
|
}
|
|
}
|
|
}
|
|
|
|
impl CfgPropagator<'_, '_> {
|
|
// Some items need to merge their attributes with their parents' otherwise a few of them
|
|
// (mostly `cfg` ones) will be missing.
|
|
fn merge_with_parent_attributes(&mut self, item: &mut Item) {
|
|
let mut attrs = Vec::new();
|
|
// We only need to merge an item attributes with its parent's in case it's an impl as an
|
|
// impl might not be defined in the same module as the item it implements.
|
|
//
|
|
// Otherwise, `cfg_info` already tracks everything we need so nothing else to do!
|
|
if matches!(item.kind, ItemKind::ImplItem(_))
|
|
&& let Some(mut next_def_id) = item.item_id.as_local_def_id()
|
|
{
|
|
while let Some(parent_def_id) = self.cx.tcx.opt_local_parent(next_def_id) {
|
|
let x = load_attrs(self.cx, parent_def_id.to_def_id());
|
|
add_only_cfg_attributes(&mut attrs, x);
|
|
next_def_id = parent_def_id;
|
|
}
|
|
}
|
|
|
|
let (_, cfg) = merge_attrs(
|
|
self.cx,
|
|
item.attrs.other_attrs.as_slice(),
|
|
Some((&attrs, None)),
|
|
&mut self.cfg_info,
|
|
);
|
|
item.inner.cfg = cfg;
|
|
}
|
|
}
|
|
|
|
impl DocFolder for CfgPropagator<'_, '_> {
|
|
fn fold_item(&mut self, mut item: Item) -> Option<Item> {
|
|
let old_cfg_info = self.cfg_info.clone();
|
|
|
|
self.merge_with_parent_attributes(&mut item);
|
|
|
|
let result = self.fold_item_recur(item);
|
|
self.cfg_info = old_cfg_info;
|
|
|
|
Some(result)
|
|
}
|
|
}
|