]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/stability_summary.rs
auto merge of #19628 : jbranchaud/rust/add-string-as-string-doctest, r=steveklabnik
[rust.git] / src / librustdoc / stability_summary.rs
1 // Copyright 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 //! This module crawls a `clean::Crate` and produces a summarization of the
12 //! stability levels within the crate. The summary contains the module
13 //! hierarchy, with item counts for every stability level per module. A parent
14 //! module's count includes its children's.
15
16 use std::ops::Add;
17 use std::num::Zero;
18
19 use syntax::attr::{Deprecated, Experimental, Unstable, Stable, Frozen, Locked};
20 use syntax::ast::Public;
21
22 use clean::{Crate, Item, ModuleItem, Module, EnumItem, Enum};
23 use clean::{ImplItem, Impl, Trait, TraitItem, TraitMethod, ProvidedMethod, RequiredMethod};
24 use clean::{TypeTraitItem, ViewItemItem, PrimitiveItem, Stability};
25
26 use html::render::cache;
27
28 #[deriving(Zero, Encodable, Decodable, PartialEq, Eq)]
29 /// The counts for each stability level.
30 pub struct Counts {
31     pub deprecated: uint,
32     pub experimental: uint,
33     pub unstable: uint,
34     pub stable: uint,
35     pub frozen: uint,
36     pub locked: uint,
37
38     /// No stability level, inherited or otherwise.
39     pub unmarked: uint,
40 }
41
42 impl Copy for Counts {}
43
44 impl Add<Counts, Counts> for Counts {
45     fn add(&self, other: &Counts) -> Counts {
46         Counts {
47             deprecated:   self.deprecated   + other.deprecated,
48             experimental: self.experimental + other.experimental,
49             unstable:     self.unstable     + other.unstable,
50             stable:       self.stable       + other.stable,
51             frozen:       self.frozen       + other.frozen,
52             locked:       self.locked       + other.locked,
53             unmarked:     self.unmarked     + other.unmarked,
54         }
55     }
56 }
57
58 impl Counts {
59     fn zero() -> Counts {
60         Counts {
61             deprecated:   0,
62             experimental: 0,
63             unstable:     0,
64             stable:       0,
65             frozen:       0,
66             locked:       0,
67             unmarked:     0,
68         }
69     }
70
71     pub fn total(&self) -> uint {
72         self.deprecated + self.experimental + self.unstable + self.stable +
73             self.frozen + self.locked + self.unmarked
74     }
75 }
76
77 #[deriving(Encodable, Decodable, PartialEq, Eq)]
78 /// A summarized module, which includes total counts and summarized children
79 /// modules.
80 pub struct ModuleSummary {
81     pub name: String,
82     pub counts: Counts,
83     pub submodules: Vec<ModuleSummary>,
84 }
85
86 impl PartialOrd for ModuleSummary {
87     fn partial_cmp(&self, other: &ModuleSummary) -> Option<Ordering> {
88         self.name.partial_cmp(&other.name)
89     }
90 }
91
92 impl Ord for ModuleSummary {
93     fn cmp(&self, other: &ModuleSummary) -> Ordering {
94         self.name.cmp(&other.name)
95     }
96 }
97
98 // is the item considered publically visible?
99 fn visible(item: &Item) -> bool {
100     match item.inner {
101         ImplItem(_) => true,
102         _ => item.visibility == Some(Public)
103     }
104 }
105
106 fn count_stability(stab: Option<&Stability>) -> Counts {
107     match stab {
108         None             => Counts { unmarked: 1,     .. Counts::zero() },
109         Some(ref stab) => match stab.level {
110             Deprecated   => Counts { deprecated: 1,   .. Counts::zero() },
111             Experimental => Counts { experimental: 1, .. Counts::zero() },
112             Unstable     => Counts { unstable: 1,     .. Counts::zero() },
113             Stable       => Counts { stable: 1,       .. Counts::zero() },
114             Frozen       => Counts { frozen: 1,       .. Counts::zero() },
115             Locked       => Counts { locked: 1,       .. Counts::zero() },
116         }
117     }
118 }
119
120 fn summarize_methods(item: &Item) -> Counts {
121     match cache().impls.get(&item.def_id) {
122         Some(v) => {
123             v.iter().map(|i| {
124                 let count = count_stability(i.stability.as_ref());
125                 if i.impl_.trait_.is_none() {
126                     count + i.impl_.items.iter()
127                         .map(|ti| summarize_item(ti).0)
128                         .fold(Counts::zero(), |acc, c| acc + c)
129                 } else {
130                     count
131                 }
132             }).fold(Counts::zero(), |acc, c| acc + c)
133         },
134         None => {
135             Counts::zero()
136         },
137     }
138 }
139
140
141 // Produce the summary for an arbitrary item. If the item is a module, include a
142 // module summary. The counts for items with nested items (e.g. modules, traits,
143 // impls) include all children counts.
144 fn summarize_item(item: &Item) -> (Counts, Option<ModuleSummary>) {
145     let item_counts = count_stability(item.stability.as_ref()) + summarize_methods(item);
146
147     // Count this item's children, if any. Note that a trait impl is
148     // considered to have no children.
149     match item.inner {
150         // Require explicit `pub` to be visible
151         ImplItem(Impl { items: ref subitems, trait_: None, .. }) => {
152             let subcounts = subitems.iter().filter(|i| visible(*i))
153                                            .map(summarize_item)
154                                            .map(|s| s.val0())
155                                            .fold(Counts::zero(), |acc, x| acc + x);
156             (subcounts, None)
157         }
158         // `pub` automatically
159         EnumItem(Enum { variants: ref subitems, .. }) => {
160             let subcounts = subitems.iter().map(summarize_item)
161                                            .map(|s| s.val0())
162                                            .fold(Counts::zero(), |acc, x| acc + x);
163             (item_counts + subcounts, None)
164         }
165         TraitItem(Trait {
166             items: ref trait_items,
167             ..
168         }) => {
169             fn extract_item<'a>(trait_item: &'a TraitMethod) -> &'a Item {
170                 match *trait_item {
171                     ProvidedMethod(ref item) |
172                     RequiredMethod(ref item) |
173                     TypeTraitItem(ref item) => item
174                 }
175             }
176             let subcounts = trait_items.iter()
177                                        .map(extract_item)
178                                        .map(summarize_item)
179                                        .map(|s| s.val0())
180                                        .fold(Counts::zero(), |acc, x| acc + x);
181             (item_counts + subcounts, None)
182         }
183         ModuleItem(Module { ref items, .. }) => {
184             let mut counts = item_counts;
185             let mut submodules = Vec::new();
186
187             for (subcounts, submodule) in items.iter().filter(|i| visible(*i))
188                                                       .map(summarize_item) {
189                 counts = counts + subcounts;
190                 submodule.map(|m| submodules.push(m));
191             }
192             submodules.sort();
193
194             (counts, Some(ModuleSummary {
195                 name: item.name.as_ref().map_or("".to_string(), |n| n.clone()),
196                 counts: counts,
197                 submodules: submodules,
198             }))
199         }
200         // no stability information for the following items:
201         ViewItemItem(_) | PrimitiveItem(_) => (Counts::zero(), None),
202         _ => (item_counts, None)
203     }
204 }
205
206 /// Summarizes the stability levels in a crate.
207 pub fn build(krate: &Crate) -> ModuleSummary {
208     match krate.module {
209         None => ModuleSummary {
210             name: krate.name.clone(),
211             counts: Counts::zero(),
212             submodules: Vec::new(),
213         },
214         Some(ref item) => ModuleSummary {
215             name: krate.name.clone(), .. summarize_item(item).val1().unwrap()
216         }
217     }
218 }