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