1
1
//! Strip all doc(hidden) items from the output.
2
+
3
+ use rustc_middle:: ty:: TyCtxt ;
2
4
use rustc_span:: symbol:: sym;
3
5
use std:: mem;
4
6
@@ -7,6 +9,7 @@ use crate::clean::{Item, ItemIdSet, NestedAttributesExt};
7
9
use crate :: core:: DocContext ;
8
10
use crate :: fold:: { strip_item, DocFolder } ;
9
11
use crate :: passes:: { ImplStripper , Pass } ;
12
+ use crate :: visit_ast:: inherits_doc_hidden;
10
13
11
14
pub ( crate ) const STRIP_HIDDEN : Pass = Pass {
12
15
name : "strip-hidden" ,
@@ -21,7 +24,12 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea
21
24
22
25
// strip all #[doc(hidden)] items
23
26
let krate = {
24
- let mut stripper = Stripper { retained : & mut retained, update_retained : true } ;
27
+ let mut stripper = Stripper {
28
+ retained : & mut retained,
29
+ update_retained : true ,
30
+ tcx : cx. tcx ,
31
+ is_in_hidden_item : false ,
32
+ } ;
25
33
stripper. fold_crate ( krate)
26
34
} ;
27
35
@@ -36,40 +44,89 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea
36
44
stripper. fold_crate ( krate)
37
45
}
38
46
39
- struct Stripper < ' a > {
47
+ struct Stripper < ' a , ' tcx > {
40
48
retained : & ' a mut ItemIdSet ,
41
49
update_retained : bool ,
50
+ tcx : TyCtxt < ' tcx > ,
51
+ is_in_hidden_item : bool ,
52
+ }
53
+
54
+ impl < ' a , ' tcx > Stripper < ' a , ' tcx > {
55
+ fn set_is_in_hidden_item_and_fold ( & mut self , is_in_hidden_item : bool , i : Item ) -> Item {
56
+ let prev = self . is_in_hidden_item ;
57
+ self . is_in_hidden_item |= is_in_hidden_item;
58
+ let ret = self . fold_item_recur ( i) ;
59
+ self . is_in_hidden_item = prev;
60
+ ret
61
+ }
62
+
63
+ /// In case `i` is a non-hidden impl block, then we special-case it by changing the value
64
+ /// of `is_in_hidden_item` to `true` because the impl children inherit its visibility.
65
+ fn recurse_in_impl ( & mut self , i : Item ) -> Item {
66
+ let prev = mem:: replace ( & mut self . is_in_hidden_item , false ) ;
67
+ let ret = self . fold_item_recur ( i) ;
68
+ self . is_in_hidden_item = prev;
69
+ ret
70
+ }
42
71
}
43
72
44
- impl < ' a > DocFolder for Stripper < ' a > {
73
+ impl < ' a , ' tcx > DocFolder for Stripper < ' a , ' tcx > {
45
74
fn fold_item ( & mut self , i : Item ) -> Option < Item > {
46
- if i. attrs . lists ( sym:: doc) . has_word ( sym:: hidden) {
47
- debug ! ( "strip_hidden: stripping {:?} {:?}" , i. type_( ) , i. name) ;
48
- // Use a dedicated hidden item for fields, variants, and modules.
49
- // We need to keep private fields and variants, so that the docs
50
- // can show a placeholder "// some variants omitted". We need to keep
51
- // private modules, because they can contain impl blocks, and impl
52
- // block privacy is inherited from the type and trait, not from the
53
- // module it's defined in. Both of these are marked "stripped," and
54
- // not included in the final docs, but since they still have an effect
55
- // on the final doc, cannot be completely removed from the Clean IR.
56
- match * i. kind {
57
- clean:: StructFieldItem ( ..) | clean:: ModuleItem ( ..) | clean:: VariantItem ( ..) => {
58
- // We need to recurse into stripped modules to
59
- // strip things like impl methods but when doing so
60
- // we must not add any items to the `retained` set.
61
- let old = mem:: replace ( & mut self . update_retained , false ) ;
62
- let ret = strip_item ( self . fold_item_recur ( i) ) ;
63
- self . update_retained = old;
64
- return Some ( ret) ;
65
- }
66
- _ => return None ,
75
+ let has_doc_hidden = i. attrs . lists ( sym:: doc) . has_word ( sym:: hidden) ;
76
+ let is_impl = matches ! ( * i. kind, clean:: ImplItem ( ..) ) ;
77
+ let mut is_hidden = has_doc_hidden;
78
+ if !is_impl {
79
+ is_hidden = self . is_in_hidden_item || has_doc_hidden;
80
+ if !is_hidden && i. inline_stmt_id . is_none ( ) {
81
+ // We don't need to check if it's coming from a reexport since the reexport itself was
82
+ // already checked.
83
+ is_hidden = i
84
+ . item_id
85
+ . as_def_id ( )
86
+ . and_then ( |def_id| def_id. as_local ( ) )
87
+ . map ( |def_id| inherits_doc_hidden ( self . tcx , def_id) )
88
+ . unwrap_or ( false ) ;
67
89
}
68
- } else {
90
+ }
91
+ if !is_hidden {
69
92
if self . update_retained {
70
93
self . retained . insert ( i. item_id ) ;
71
94
}
95
+ return Some ( if is_impl {
96
+ self . recurse_in_impl ( i)
97
+ } else {
98
+ self . set_is_in_hidden_item_and_fold ( false , i)
99
+ } ) ;
100
+ }
101
+ debug ! ( "strip_hidden: stripping {:?} {:?}" , i. type_( ) , i. name) ;
102
+ // Use a dedicated hidden item for fields, variants, and modules.
103
+ // We need to keep private fields and variants, so that the docs
104
+ // can show a placeholder "// some variants omitted". We need to keep
105
+ // private modules, because they can contain impl blocks, and impl
106
+ // block privacy is inherited from the type and trait, not from the
107
+ // module it's defined in. Both of these are marked "stripped," and
108
+ // not included in the final docs, but since they still have an effect
109
+ // on the final doc, cannot be completely removed from the Clean IR.
110
+ match * i. kind {
111
+ clean:: StructFieldItem ( ..) | clean:: ModuleItem ( ..) | clean:: VariantItem ( ..) => {
112
+ // We need to recurse into stripped modules to
113
+ // strip things like impl methods but when doing so
114
+ // we must not add any items to the `retained` set.
115
+ let old = mem:: replace ( & mut self . update_retained , false ) ;
116
+ let ret = strip_item ( self . set_is_in_hidden_item_and_fold ( true , i) ) ;
117
+ self . update_retained = old;
118
+ Some ( ret)
119
+ }
120
+ _ => {
121
+ let ret = self . set_is_in_hidden_item_and_fold ( true , i) ;
122
+ if has_doc_hidden {
123
+ // If the item itself has `#[doc(hidden)]`, then we simply remove it.
124
+ None
125
+ } else {
126
+ // However if it's a "descendant" of a `#[doc(hidden)]` item, then we strip it.
127
+ Some ( strip_item ( ret) )
128
+ }
129
+ }
72
130
}
73
- Some ( self . fold_item_recur ( i) )
74
131
}
75
132
}
0 commit comments