]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/passes/mod.rs
rustdoc: rework how default passes are chosen
[rust.git] / src / librustdoc / passes / mod.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use rustc::hir::def_id::DefId;
12 use rustc::middle::privacy::AccessLevels;
13 use rustc::util::nodemap::DefIdSet;
14 use std::mem;
15
16 use clean::{self, GetDefId, Item};
17 use fold;
18 use fold::FoldItem::Strip;
19
20 mod collapse_docs;
21 pub use self::collapse_docs::collapse_docs;
22
23 mod strip_hidden;
24 pub use self::strip_hidden::strip_hidden;
25
26 mod strip_private;
27 pub use self::strip_private::strip_private;
28
29 mod strip_priv_imports;
30 pub use self::strip_priv_imports::strip_priv_imports;
31
32 mod unindent_comments;
33 pub use self::unindent_comments::unindent_comments;
34
35 mod propagate_doc_cfg;
36 pub use self::propagate_doc_cfg::propagate_doc_cfg;
37
38 type Pass = (&'static str,                                      // name
39              fn(clean::Crate) -> clean::Crate,                  // fn
40              &'static str);                                     // description
41
42 pub const PASSES: &'static [Pass] = &[
43     ("strip-hidden", strip_hidden,
44      "strips all doc(hidden) items from the output"),
45     ("unindent-comments", unindent_comments,
46      "removes excess indentation on comments in order for markdown to like it"),
47     ("collapse-docs", collapse_docs,
48      "concatenates all document attributes into one document attribute"),
49     ("strip-private", strip_private,
50      "strips all private items from a crate which cannot be seen externally, \
51       implies strip-priv-imports"),
52     ("strip-priv-imports", strip_priv_imports,
53      "strips all private import statements (`use`, `extern crate`) from a crate"),
54     ("propagate-doc-cfg", propagate_doc_cfg,
55      "propagates `#[doc(cfg(...))]` to child items"),
56 ];
57
58 pub const DEFAULT_PASSES: &'static [&'static str] = &[
59     "strip-hidden",
60     "strip-private",
61     "collapse-docs",
62     "unindent-comments",
63     "propagate-doc-cfg",
64 ];
65
66 pub const DEFAULT_PRIVATE_PASSES: &'static [&'static str] = &[
67     "strip-priv-imports",
68     "collapse-docs",
69     "unindent-comments",
70     "propagate-doc-cfg",
71 ];
72
73 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
74 pub enum DefaultPassOption {
75     Default,
76     Private,
77     None,
78 }
79
80 pub fn defaults(default_set: DefaultPassOption) -> &'static [&'static str] {
81     match default_set {
82         DefaultPassOption::Default => {
83             DEFAULT_PASSES
84         },
85         DefaultPassOption::Private => {
86             DEFAULT_PRIVATE_PASSES
87         },
88         DefaultPassOption::None => {
89             &[]
90         },
91     }
92 }
93
94 struct Stripper<'a> {
95     retained: &'a mut DefIdSet,
96     access_levels: &'a AccessLevels<DefId>,
97     update_retained: bool,
98 }
99
100 impl<'a> fold::DocFolder for Stripper<'a> {
101     fn fold_item(&mut self, i: Item) -> Option<Item> {
102         match i.inner {
103             clean::StrippedItem(..) => {
104                 // We need to recurse into stripped modules to strip things
105                 // like impl methods but when doing so we must not add any
106                 // items to the `retained` set.
107                 let old = mem::replace(&mut self.update_retained, false);
108                 let ret = self.fold_item_recur(i);
109                 self.update_retained = old;
110                 return ret;
111             }
112             // These items can all get re-exported
113             clean::ExistentialItem(..) |
114             clean::TypedefItem(..) | clean::StaticItem(..) |
115             clean::StructItem(..) | clean::EnumItem(..) |
116             clean::TraitItem(..) | clean::FunctionItem(..) |
117             clean::VariantItem(..) | clean::MethodItem(..) |
118             clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
119             clean::ConstantItem(..) | clean::UnionItem(..) |
120             clean::AssociatedConstItem(..) | clean::ForeignTypeItem => {
121                 if i.def_id.is_local() {
122                     if !self.access_levels.is_exported(i.def_id) {
123                         return None;
124                     }
125                 }
126             }
127
128             clean::StructFieldItem(..) => {
129                 if i.visibility != Some(clean::Public) {
130                     return Strip(i).fold();
131                 }
132             }
133
134             clean::ModuleItem(..) => {
135                 if i.def_id.is_local() && i.visibility != Some(clean::Public) {
136                     let old = mem::replace(&mut self.update_retained, false);
137                     let ret = Strip(self.fold_item_recur(i).unwrap()).fold();
138                     self.update_retained = old;
139                     return ret;
140                 }
141             }
142
143             // handled in the `strip-priv-imports` pass
144             clean::ExternCrateItem(..) | clean::ImportItem(..) => {}
145
146             clean::ImplItem(..) => {}
147
148             // tymethods/macros have no control over privacy
149             clean::MacroItem(..) | clean::TyMethodItem(..) => {}
150
151             // Primitives are never stripped
152             clean::PrimitiveItem(..) => {}
153
154             // Associated types are never stripped
155             clean::AssociatedTypeItem(..) => {}
156
157             // Keywords are never stripped
158             clean::KeywordItem(..) => {}
159         }
160
161         let fastreturn = match i.inner {
162             // nothing left to do for traits (don't want to filter their
163             // methods out, visibility controlled by the trait)
164             clean::TraitItem(..) => true,
165
166             // implementations of traits are always public.
167             clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
168             // Struct variant fields have inherited visibility
169             clean::VariantItem(clean::Variant {
170                 kind: clean::VariantKind::Struct(..)
171             }) => true,
172             _ => false,
173         };
174
175         let i = if fastreturn {
176             if self.update_retained {
177                 self.retained.insert(i.def_id);
178             }
179             return Some(i);
180         } else {
181             self.fold_item_recur(i)
182         };
183
184         if let Some(ref i) = i {
185             if self.update_retained {
186                 self.retained.insert(i.def_id);
187             }
188         }
189         i
190     }
191 }
192
193 // This stripper discards all impls which reference stripped items
194 struct ImplStripper<'a> {
195     retained: &'a DefIdSet
196 }
197
198 impl<'a> fold::DocFolder for ImplStripper<'a> {
199     fn fold_item(&mut self, i: Item) -> Option<Item> {
200         if let clean::ImplItem(ref imp) = i.inner {
201             // emptied none trait impls can be stripped
202             if imp.trait_.is_none() && imp.items.is_empty() {
203                 return None;
204             }
205             if let Some(did) = imp.for_.def_id() {
206                 if did.is_local() && !imp.for_.is_generic() &&
207                     !self.retained.contains(&did)
208                 {
209                     return None;
210                 }
211             }
212             if let Some(did) = imp.trait_.def_id() {
213                 if did.is_local() && !self.retained.contains(&did) {
214                     return None;
215                 }
216             }
217             if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
218                 for typaram in generics {
219                     if let Some(did) = typaram.def_id() {
220                         if did.is_local() && !self.retained.contains(&did) {
221                             return None;
222                         }
223                     }
224                 }
225             }
226         }
227         self.fold_item_recur(i)
228     }
229 }
230
231 // This stripper discards all private import statements (`use`, `extern crate`)
232 struct ImportStripper;
233 impl fold::DocFolder for ImportStripper {
234     fn fold_item(&mut self, i: Item) -> Option<Item> {
235         match i.inner {
236             clean::ExternCrateItem(..) |
237             clean::ImportItem(..) if i.visibility != Some(clean::Public) => None,
238             _ => self.fold_item_recur(i)
239         }
240     }
241 }