Skip to content

Commit 7cffb4c

Browse files
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`
2 parents 378f851 + 2ed9454 commit 7cffb4c

File tree

6 files changed

+104
-8
lines changed

6 files changed

+104
-8
lines changed

Diff for: src/librustdoc/clean/inline.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ pub(crate) fn build_impls(
300300
}
301301

302302
/// `parent_module` refers to the parent of the re-export, not the original item
303-
fn merge_attrs(
303+
pub(crate) fn merge_attrs(
304304
cx: &mut DocContext<'_>,
305305
parent_module: Option<DefId>,
306306
old_attrs: Attrs<'_>,

Diff for: src/librustdoc/clean/types.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ impl Item {
482482
cx: &mut DocContext<'_>,
483483
cfg: Option<Arc<Cfg>>,
484484
) -> Item {
485-
trace!("name={:?}, def_id={:?}", name, def_id);
485+
trace!("name={:?}, def_id={:?} cfg={:?}", name, def_id, cfg);
486486

487487
// Primitives and Keywords are written in the source code as private modules.
488488
// The modules need to be private so that nobody actually uses them, but the
@@ -801,6 +801,31 @@ impl ItemKind {
801801
| KeywordItem => [].iter(),
802802
}
803803
}
804+
805+
/// Returns `true` if this item does not appear inside an impl block.
806+
pub(crate) fn is_non_assoc(&self) -> bool {
807+
matches!(
808+
self,
809+
StructItem(_)
810+
| UnionItem(_)
811+
| EnumItem(_)
812+
| TraitItem(_)
813+
| ModuleItem(_)
814+
| ExternCrateItem { .. }
815+
| FunctionItem(_)
816+
| TypedefItem(_)
817+
| OpaqueTyItem(_)
818+
| StaticItem(_)
819+
| ConstantItem(_)
820+
| TraitAliasItem(_)
821+
| ForeignFunctionItem(_)
822+
| ForeignStaticItem(_)
823+
| ForeignTypeItem
824+
| MacroItem(_)
825+
| ProcMacroItem(_)
826+
| PrimitiveItem(_)
827+
)
828+
}
804829
}
805830

806831
#[derive(Clone, Debug)]

Diff for: src/librustdoc/html/render/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,14 @@ fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option<Strin
516516
(cfg, _) => cfg.as_deref().cloned(),
517517
};
518518

519-
debug!("Portability {:?} - {:?} = {:?}", item.cfg, parent.and_then(|p| p.cfg.as_ref()), cfg);
519+
debug!(
520+
"Portability {:?} {:?} (parent: {:?}) - {:?} = {:?}",
521+
item.name,
522+
item.cfg,
523+
parent,
524+
parent.and_then(|p| p.cfg.as_ref()),
525+
cfg
526+
);
520527

521528
Some(format!("<div class=\"stab portability\">{}</div>", cfg?.render_long_html()))
522529
}

Diff for: src/librustdoc/html/render/print_item.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) ->
477477
(cfg, _) => cfg.as_deref().cloned(),
478478
};
479479

480-
debug!("Portability {:?} - {:?} = {:?}", item.cfg, parent.cfg, cfg);
480+
debug!("Portability name={:?} {:?} - {:?} = {:?}", item.name, item.cfg, parent.cfg, cfg);
481481
if let Some(ref cfg) = cfg {
482482
tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html());
483483
}

Diff for: src/librustdoc/passes/propagate_doc_cfg.rs

+35-4
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,53 @@
22
use std::sync::Arc;
33

44
use crate::clean::cfg::Cfg;
5+
use crate::clean::inline::{load_attrs, merge_attrs};
56
use crate::clean::{Crate, Item};
67
use crate::core::DocContext;
78
use crate::fold::DocFolder;
89
use crate::passes::Pass;
910

11+
use rustc_hir::def_id::LocalDefId;
12+
1013
pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass {
1114
name: "propagate-doc-cfg",
1215
run: propagate_doc_cfg,
1316
description: "propagates `#[doc(cfg(...))]` to child items",
1417
};
1518

16-
pub(crate) fn propagate_doc_cfg(cr: Crate, _: &mut DocContext<'_>) -> Crate {
17-
CfgPropagator { parent_cfg: None }.fold_crate(cr)
19+
pub(crate) fn propagate_doc_cfg(cr: Crate, cx: &mut DocContext<'_>) -> Crate {
20+
CfgPropagator { parent_cfg: None, parent: None, cx }.fold_crate(cr)
1821
}
1922

20-
struct CfgPropagator {
23+
struct CfgPropagator<'a, 'tcx> {
2124
parent_cfg: Option<Arc<Cfg>>,
25+
parent: Option<LocalDefId>,
26+
cx: &'a mut DocContext<'tcx>,
2227
}
2328

24-
impl DocFolder for CfgPropagator {
29+
impl<'a, 'tcx> DocFolder for CfgPropagator<'a, 'tcx> {
2530
fn fold_item(&mut self, mut item: Item) -> Option<Item> {
2631
let old_parent_cfg = self.parent_cfg.clone();
2732

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+
let def_id = hir.local_def_id(parent_hir_id).to_def_id();
45+
attrs.extend_from_slice(load_attrs(self.cx, def_id));
46+
}
47+
let (_, cfg) =
48+
merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs));
49+
item.cfg = cfg;
50+
}
51+
}
2852
let new_cfg = match (self.parent_cfg.take(), item.cfg.take()) {
2953
(None, None) => None,
3054
(Some(rc), None) | (None, Some(rc)) => Some(rc),
@@ -37,8 +61,15 @@ impl DocFolder for CfgPropagator {
3761
self.parent_cfg = new_cfg.clone();
3862
item.cfg = new_cfg;
3963

64+
let old_parent =
65+
if let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) {
66+
self.parent.replace(def_id)
67+
} else {
68+
self.parent.take()
69+
};
4070
let result = self.fold_item_recur(item);
4171
self.parent_cfg = old_parent_cfg;
72+
self.parent = old_parent;
4273

4374
Some(result)
4475
}

Diff for: src/test/rustdoc/cfg_doc_reexport.rs

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#![feature(doc_cfg)]
2+
#![feature(no_core)]
3+
4+
#![crate_name = "foo"]
5+
#![no_core]
6+
7+
// @has 'foo/index.html'
8+
// @has - '//*[@class="item-left module-item"]/*[@class="stab portability"]' 'foobar'
9+
// @has - '//*[@class="item-left module-item"]/*[@class="stab portability"]' 'bar'
10+
11+
#[doc(cfg(feature = "foobar"))]
12+
mod imp_priv {
13+
// @has 'foo/struct.BarPriv.html'
14+
// @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
15+
// 'Available on crate feature foobar only.'
16+
pub struct BarPriv {}
17+
impl BarPriv {
18+
pub fn test() {}
19+
}
20+
}
21+
#[doc(cfg(feature = "foobar"))]
22+
pub use crate::imp_priv::*;
23+
24+
pub mod bar {
25+
// @has 'foo/bar/struct.Bar.html'
26+
// @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
27+
// 'Available on crate feature bar only.'
28+
#[doc(cfg(feature = "bar"))]
29+
pub struct Bar;
30+
}
31+
32+
#[doc(cfg(feature = "bar"))]
33+
pub use bar::Bar;

0 commit comments

Comments
 (0)