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