]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/passes/mod.rs
Implement existential types
[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 use plugins;
20
21 mod collapse_docs;
22 pub use self::collapse_docs::collapse_docs;
23
24 mod strip_hidden;
25 pub use self::strip_hidden::strip_hidden;
26
27 mod strip_private;
28 pub use self::strip_private::strip_private;
29
30 mod strip_priv_imports;
31 pub use self::strip_priv_imports::strip_priv_imports;
32
33 mod unindent_comments;
34 pub use self::unindent_comments::unindent_comments;
35
36 mod propagate_doc_cfg;
37 pub use self::propagate_doc_cfg::propagate_doc_cfg;
38
39 type Pass = (&'static str,                                      // name
40              fn(clean::Crate) -> plugins::PluginResult,         // fn
41              &'static str);                                     // description
42
43 pub const PASSES: &'static [Pass] = &[
44     ("strip-hidden", strip_hidden,
45      "strips all doc(hidden) items from the output"),
46     ("unindent-comments", unindent_comments,
47      "removes excess indentation on comments in order for markdown to like it"),
48     ("collapse-docs", collapse_docs,
49      "concatenates all document attributes into one document attribute"),
50     ("strip-private", strip_private,
51      "strips all private items from a crate which cannot be seen externally, \
52       implies strip-priv-imports"),
53     ("strip-priv-imports", strip_priv_imports,
54      "strips all private import statements (`use`, `extern crate`) from a crate"),
55     ("propagate-doc-cfg", propagate_doc_cfg,
56      "propagates `#[doc(cfg(...))]` to child items"),
57 ];
58
59 pub const DEFAULT_PASSES: &'static [&'static str] = &[
60     "strip-hidden",
61     "strip-private",
62     "collapse-docs",
63     "unindent-comments",
64     "propagate-doc-cfg",
65 ];
66
67
68 struct Stripper<'a> {
69     retained: &'a mut DefIdSet,
70     access_levels: &'a AccessLevels<DefId>,
71     update_retained: bool,
72 }
73
74 impl<'a> fold::DocFolder for Stripper<'a> {
75     fn fold_item(&mut self, i: Item) -> Option<Item> {
76         match i.inner {
77             clean::StrippedItem(..) => {
78                 // We need to recurse into stripped modules to strip things
79                 // like impl methods but when doing so we must not add any
80                 // items to the `retained` set.
81                 let old = mem::replace(&mut self.update_retained, false);
82                 let ret = self.fold_item_recur(i);
83                 self.update_retained = old;
84                 return ret;
85             }
86             // These items can all get re-exported
87             clean::ExistentialItem(..) |
88             clean::TypedefItem(..) | clean::StaticItem(..) |
89             clean::StructItem(..) | clean::EnumItem(..) |
90             clean::TraitItem(..) | clean::FunctionItem(..) |
91             clean::VariantItem(..) | clean::MethodItem(..) |
92             clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
93             clean::ConstantItem(..) | clean::UnionItem(..) |
94             clean::AssociatedConstItem(..) | clean::ForeignTypeItem => {
95                 if i.def_id.is_local() {
96                     if !self.access_levels.is_exported(i.def_id) {
97                         return None;
98                     }
99                 }
100             }
101
102             clean::StructFieldItem(..) => {
103                 if i.visibility != Some(clean::Public) {
104                     return Strip(i).fold();
105                 }
106             }
107
108             clean::ModuleItem(..) => {
109                 if i.def_id.is_local() && i.visibility != Some(clean::Public) {
110                     let old = mem::replace(&mut self.update_retained, false);
111                     let ret = Strip(self.fold_item_recur(i).unwrap()).fold();
112                     self.update_retained = old;
113                     return ret;
114                 }
115             }
116
117             // handled in the `strip-priv-imports` pass
118             clean::ExternCrateItem(..) | clean::ImportItem(..) => {}
119
120             clean::ImplItem(..) => {}
121
122             // tymethods/macros have no control over privacy
123             clean::MacroItem(..) | clean::TyMethodItem(..) => {}
124
125             // Primitives are never stripped
126             clean::PrimitiveItem(..) => {}
127
128             // Associated types are never stripped
129             clean::AssociatedTypeItem(..) => {}
130
131             // Keywords are never stripped
132             clean::KeywordItem(..) => {}
133         }
134
135         let fastreturn = match i.inner {
136             // nothing left to do for traits (don't want to filter their
137             // methods out, visibility controlled by the trait)
138             clean::TraitItem(..) => true,
139
140             // implementations of traits are always public.
141             clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
142             // Struct variant fields have inherited visibility
143             clean::VariantItem(clean::Variant {
144                 kind: clean::VariantKind::Struct(..)
145             }) => true,
146             _ => false,
147         };
148
149         let i = if fastreturn {
150             if self.update_retained {
151                 self.retained.insert(i.def_id);
152             }
153             return Some(i);
154         } else {
155             self.fold_item_recur(i)
156         };
157
158         if let Some(ref i) = i {
159             if self.update_retained {
160                 self.retained.insert(i.def_id);
161             }
162         }
163         i
164     }
165 }
166
167 // This stripper discards all impls which reference stripped items
168 struct ImplStripper<'a> {
169     retained: &'a DefIdSet
170 }
171
172 impl<'a> fold::DocFolder for ImplStripper<'a> {
173     fn fold_item(&mut self, i: Item) -> Option<Item> {
174         if let clean::ImplItem(ref imp) = i.inner {
175             // emptied none trait impls can be stripped
176             if imp.trait_.is_none() && imp.items.is_empty() {
177                 return None;
178             }
179             if let Some(did) = imp.for_.def_id() {
180                 if did.is_local() && !imp.for_.is_generic() &&
181                     !self.retained.contains(&did)
182                 {
183                     return None;
184                 }
185             }
186             if let Some(did) = imp.trait_.def_id() {
187                 if did.is_local() && !self.retained.contains(&did) {
188                     return None;
189                 }
190             }
191             if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
192                 for typaram in generics {
193                     if let Some(did) = typaram.def_id() {
194                         if did.is_local() && !self.retained.contains(&did) {
195                             return None;
196                         }
197                     }
198                 }
199             }
200         }
201         self.fold_item_recur(i)
202     }
203 }
204
205 // This stripper discards all private import statements (`use`, `extern crate`)
206 struct ImportStripper;
207 impl fold::DocFolder for ImportStripper {
208     fn fold_item(&mut self, i: Item) -> Option<Item> {
209         match i.inner {
210             clean::ExternCrateItem(..) |
211             clean::ImportItem(..) if i.visibility != Some(clean::Public) => None,
212             _ => self.fold_item_recur(i)
213         }
214     }
215 }