1 //! A collection of utility functions for the `strip_*` passes.
2 use rustc_hir
::def_id
::DefId
;
3 use rustc_middle
::ty
::{TyCtxt, Visibility}
;
4 use rustc_span
::symbol
::sym
;
7 use crate::clean
::{self, Item, ItemId, ItemIdSet, NestedAttributesExt}
;
8 use crate::fold
::{strip_item, DocFolder}
;
9 use crate::formats
::cache
::Cache
;
10 use crate::visit_lib
::RustdocEffectiveVisibilities
;
12 pub(crate) struct Stripper
<'a
, 'tcx
> {
13 pub(crate) retained
: &'a
mut ItemIdSet
,
14 pub(crate) effective_visibilities
: &'a RustdocEffectiveVisibilities
,
15 pub(crate) update_retained
: bool
,
16 pub(crate) is_json_output
: bool
,
17 pub(crate) tcx
: TyCtxt
<'tcx
>,
20 // We need to handle this differently for the JSON output because some non exported items could
21 // be used in public API. And so, we need these items as well. `is_exported` only checks if they
22 // are in the public API, which is not enough.
27 effective_visibilities
: &RustdocEffectiveVisibilities
,
31 effective_visibilities
.is_reachable(tcx
, item_id
.expect_def_id())
33 effective_visibilities
.is_exported(tcx
, item_id
.expect_def_id())
37 impl<'a
, 'tcx
> DocFolder
for Stripper
<'a
, 'tcx
> {
38 fn fold_item(&mut self, i
: Item
) -> Option
<Item
> {
40 clean
::StrippedItem(..) => {
41 // We need to recurse into stripped modules to strip things
42 // like impl methods but when doing so we must not add any
43 // items to the `retained` set.
44 debug
!("Stripper: recursing into stripped {:?} {:?}", i
.type_(), i
.name
);
45 let old
= mem
::replace(&mut self.update_retained
, false);
46 let ret
= self.fold_item_recur(i
);
47 self.update_retained
= old
;
50 // These items can all get re-exported
51 clean
::OpaqueTyItem(..)
52 | clean
::TypedefItem(..)
53 | clean
::StaticItem(..)
54 | clean
::StructItem(..)
56 | clean
::TraitItem(..)
57 | clean
::FunctionItem(..)
58 | clean
::VariantItem(..)
59 | clean
::MethodItem(..)
60 | clean
::ForeignFunctionItem(..)
61 | clean
::ForeignStaticItem(..)
62 | clean
::ConstantItem(..)
63 | clean
::UnionItem(..)
64 | clean
::AssocConstItem(..)
65 | clean
::AssocTypeItem(..)
66 | clean
::TraitAliasItem(..)
67 | clean
::MacroItem(..)
68 | clean
::ForeignTypeItem
=> {
69 let item_id
= i
.item_id
;
71 && !is_item_reachable(
74 self.effective_visibilities
,
78 debug
!("Stripper: stripping {:?} {:?}", i
.type_(), i
.name
);
83 clean
::StructFieldItem(..) => {
84 if i
.visibility(self.tcx
) != Some(Visibility
::Public
) {
85 return Some(strip_item(i
));
89 clean
::ModuleItem(..) => {
90 if i
.item_id
.is_local() && i
.visibility(self.tcx
) != Some(Visibility
::Public
) {
91 debug
!("Stripper: stripping module {:?}", i
.name
);
92 let old
= mem
::replace(&mut self.update_retained
, false);
93 let ret
= strip_item(self.fold_item_recur(i
));
94 self.update_retained
= old
;
99 // handled in the `strip-priv-imports` pass
100 clean
::ExternCrateItem { .. }
| clean
::ImportItem(_
) => {}
102 clean
::ImplItem(..) => {}
104 // tymethods etc. have no control over privacy
105 clean
::TyMethodItem(..) | clean
::TyAssocConstItem(..) | clean
::TyAssocTypeItem(..) => {}
107 // Proc-macros are always public
108 clean
::ProcMacroItem(..) => {}
110 // Primitives are never stripped
111 clean
::PrimitiveItem(..) => {}
113 // Keywords are never stripped
114 clean
::KeywordItem
=> {}
117 let fastreturn
= match *i
.kind
{
118 // nothing left to do for traits (don't want to filter their
119 // methods out, visibility controlled by the trait)
120 clean
::TraitItem(..) => true,
122 // implementations of traits are always public.
123 clean
::ImplItem(ref imp
) if imp
.trait_
.is_some() => true,
124 // Variant fields have inherited visibility
125 clean
::VariantItem(clean
::Variant
{
126 kind
: clean
::VariantKind
::Struct(..) | clean
::VariantKind
::Tuple(..),
132 let i
= if fastreturn
{
133 if self.update_retained
{
134 self.retained
.insert(i
.item_id
);
138 self.fold_item_recur(i
)
141 if self.update_retained
{
142 self.retained
.insert(i
.item_id
);
148 /// This stripper discards all impls which reference stripped items
149 pub(crate) struct ImplStripper
<'a
, 'tcx
> {
150 pub(crate) tcx
: TyCtxt
<'tcx
>,
151 pub(crate) retained
: &'a ItemIdSet
,
152 pub(crate) cache
: &'a Cache
,
153 pub(crate) is_json_output
: bool
,
154 pub(crate) document_private
: bool
,
157 impl<'a
> ImplStripper
<'a
, '_
> {
159 fn should_keep_impl(&self, item
: &Item
, for_def_id
: DefId
) -> bool
{
160 if !for_def_id
.is_local() || self.retained
.contains(&for_def_id
.into()) {
162 } else if self.is_json_output
{
163 // If the "for" item is exported and the impl block isn't `#[doc(hidden)]`, then we
165 self.cache
.effective_visibilities
.is_exported(self.tcx
, for_def_id
)
166 && !item
.attrs
.lists(sym
::doc
).has_word(sym
::hidden
)
173 impl<'a
> DocFolder
for ImplStripper
<'a
, '_
> {
174 fn fold_item(&mut self, i
: Item
) -> Option
<Item
> {
175 if let clean
::ImplItem(ref imp
) = *i
.kind
{
176 // Impl blocks can be skipped if they are: empty; not a trait impl; and have no
179 // There is one special case: if the impl block contains only private items.
180 if imp
.trait_
.is_none() {
181 // If the only items present are private ones and we're not rendering private items,
182 // we don't document it.
183 if !imp
.items
.is_empty()
184 && !self.document_private
185 && imp
.items
.iter().all(|i
| {
186 let item_id
= i
.item_id
;
188 && !is_item_reachable(
191 &self.cache
.effective_visibilities
,
197 } else if imp
.items
.is_empty() && i
.doc_value().is_none() {
201 // Because we don't inline in `maybe_inline_local` if the output format is JSON,
202 // we need to make a special check for JSON output: we want to keep it unless it has
203 // a `#[doc(hidden)]` attribute if the `for_` type is exported.
204 if let Some(did
) = imp
.for_
.def_id(self.cache
) &&
205 !imp
.for_
.is_assoc_ty() && !self.should_keep_impl(&i
, did
)
207 debug
!("ImplStripper: impl item for stripped type; removing");
210 if let Some(did
) = imp
.trait_
.as_ref().map(|t
| t
.def_id()) &&
211 !self.should_keep_impl(&i
, did
) {
212 debug
!("ImplStripper: impl item for stripped trait; removing");
215 if let Some(generics
) = imp
.trait_
.as_ref().and_then(|t
| t
.generics()) {
216 for typaram
in generics
{
217 if let Some(did
) = typaram
.def_id(self.cache
) && !self.should_keep_impl(&i
, did
)
220 "ImplStripper: stripped item in trait's generics; removing impl"
227 Some(self.fold_item_recur(i
))
231 /// This stripper discards all private import statements (`use`, `extern crate`)
232 pub(crate) struct ImportStripper
<'tcx
> {
233 pub(crate) tcx
: TyCtxt
<'tcx
>,
234 pub(crate) is_json_output
: bool
,
237 impl<'tcx
> ImportStripper
<'tcx
> {
238 fn import_should_be_hidden(&self, i
: &Item
, imp
: &clean
::Import
) -> bool
{
239 if self.is_json_output
{
240 // FIXME: This should be handled the same way as for HTML output.
241 imp
.imported_item_is_doc_hidden(self.tcx
)
243 i
.attrs
.lists(sym
::doc
).has_word(sym
::hidden
)
248 impl<'tcx
> DocFolder
for ImportStripper
<'tcx
> {
249 fn fold_item(&mut self, i
: Item
) -> Option
<Item
> {
251 clean
::ImportItem(imp
) if self.import_should_be_hidden(&i
, &imp
) => None
,
252 clean
::ImportItem(_
) if i
.attrs
.lists(sym
::doc
).has_word(sym
::hidden
) => None
,
253 clean
::ExternCrateItem { .. }
| clean
::ImportItem(..)
254 if i
.visibility(self.tcx
) != Some(Visibility
::Public
) =>
258 _
=> Some(self.fold_item_recur(i
)),