]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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::cmp::Ordering; | |
17 | use std::ops::Add; | |
18 | ||
85aaf69f | 19 | use syntax::attr::{Unstable, Stable}; |
1a4d82fc JJ |
20 | use syntax::ast::Public; |
21 | ||
22 | use clean::{Crate, Item, ModuleItem, Module, EnumItem, Enum}; | |
c34b1796 AL |
23 | use clean::{ImplItem, Impl, Trait, TraitItem}; |
24 | use clean::{ExternCrateItem, ImportItem, PrimitiveItem, Stability}; | |
1a4d82fc JJ |
25 | |
26 | use html::render::cache; | |
27 | ||
28 | #[derive(RustcEncodable, RustcDecodable, PartialEq, Eq)] | |
29 | /// The counts for each stability level. | |
c34b1796 | 30 | #[derive(Copy, Clone)] |
1a4d82fc | 31 | pub struct Counts { |
85aaf69f SL |
32 | pub deprecated: u64, |
33 | pub unstable: u64, | |
34 | pub stable: u64, | |
1a4d82fc JJ |
35 | |
36 | /// No stability level, inherited or otherwise. | |
85aaf69f | 37 | pub unmarked: u64, |
1a4d82fc JJ |
38 | } |
39 | ||
40 | impl Add for Counts { | |
41 | type Output = Counts; | |
42 | ||
43 | fn add(self, other: Counts) -> Counts { | |
44 | Counts { | |
45 | deprecated: self.deprecated + other.deprecated, | |
1a4d82fc JJ |
46 | unstable: self.unstable + other.unstable, |
47 | stable: self.stable + other.stable, | |
1a4d82fc JJ |
48 | unmarked: self.unmarked + other.unmarked, |
49 | } | |
50 | } | |
51 | } | |
52 | ||
53 | impl Counts { | |
54 | fn zero() -> Counts { | |
55 | Counts { | |
56 | deprecated: 0, | |
1a4d82fc JJ |
57 | unstable: 0, |
58 | stable: 0, | |
1a4d82fc JJ |
59 | unmarked: 0, |
60 | } | |
61 | } | |
62 | ||
85aaf69f SL |
63 | pub fn total(&self) -> u64 { |
64 | self.deprecated + self.unstable + self.stable + self.unmarked | |
1a4d82fc JJ |
65 | } |
66 | } | |
67 | ||
68 | #[derive(RustcEncodable, RustcDecodable, PartialEq, Eq)] | |
69 | /// A summarized module, which includes total counts and summarized children | |
70 | /// modules. | |
71 | pub struct ModuleSummary { | |
72 | pub name: String, | |
73 | pub counts: Counts, | |
74 | pub submodules: Vec<ModuleSummary>, | |
75 | } | |
76 | ||
77 | impl PartialOrd for ModuleSummary { | |
78 | fn partial_cmp(&self, other: &ModuleSummary) -> Option<Ordering> { | |
79 | self.name.partial_cmp(&other.name) | |
80 | } | |
81 | } | |
82 | ||
83 | impl Ord for ModuleSummary { | |
84 | fn cmp(&self, other: &ModuleSummary) -> Ordering { | |
85 | self.name.cmp(&other.name) | |
86 | } | |
87 | } | |
88 | ||
c34b1796 | 89 | // is the item considered publicly visible? |
1a4d82fc JJ |
90 | fn visible(item: &Item) -> bool { |
91 | match item.inner { | |
92 | ImplItem(_) => true, | |
93 | _ => item.visibility == Some(Public) | |
94 | } | |
95 | } | |
96 | ||
97 | fn count_stability(stab: Option<&Stability>) -> Counts { | |
98 | match stab { | |
85aaf69f SL |
99 | None => Counts { unmarked: 1, .. Counts::zero() }, |
100 | Some(ref stab) => { | |
101 | if !stab.deprecated_since.is_empty() { | |
102 | return Counts { deprecated: 1, .. Counts::zero() }; | |
103 | } | |
104 | match stab.level { | |
105 | Unstable => Counts { unstable: 1, .. Counts::zero() }, | |
106 | Stable => Counts { stable: 1, .. Counts::zero() }, | |
107 | } | |
1a4d82fc JJ |
108 | } |
109 | } | |
110 | } | |
111 | ||
112 | fn summarize_methods(item: &Item) -> Counts { | |
113 | match cache().impls.get(&item.def_id) { | |
114 | Some(v) => { | |
115 | v.iter().map(|i| { | |
116 | let count = count_stability(i.stability.as_ref()); | |
117 | if i.impl_.trait_.is_none() { | |
118 | count + i.impl_.items.iter() | |
119 | .map(|ti| summarize_item(ti).0) | |
120 | .fold(Counts::zero(), |acc, c| acc + c) | |
121 | } else { | |
122 | count | |
123 | } | |
124 | }).fold(Counts::zero(), |acc, c| acc + c) | |
125 | }, | |
126 | None => { | |
127 | Counts::zero() | |
128 | }, | |
129 | } | |
130 | } | |
131 | ||
132 | ||
133 | // Produce the summary for an arbitrary item. If the item is a module, include a | |
134 | // module summary. The counts for items with nested items (e.g. modules, traits, | |
135 | // impls) include all children counts. | |
136 | fn summarize_item(item: &Item) -> (Counts, Option<ModuleSummary>) { | |
137 | let item_counts = count_stability(item.stability.as_ref()) + summarize_methods(item); | |
138 | ||
139 | // Count this item's children, if any. Note that a trait impl is | |
140 | // considered to have no children. | |
141 | match item.inner { | |
142 | // Require explicit `pub` to be visible | |
c34b1796 AL |
143 | ImplItem(Impl { ref items, trait_: None, .. }) => { |
144 | let subcounts = items.iter().filter(|i| visible(*i)) | |
145 | .map(summarize_item) | |
146 | .map(|s| s.0) | |
147 | .fold(Counts::zero(), |acc, x| acc + x); | |
1a4d82fc JJ |
148 | (subcounts, None) |
149 | } | |
150 | // `pub` automatically | |
151 | EnumItem(Enum { variants: ref subitems, .. }) => { | |
152 | let subcounts = subitems.iter().map(summarize_item) | |
153 | .map(|s| s.0) | |
154 | .fold(Counts::zero(), |acc, x| acc + x); | |
155 | (item_counts + subcounts, None) | |
156 | } | |
c34b1796 AL |
157 | TraitItem(Trait { ref items, .. }) => { |
158 | let subcounts = items.iter().map(summarize_item) | |
159 | .map(|s| s.0) | |
160 | .fold(Counts::zero(), |acc, x| acc + x); | |
1a4d82fc JJ |
161 | (item_counts + subcounts, None) |
162 | } | |
163 | ModuleItem(Module { ref items, .. }) => { | |
164 | let mut counts = item_counts; | |
165 | let mut submodules = Vec::new(); | |
166 | ||
167 | for (subcounts, submodule) in items.iter().filter(|i| visible(*i)) | |
168 | .map(summarize_item) { | |
169 | counts = counts + subcounts; | |
170 | submodule.map(|m| submodules.push(m)); | |
171 | } | |
172 | submodules.sort(); | |
173 | ||
174 | (counts, Some(ModuleSummary { | |
175 | name: item.name.as_ref().map_or("".to_string(), |n| n.clone()), | |
176 | counts: counts, | |
177 | submodules: submodules, | |
178 | })) | |
179 | } | |
180 | // no stability information for the following items: | |
85aaf69f SL |
181 | ExternCrateItem(..) | ImportItem(_) | |
182 | PrimitiveItem(_) => (Counts::zero(), None), | |
1a4d82fc JJ |
183 | _ => (item_counts, None) |
184 | } | |
185 | } | |
186 | ||
187 | /// Summarizes the stability levels in a crate. | |
188 | pub fn build(krate: &Crate) -> ModuleSummary { | |
189 | match krate.module { | |
190 | None => ModuleSummary { | |
191 | name: krate.name.clone(), | |
192 | counts: Counts::zero(), | |
193 | submodules: Vec::new(), | |
194 | }, | |
195 | Some(ref item) => ModuleSummary { | |
196 | name: krate.name.clone(), .. summarize_item(item).1.unwrap() | |
197 | } | |
198 | } | |
199 | } |