]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012-2013 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 | //! Support for inlining external documentation into the current AST. | |
12 | ||
32a655c1 SL |
13 | use std::collections::BTreeMap; |
14 | use std::io; | |
54a0048b | 15 | use std::iter::once; |
7cac9316 | 16 | use std::rc::Rc; |
9346a6ac | 17 | |
1a4d82fc | 18 | use syntax::ast; |
54a0048b | 19 | use rustc::hir; |
1a4d82fc | 20 | |
c30ab7b3 | 21 | use rustc::hir::def::{Def, CtorKind}; |
54a0048b | 22 | use rustc::hir::def_id::DefId; |
476ff2be SL |
23 | use rustc::ty; |
24 | use rustc::util::nodemap::FxHashSet; | |
54a0048b | 25 | |
a7813a04 | 26 | use core::{DocContext, DocAccessLevels}; |
1a4d82fc | 27 | use doctree; |
a7813a04 | 28 | use clean::{self, GetDefId}; |
1a4d82fc | 29 | |
a7813a04 | 30 | use super::Clean; |
1a4d82fc | 31 | |
476ff2be | 32 | /// Attempt to inline a definition into this AST. |
1a4d82fc | 33 | /// |
476ff2be SL |
34 | /// This function will fetch the definition specified, and if it is |
35 | /// from another crate it will attempt to inline the documentation | |
36 | /// from the other crate into this crate. | |
1a4d82fc JJ |
37 | /// |
38 | /// This is primarily used for `pub use` statements which are, in general, | |
39 | /// implementation details. Inlining the documentation should help provide a | |
40 | /// better experience when reading the documentation in this use case. | |
41 | /// | |
476ff2be SL |
42 | /// The returned value is `None` if the definition could not be inlined, |
43 | /// and `Some` of a vector of items if it was successfully expanded. | |
7cac9316 | 44 | pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name) |
1a4d82fc | 45 | -> Option<Vec<clean::Item>> { |
476ff2be | 46 | if def == Def::Err { return None } |
1a4d82fc | 47 | let did = def.def_id(); |
e9174d1e | 48 | if did.is_local() { return None } |
1a4d82fc | 49 | let mut ret = Vec::new(); |
1a4d82fc | 50 | let inner = match def { |
7453a54e | 51 | Def::Trait(did) => { |
c30ab7b3 | 52 | record_extern_fqn(cx, did, clean::TypeKind::Trait); |
476ff2be SL |
53 | ret.extend(build_impls(cx, did)); |
54 | clean::TraitItem(build_external_trait(cx, did)) | |
1a4d82fc | 55 | } |
7453a54e | 56 | Def::Fn(did) => { |
c30ab7b3 | 57 | record_extern_fqn(cx, did, clean::TypeKind::Function); |
476ff2be | 58 | clean::FunctionItem(build_external_function(cx, did)) |
1a4d82fc | 59 | } |
c30ab7b3 SL |
60 | Def::Struct(did) => { |
61 | record_extern_fqn(cx, did, clean::TypeKind::Struct); | |
476ff2be SL |
62 | ret.extend(build_impls(cx, did)); |
63 | clean::StructItem(build_struct(cx, did)) | |
1a4d82fc | 64 | } |
9e0c209e | 65 | Def::Union(did) => { |
c30ab7b3 | 66 | record_extern_fqn(cx, did, clean::TypeKind::Union); |
476ff2be SL |
67 | ret.extend(build_impls(cx, did)); |
68 | clean::UnionItem(build_union(cx, did)) | |
9e0c209e | 69 | } |
7453a54e | 70 | Def::TyAlias(did) => { |
c30ab7b3 | 71 | record_extern_fqn(cx, did, clean::TypeKind::Typedef); |
476ff2be SL |
72 | ret.extend(build_impls(cx, did)); |
73 | clean::TypedefItem(build_type_alias(cx, did), false) | |
1a4d82fc | 74 | } |
7453a54e | 75 | Def::Enum(did) => { |
c30ab7b3 | 76 | record_extern_fqn(cx, did, clean::TypeKind::Enum); |
476ff2be SL |
77 | ret.extend(build_impls(cx, did)); |
78 | clean::EnumItem(build_enum(cx, did)) | |
1a4d82fc JJ |
79 | } |
80 | // Assume that the enum type is reexported next to the variant, and | |
81 | // variants don't show up in documentation specially. | |
c30ab7b3 SL |
82 | // Similarly, consider that struct type is reexported next to its constructor. |
83 | Def::Variant(..) | | |
84 | Def::VariantCtor(..) | | |
85 | Def::StructCtor(..) => return Some(Vec::new()), | |
7453a54e | 86 | Def::Mod(did) => { |
c30ab7b3 | 87 | record_extern_fqn(cx, did, clean::TypeKind::Module); |
476ff2be | 88 | clean::ModuleItem(build_module(cx, did)) |
1a4d82fc | 89 | } |
7453a54e | 90 | Def::Static(did, mtbl) => { |
c30ab7b3 | 91 | record_extern_fqn(cx, did, clean::TypeKind::Static); |
476ff2be | 92 | clean::StaticItem(build_static(cx, did, mtbl)) |
1a4d82fc | 93 | } |
c30ab7b3 SL |
94 | Def::Const(did) => { |
95 | record_extern_fqn(cx, did, clean::TypeKind::Const); | |
476ff2be | 96 | clean::ConstantItem(build_const(cx, did)) |
1a4d82fc JJ |
97 | } |
98 | _ => return None, | |
99 | }; | |
a7813a04 | 100 | cx.renderinfo.borrow_mut().inlined.insert(did); |
1a4d82fc | 101 | ret.push(clean::Item { |
7cac9316 XL |
102 | source: cx.tcx.def_span(did).clean(cx), |
103 | name: Some(name.clean(cx)), | |
476ff2be | 104 | attrs: load_attrs(cx, did), |
1a4d82fc | 105 | inner: inner, |
a7813a04 | 106 | visibility: Some(clean::Public), |
7cac9316 XL |
107 | stability: cx.tcx.lookup_stability(did).clean(cx), |
108 | deprecation: cx.tcx.lookup_deprecation(did).clean(cx), | |
1a4d82fc JJ |
109 | def_id: did, |
110 | }); | |
111 | Some(ret) | |
112 | } | |
113 | ||
476ff2be SL |
114 | pub fn load_attrs(cx: &DocContext, did: DefId) -> clean::Attributes { |
115 | cx.tcx.get_attrs(did).clean(cx) | |
1a4d82fc JJ |
116 | } |
117 | ||
118 | /// Record an external fully qualified name in the external_paths cache. | |
119 | /// | |
120 | /// These names are used later on by HTML rendering to generate things like | |
121 | /// source links back to the original item. | |
e9174d1e | 122 | pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) { |
476ff2be SL |
123 | let crate_name = cx.tcx.sess.cstore.crate_name(did.krate).to_string(); |
124 | let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| { | |
125 | // extern blocks have an empty name | |
126 | let s = elem.data.to_string(); | |
127 | if !s.is_empty() { | |
128 | Some(s) | |
129 | } else { | |
130 | None | |
131 | } | |
132 | }); | |
133 | let fqn = once(crate_name).chain(relative).collect(); | |
134 | cx.renderinfo.borrow_mut().external_paths.insert(did, (fqn, kind)); | |
1a4d82fc JJ |
135 | } |
136 | ||
476ff2be SL |
137 | pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait { |
138 | let trait_items = cx.tcx.associated_items(did).map(|item| item.clean(cx)).collect(); | |
7cac9316 XL |
139 | let predicates = cx.tcx.predicates_of(did); |
140 | let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); | |
9346a6ac AL |
141 | let generics = filter_non_trait_generics(did, generics); |
142 | let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); | |
1a4d82fc | 143 | clean::Trait { |
7cac9316 | 144 | unsafety: cx.tcx.trait_def(did).unsafety, |
9346a6ac | 145 | generics: generics, |
c34b1796 | 146 | items: trait_items, |
9346a6ac | 147 | bounds: supertrait_bounds, |
1a4d82fc JJ |
148 | } |
149 | } | |
150 | ||
476ff2be | 151 | fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function { |
7cac9316 | 152 | let sig = cx.tcx.type_of(did).fn_sig(); |
92a42be0 | 153 | |
476ff2be | 154 | let constness = if cx.tcx.sess.cstore.is_const_fn(did) { |
92a42be0 SL |
155 | hir::Constness::Const |
156 | } else { | |
157 | hir::Constness::NotConst | |
158 | }; | |
159 | ||
7cac9316 | 160 | let predicates = cx.tcx.predicates_of(did); |
1a4d82fc | 161 | clean::Function { |
8bb4bdeb | 162 | decl: (did, sig).clean(cx), |
7cac9316 | 163 | generics: (cx.tcx.generics_of(did), &predicates).clean(cx), |
8bb4bdeb | 164 | unsafety: sig.unsafety(), |
92a42be0 | 165 | constness: constness, |
8bb4bdeb | 166 | abi: sig.abi(), |
1a4d82fc JJ |
167 | } |
168 | } | |
169 | ||
476ff2be | 170 | fn build_enum(cx: &DocContext, did: DefId) -> clean::Enum { |
7cac9316 | 171 | let predicates = cx.tcx.predicates_of(did); |
9e0c209e SL |
172 | |
173 | clean::Enum { | |
7cac9316 | 174 | generics: (cx.tcx.generics_of(did), &predicates).clean(cx), |
9e0c209e | 175 | variants_stripped: false, |
7cac9316 | 176 | variants: cx.tcx.adt_def(did).variants.clean(cx), |
9e0c209e SL |
177 | } |
178 | } | |
179 | ||
476ff2be | 180 | fn build_struct(cx: &DocContext, did: DefId) -> clean::Struct { |
7cac9316 XL |
181 | let predicates = cx.tcx.predicates_of(did); |
182 | let variant = cx.tcx.adt_def(did).struct_variant(); | |
1a4d82fc JJ |
183 | |
184 | clean::Struct { | |
c30ab7b3 SL |
185 | struct_type: match variant.ctor_kind { |
186 | CtorKind::Fictive => doctree::Plain, | |
187 | CtorKind::Fn => doctree::Tuple, | |
188 | CtorKind::Const => doctree::Unit, | |
1a4d82fc | 189 | }, |
7cac9316 | 190 | generics: (cx.tcx.generics_of(did), &predicates).clean(cx), |
e9174d1e | 191 | fields: variant.fields.clean(cx), |
1a4d82fc JJ |
192 | fields_stripped: false, |
193 | } | |
194 | } | |
195 | ||
476ff2be | 196 | fn build_union(cx: &DocContext, did: DefId) -> clean::Union { |
7cac9316 XL |
197 | let predicates = cx.tcx.predicates_of(did); |
198 | let variant = cx.tcx.adt_def(did).struct_variant(); | |
9e0c209e SL |
199 | |
200 | clean::Union { | |
201 | struct_type: doctree::Plain, | |
7cac9316 | 202 | generics: (cx.tcx.generics_of(did), &predicates).clean(cx), |
9e0c209e SL |
203 | fields: variant.fields.clean(cx), |
204 | fields_stripped: false, | |
1a4d82fc | 205 | } |
9e0c209e SL |
206 | } |
207 | ||
476ff2be | 208 | fn build_type_alias(cx: &DocContext, did: DefId) -> clean::Typedef { |
7cac9316 | 209 | let predicates = cx.tcx.predicates_of(did); |
1a4d82fc | 210 | |
9e0c209e | 211 | clean::Typedef { |
7cac9316 XL |
212 | type_: cx.tcx.type_of(did).clean(cx), |
213 | generics: (cx.tcx.generics_of(did), &predicates).clean(cx), | |
9e0c209e | 214 | } |
1a4d82fc JJ |
215 | } |
216 | ||
476ff2be SL |
217 | pub fn build_impls(cx: &DocContext, did: DefId) -> Vec<clean::Item> { |
218 | let tcx = cx.tcx; | |
1a4d82fc JJ |
219 | let mut impls = Vec::new(); |
220 | ||
7cac9316 | 221 | for &did in tcx.inherent_impls(did).iter() { |
cc61c64b | 222 | build_impl(cx, did, &mut impls); |
1a4d82fc | 223 | } |
cc61c64b | 224 | |
9e0c209e SL |
225 | // If this is the first time we've inlined something from another crate, then |
226 | // we inline *all* impls from all the crates into this crate. Note that there's | |
1a4d82fc JJ |
227 | // currently no way for us to filter this based on type, and we likely need |
228 | // many impls for a variety of reasons. | |
229 | // | |
230 | // Primarily, the impls will be used to populate the documentation for this | |
231 | // type being inlined, but impls can also be used when generating | |
232 | // documentation for primitives (no way to find those specifically). | |
9e0c209e SL |
233 | if cx.populated_all_crate_impls.get() { |
234 | return impls; | |
235 | } | |
1a4d82fc | 236 | |
9e0c209e SL |
237 | cx.populated_all_crate_impls.set(true); |
238 | ||
239 | for did in tcx.sess.cstore.implementations_of_trait(None) { | |
476ff2be | 240 | build_impl(cx, did, &mut impls); |
9e0c209e SL |
241 | } |
242 | ||
243 | // Also try to inline primitive impls from other crates. | |
244 | let primitive_impls = [ | |
245 | tcx.lang_items.isize_impl(), | |
246 | tcx.lang_items.i8_impl(), | |
247 | tcx.lang_items.i16_impl(), | |
248 | tcx.lang_items.i32_impl(), | |
249 | tcx.lang_items.i64_impl(), | |
32a655c1 | 250 | tcx.lang_items.i128_impl(), |
9e0c209e SL |
251 | tcx.lang_items.usize_impl(), |
252 | tcx.lang_items.u8_impl(), | |
253 | tcx.lang_items.u16_impl(), | |
254 | tcx.lang_items.u32_impl(), | |
255 | tcx.lang_items.u64_impl(), | |
32a655c1 | 256 | tcx.lang_items.u128_impl(), |
9e0c209e SL |
257 | tcx.lang_items.f32_impl(), |
258 | tcx.lang_items.f64_impl(), | |
259 | tcx.lang_items.char_impl(), | |
260 | tcx.lang_items.str_impl(), | |
261 | tcx.lang_items.slice_impl(), | |
c30ab7b3 SL |
262 | tcx.lang_items.const_ptr_impl(), |
263 | tcx.lang_items.mut_ptr_impl(), | |
9e0c209e SL |
264 | ]; |
265 | ||
266 | for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) { | |
267 | if !def_id.is_local() { | |
476ff2be | 268 | build_impl(cx, def_id, &mut impls); |
1a4d82fc JJ |
269 | } |
270 | } | |
271 | ||
a7813a04 | 272 | impls |
1a4d82fc JJ |
273 | } |
274 | ||
476ff2be | 275 | pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) { |
a7813a04 | 276 | if !cx.renderinfo.borrow_mut().inlined.insert(did) { |
d9579d0f | 277 | return |
1a4d82fc JJ |
278 | } |
279 | ||
476ff2be SL |
280 | let attrs = load_attrs(cx, did); |
281 | let tcx = cx.tcx; | |
92a42be0 | 282 | let associated_trait = tcx.impl_trait_ref(did); |
a7813a04 XL |
283 | |
284 | // Only inline impl if the implemented trait is | |
285 | // reachable in rustdoc generated documentation | |
286 | if let Some(traitref) = associated_trait { | |
287 | if !cx.access_levels.borrow().is_doc_reachable(traitref.def_id) { | |
d9579d0f | 288 | return |
1a4d82fc | 289 | } |
1a4d82fc JJ |
290 | } |
291 | ||
c34b1796 | 292 | // If this is a defaulted impl, then bail out early here |
7cac9316 | 293 | if tcx.is_default_impl(did) { |
d9579d0f | 294 | return ret.push(clean::Item { |
c34b1796 AL |
295 | inner: clean::DefaultImplItem(clean::DefaultImpl { |
296 | // FIXME: this should be decoded | |
e9174d1e | 297 | unsafety: hir::Unsafety::Normal, |
c34b1796 AL |
298 | trait_: match associated_trait.as_ref().unwrap().clean(cx) { |
299 | clean::TraitBound(polyt, _) => polyt.trait_, | |
300 | clean::RegionBound(..) => unreachable!(), | |
301 | }, | |
302 | }), | |
476ff2be | 303 | source: tcx.def_span(did).clean(cx), |
c34b1796 AL |
304 | name: None, |
305 | attrs: attrs, | |
a7813a04 XL |
306 | visibility: Some(clean::Inherited), |
307 | stability: tcx.lookup_stability(did).clean(cx), | |
308 | deprecation: tcx.lookup_deprecation(did).clean(cx), | |
c34b1796 AL |
309 | def_id: did, |
310 | }); | |
311 | } | |
312 | ||
7cac9316 | 313 | let for_ = tcx.type_of(did).clean(cx); |
a7813a04 XL |
314 | |
315 | // Only inline impl if the implementing type is | |
316 | // reachable in rustdoc generated documentation | |
317 | if let Some(did) = for_.def_id() { | |
318 | if !cx.access_levels.borrow().is_doc_reachable(did) { | |
319 | return | |
320 | } | |
321 | } | |
322 | ||
7cac9316 | 323 | let predicates = tcx.predicates_of(did); |
476ff2be SL |
324 | let trait_items = tcx.associated_items(did).filter_map(|item| { |
325 | match item.kind { | |
326 | ty::AssociatedKind::Const => { | |
327 | let default = if item.defaultness.has_value() { | |
32a655c1 | 328 | Some(print_inlined_const(cx, item.def_id)) |
b039eaaf SL |
329 | } else { |
330 | None | |
d9579d0f AL |
331 | }; |
332 | Some(clean::Item { | |
476ff2be | 333 | name: Some(item.name.clean(cx)), |
d9579d0f | 334 | inner: clean::AssociatedConstItem( |
7cac9316 | 335 | tcx.type_of(item.def_id).clean(cx), |
d9579d0f AL |
336 | default, |
337 | ), | |
476ff2be SL |
338 | source: tcx.def_span(item.def_id).clean(cx), |
339 | attrs: clean::Attributes::default(), | |
d9579d0f | 340 | visibility: None, |
476ff2be SL |
341 | stability: tcx.lookup_stability(item.def_id).clean(cx), |
342 | deprecation: tcx.lookup_deprecation(item.def_id).clean(cx), | |
343 | def_id: item.def_id | |
d9579d0f AL |
344 | }) |
345 | } | |
476ff2be SL |
346 | ty::AssociatedKind::Method => { |
347 | if item.vis != ty::Visibility::Public && associated_trait.is_none() { | |
1a4d82fc JJ |
348 | return None |
349 | } | |
476ff2be SL |
350 | let mut cleaned = item.clean(cx); |
351 | cleaned.inner = match cleaned.inner.clone() { | |
1a4d82fc | 352 | clean::TyMethodItem(clean::TyMethod { |
a7813a04 | 353 | unsafety, decl, generics, abi |
1a4d82fc | 354 | }) => { |
476ff2be | 355 | let constness = if tcx.sess.cstore.is_const_fn(item.def_id) { |
92a42be0 SL |
356 | hir::Constness::Const |
357 | } else { | |
358 | hir::Constness::NotConst | |
359 | }; | |
360 | ||
1a4d82fc JJ |
361 | clean::MethodItem(clean::Method { |
362 | unsafety: unsafety, | |
92a42be0 | 363 | constness: constness, |
1a4d82fc | 364 | decl: decl, |
1a4d82fc | 365 | generics: generics, |
85aaf69f | 366 | abi: abi |
1a4d82fc JJ |
367 | }) |
368 | } | |
476ff2be | 369 | ref r => panic!("not a tymethod: {:?}", r), |
1a4d82fc | 370 | }; |
476ff2be | 371 | Some(cleaned) |
1a4d82fc | 372 | } |
476ff2be | 373 | ty::AssociatedKind::Type => { |
9e0c209e | 374 | let typedef = clean::Typedef { |
7cac9316 | 375 | type_: tcx.type_of(item.def_id).clean(cx), |
9e0c209e SL |
376 | generics: clean::Generics { |
377 | lifetimes: vec![], | |
378 | type_params: vec![], | |
379 | where_predicates: vec![] | |
380 | } | |
62682a34 | 381 | }; |
85aaf69f | 382 | Some(clean::Item { |
476ff2be | 383 | name: Some(item.name.clean(cx)), |
62682a34 | 384 | inner: clean::TypedefItem(typedef, true), |
476ff2be SL |
385 | source: tcx.def_span(item.def_id).clean(cx), |
386 | attrs: clean::Attributes::default(), | |
85aaf69f | 387 | visibility: None, |
476ff2be SL |
388 | stability: tcx.lookup_stability(item.def_id).clean(cx), |
389 | deprecation: tcx.lookup_deprecation(item.def_id).clean(cx), | |
390 | def_id: item.def_id | |
85aaf69f | 391 | }) |
1a4d82fc JJ |
392 | } |
393 | } | |
d9579d0f | 394 | }).collect::<Vec<_>>(); |
7cac9316 | 395 | let polarity = tcx.impl_polarity(did); |
d9579d0f AL |
396 | let trait_ = associated_trait.clean(cx).map(|bound| { |
397 | match bound { | |
398 | clean::TraitBound(polyt, _) => polyt.trait_, | |
399 | clean::RegionBound(..) => unreachable!(), | |
400 | } | |
401 | }); | |
476ff2be | 402 | if trait_.def_id() == tcx.lang_items.deref_trait() { |
54a0048b | 403 | super::build_deref_target_impls(cx, &trait_items, ret); |
d9579d0f | 404 | } |
54a0048b SL |
405 | |
406 | let provided = trait_.def_id().map(|did| { | |
476ff2be SL |
407 | tcx.provided_trait_methods(did) |
408 | .into_iter() | |
409 | .map(|meth| meth.name.to_string()) | |
410 | .collect() | |
411 | }).unwrap_or(FxHashSet()); | |
54a0048b | 412 | |
d9579d0f | 413 | ret.push(clean::Item { |
1a4d82fc | 414 | inner: clean::ImplItem(clean::Impl { |
e9174d1e | 415 | unsafety: hir::Unsafety::Normal, // FIXME: this should be decoded |
54a0048b | 416 | provided_trait_methods: provided, |
d9579d0f | 417 | trait_: trait_, |
a7813a04 | 418 | for_: for_, |
7cac9316 | 419 | generics: (tcx.generics_of(did), &predicates).clean(cx), |
1a4d82fc | 420 | items: trait_items, |
9e0c209e | 421 | polarity: Some(polarity.clean(cx)), |
1a4d82fc | 422 | }), |
476ff2be | 423 | source: tcx.def_span(did).clean(cx), |
1a4d82fc JJ |
424 | name: None, |
425 | attrs: attrs, | |
a7813a04 XL |
426 | visibility: Some(clean::Inherited), |
427 | stability: tcx.lookup_stability(did).clean(cx), | |
428 | deprecation: tcx.lookup_deprecation(did).clean(cx), | |
1a4d82fc JJ |
429 | def_id: did, |
430 | }); | |
7453a54e | 431 | } |
1a4d82fc | 432 | |
476ff2be | 433 | fn build_module(cx: &DocContext, did: DefId) -> clean::Module { |
1a4d82fc | 434 | let mut items = Vec::new(); |
476ff2be | 435 | fill_in(cx, did, &mut items); |
1a4d82fc JJ |
436 | return clean::Module { |
437 | items: items, | |
438 | is_crate: false, | |
439 | }; | |
440 | ||
476ff2be | 441 | fn fill_in(cx: &DocContext, did: DefId, items: &mut Vec<clean::Item>) { |
9346a6ac AL |
442 | // If we're reexporting a reexport it may actually reexport something in |
443 | // two namespaces, so the target may be listed twice. Make sure we only | |
444 | // visit each node at most once. | |
476ff2be SL |
445 | let mut visited = FxHashSet(); |
446 | for item in cx.tcx.sess.cstore.item_children(did) { | |
c30ab7b3 | 447 | let def_id = item.def.def_id(); |
476ff2be | 448 | if cx.tcx.sess.cstore.visibility(def_id) == ty::Visibility::Public { |
c30ab7b3 | 449 | if !visited.insert(def_id) { continue } |
7cac9316 | 450 | if let Some(i) = try_inline(cx, item.def, item.ident.name) { |
c30ab7b3 | 451 | items.extend(i) |
1a4d82fc | 452 | } |
1a4d82fc | 453 | } |
92a42be0 | 454 | } |
1a4d82fc JJ |
455 | } |
456 | } | |
457 | ||
32a655c1 | 458 | struct InlinedConst { |
7cac9316 | 459 | nested_bodies: Rc<BTreeMap<hir::BodyId, hir::Body>> |
32a655c1 SL |
460 | } |
461 | ||
462 | impl hir::print::PpAnn for InlinedConst { | |
463 | fn nested(&self, state: &mut hir::print::State, nested: hir::print::Nested) | |
464 | -> io::Result<()> { | |
465 | if let hir::print::Nested::Body(body) = nested { | |
466 | state.print_expr(&self.nested_bodies[&body].value) | |
467 | } else { | |
468 | Ok(()) | |
469 | } | |
470 | } | |
471 | } | |
1a4d82fc | 472 | |
32a655c1 | 473 | fn print_inlined_const(cx: &DocContext, did: DefId) -> String { |
cc61c64b | 474 | let body = cx.tcx.sess.cstore.item_body(cx.tcx, did); |
32a655c1 | 475 | let inlined = InlinedConst { |
7cac9316 | 476 | nested_bodies: cx.tcx.item_body_nested_bodies(did) |
32a655c1 SL |
477 | }; |
478 | hir::print::to_string(&inlined, |s| s.print_expr(&body.value)) | |
479 | } | |
480 | ||
481 | fn build_const(cx: &DocContext, did: DefId) -> clean::Constant { | |
1a4d82fc | 482 | clean::Constant { |
7cac9316 | 483 | type_: cx.tcx.type_of(did).clean(cx), |
32a655c1 | 484 | expr: print_inlined_const(cx, did) |
1a4d82fc JJ |
485 | } |
486 | } | |
487 | ||
476ff2be | 488 | fn build_static(cx: &DocContext, did: DefId, mutable: bool) -> clean::Static { |
1a4d82fc | 489 | clean::Static { |
7cac9316 | 490 | type_: cx.tcx.type_of(did).clean(cx), |
1a4d82fc JJ |
491 | mutability: if mutable {clean::Mutable} else {clean::Immutable}, |
492 | expr: "\n\n\n".to_string(), // trigger the "[definition]" links | |
493 | } | |
494 | } | |
9346a6ac AL |
495 | |
496 | /// A trait's generics clause actually contains all of the predicates for all of | |
497 | /// its associated types as well. We specifically move these clauses to the | |
498 | /// associated types instead when displaying, so when we're genering the | |
499 | /// generics for the trait itself we need to be sure to remove them. | |
9e0c209e | 500 | /// We also need to remove the implied "recursive" Self: Trait bound. |
9346a6ac AL |
501 | /// |
502 | /// The inverse of this filtering logic can be found in the `Clean` | |
503 | /// implementation for `AssociatedType` | |
e9174d1e | 504 | fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) |
9346a6ac | 505 | -> clean::Generics { |
9e0c209e SL |
506 | for pred in &mut g.where_predicates { |
507 | match *pred { | |
508 | clean::WherePredicate::BoundPredicate { | |
509 | ty: clean::Generic(ref s), | |
510 | ref mut bounds | |
511 | } if *s == "Self" => { | |
512 | bounds.retain(|bound| { | |
513 | match *bound { | |
514 | clean::TyParamBound::TraitBound(clean::PolyTrait { | |
515 | trait_: clean::ResolvedPath { did, .. }, | |
516 | .. | |
517 | }, _) => did != trait_did, | |
518 | _ => true | |
519 | } | |
520 | }); | |
521 | } | |
522 | _ => {} | |
523 | } | |
524 | } | |
525 | ||
9346a6ac AL |
526 | g.where_predicates.retain(|pred| { |
527 | match *pred { | |
528 | clean::WherePredicate::BoundPredicate { | |
529 | ty: clean::QPath { | |
530 | self_type: box clean::Generic(ref s), | |
531 | trait_: box clean::ResolvedPath { did, .. }, | |
532 | name: ref _name, | |
9e0c209e SL |
533 | }, ref bounds |
534 | } => !(*s == "Self" && did == trait_did) && !bounds.is_empty(), | |
9346a6ac AL |
535 | _ => true, |
536 | } | |
537 | }); | |
c30ab7b3 | 538 | g |
9346a6ac AL |
539 | } |
540 | ||
541 | /// Supertrait bounds for a trait are also listed in the generics coming from | |
542 | /// the metadata for a crate, so we want to separate those out and create a new | |
543 | /// list of explicit supertrait bounds to render nicely. | |
544 | fn separate_supertrait_bounds(mut g: clean::Generics) | |
545 | -> (clean::Generics, Vec<clean::TyParamBound>) { | |
546 | let mut ty_bounds = Vec::new(); | |
547 | g.where_predicates.retain(|pred| { | |
548 | match *pred { | |
549 | clean::WherePredicate::BoundPredicate { | |
550 | ty: clean::Generic(ref s), | |
551 | ref bounds | |
552 | } if *s == "Self" => { | |
553 | ty_bounds.extend(bounds.iter().cloned()); | |
554 | false | |
555 | } | |
556 | _ => true, | |
557 | } | |
558 | }); | |
559 | (g, ty_bounds) | |
560 | } |