]>
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; |
b039eaaf | 17 | use syntax::attr::AttrMetaMethods; |
54a0048b | 18 | use rustc::hir; |
1a4d82fc | 19 | |
92a42be0 | 20 | use rustc::middle::cstore::{self, CrateStore}; |
54a0048b SL |
21 | use rustc::hir::def::Def; |
22 | use rustc::hir::def_id::DefId; | |
23 | use rustc::ty::{self, TyCtxt}; | |
24 | use rustc::ty::subst; | |
1a4d82fc | 25 | use rustc::middle::stability; |
54a0048b SL |
26 | |
27 | use rustc_const_eval::lookup_const_by_id; | |
1a4d82fc JJ |
28 | |
29 | use core::DocContext; | |
30 | use doctree; | |
54a0048b | 31 | use clean::{self, Attributes, GetDefId}; |
1a4d82fc | 32 | |
d9579d0f | 33 | use super::{Clean, ToSource}; |
1a4d82fc JJ |
34 | |
35 | /// Attempt to inline the definition of a local node id into this AST. | |
36 | /// | |
37 | /// This function will fetch the definition of the id specified, and if it is | |
38 | /// from another crate it will attempt to inline the documentation from the | |
39 | /// other crate into this crate. | |
40 | /// | |
41 | /// This is primarily used for `pub use` statements which are, in general, | |
42 | /// implementation details. Inlining the documentation should help provide a | |
43 | /// better experience when reading the documentation in this use case. | |
44 | /// | |
45 | /// The returned value is `None` if the `id` could not be inlined, and `Some` | |
46 | /// of a vector of items if it was successfully expanded. | |
b039eaaf | 47 | pub fn try_inline(cx: &DocContext, id: ast::NodeId, into: Option<ast::Name>) |
1a4d82fc JJ |
48 | -> Option<Vec<clean::Item>> { |
49 | let tcx = match cx.tcx_opt() { | |
50 | Some(tcx) => tcx, | |
51 | None => return None, | |
52 | }; | |
53 | let def = match tcx.def_map.borrow().get(&id) { | |
c34b1796 | 54 | Some(d) => d.full_def(), |
1a4d82fc JJ |
55 | None => return None, |
56 | }; | |
57 | let did = def.def_id(); | |
e9174d1e | 58 | if did.is_local() { return None } |
1a4d82fc JJ |
59 | try_inline_def(cx, tcx, def).map(|vec| { |
60 | vec.into_iter().map(|mut item| { | |
61 | match into { | |
62 | Some(into) if item.name.is_some() => { | |
63 | item.name = Some(into.clean(cx)); | |
64 | } | |
65 | _ => {} | |
66 | } | |
67 | item | |
68 | }).collect() | |
69 | }) | |
70 | } | |
71 | ||
54a0048b | 72 | fn try_inline_def(cx: &DocContext, tcx: &TyCtxt, |
7453a54e | 73 | def: Def) -> Option<Vec<clean::Item>> { |
1a4d82fc JJ |
74 | let mut ret = Vec::new(); |
75 | let did = def.def_id(); | |
76 | let inner = match def { | |
7453a54e | 77 | Def::Trait(did) => { |
1a4d82fc JJ |
78 | record_extern_fqn(cx, did, clean::TypeTrait); |
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 | }; | |
1a4d82fc JJ |
119 | cx.inlined.borrow_mut().as_mut().unwrap().insert(did); |
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, | |
e9174d1e | 125 | visibility: Some(hir::Public), |
9cc50fc6 SL |
126 | stability: stability::lookup_stability(tcx, did).clean(cx), |
127 | deprecation: stability::lookup_deprecation(tcx, did).clean(cx), | |
1a4d82fc JJ |
128 | def_id: did, |
129 | }); | |
130 | Some(ret) | |
131 | } | |
132 | ||
54a0048b | 133 | pub fn load_attrs(cx: &DocContext, tcx: &TyCtxt, |
e9174d1e | 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(); | |
145 | let relative = tcx.def_path(did).data.into_iter().map(|elem| { | |
146 | elem.data.to_string() | |
147 | }); | |
148 | let fqn = once(crate_name).chain(relative).collect(); | |
149 | cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind)); | |
1a4d82fc JJ |
150 | } |
151 | } | |
152 | ||
54a0048b | 153 | pub fn build_external_trait(cx: &DocContext, tcx: &TyCtxt, |
e9174d1e | 154 | did: DefId) -> clean::Trait { |
c1a9b12d SL |
155 | let def = tcx.lookup_trait_def(did); |
156 | let trait_items = tcx.trait_items(did).clean(cx); | |
157 | let predicates = tcx.lookup_predicates(did); | |
9346a6ac AL |
158 | let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx); |
159 | let generics = filter_non_trait_generics(did, generics); | |
160 | let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); | |
1a4d82fc JJ |
161 | clean::Trait { |
162 | unsafety: def.unsafety, | |
9346a6ac | 163 | generics: generics, |
c34b1796 | 164 | items: trait_items, |
9346a6ac | 165 | bounds: supertrait_bounds, |
1a4d82fc JJ |
166 | } |
167 | } | |
168 | ||
54a0048b | 169 | fn build_external_function(cx: &DocContext, tcx: &TyCtxt, did: DefId) -> clean::Function { |
c1a9b12d | 170 | let t = tcx.lookup_item_type(did); |
9346a6ac | 171 | let (decl, style, abi) = match t.ty.sty { |
54a0048b | 172 | ty::TyFnDef(_, _, ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi), |
1a4d82fc JJ |
173 | _ => panic!("bad function"), |
174 | }; | |
92a42be0 SL |
175 | |
176 | let constness = if tcx.sess.cstore.is_const_fn(did) { | |
177 | hir::Constness::Const | |
178 | } else { | |
179 | hir::Constness::NotConst | |
180 | }; | |
181 | ||
c1a9b12d | 182 | let predicates = tcx.lookup_predicates(did); |
1a4d82fc JJ |
183 | clean::Function { |
184 | decl: decl, | |
85aaf69f | 185 | generics: (&t.generics, &predicates, subst::FnSpace).clean(cx), |
1a4d82fc | 186 | unsafety: style, |
92a42be0 | 187 | constness: constness, |
9346a6ac | 188 | abi: abi, |
1a4d82fc JJ |
189 | } |
190 | } | |
191 | ||
54a0048b | 192 | fn build_struct(cx: &DocContext, tcx: &TyCtxt, did: DefId) -> clean::Struct { |
c1a9b12d SL |
193 | let t = tcx.lookup_item_type(did); |
194 | let predicates = tcx.lookup_predicates(did); | |
e9174d1e | 195 | let variant = tcx.lookup_adt_def(did).struct_variant(); |
1a4d82fc JJ |
196 | |
197 | clean::Struct { | |
e9174d1e | 198 | struct_type: match &*variant.fields { |
1a4d82fc | 199 | [] => doctree::Unit, |
54a0048b SL |
200 | [_] if variant.kind == ty::VariantKind::Tuple => doctree::Newtype, |
201 | [..] if variant.kind == ty::VariantKind::Tuple => doctree::Tuple, | |
1a4d82fc JJ |
202 | _ => doctree::Plain, |
203 | }, | |
85aaf69f | 204 | generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx), |
e9174d1e | 205 | fields: variant.fields.clean(cx), |
1a4d82fc JJ |
206 | fields_stripped: false, |
207 | } | |
208 | } | |
209 | ||
54a0048b | 210 | fn build_type(cx: &DocContext, tcx: &TyCtxt, did: DefId) -> clean::ItemEnum { |
c1a9b12d SL |
211 | let t = tcx.lookup_item_type(did); |
212 | let predicates = tcx.lookup_predicates(did); | |
1a4d82fc | 213 | match t.ty.sty { |
92a42be0 | 214 | ty::TyEnum(edef, _) if !tcx.sess.cstore.is_typedef(did) => { |
1a4d82fc | 215 | return clean::EnumItem(clean::Enum { |
85aaf69f | 216 | generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx), |
1a4d82fc | 217 | variants_stripped: false, |
e9174d1e | 218 | variants: edef.variants.clean(cx), |
1a4d82fc JJ |
219 | }) |
220 | } | |
221 | _ => {} | |
222 | } | |
223 | ||
224 | clean::TypedefItem(clean::Typedef { | |
225 | type_: t.ty.clean(cx), | |
85aaf69f | 226 | generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx), |
62682a34 | 227 | }, false) |
1a4d82fc JJ |
228 | } |
229 | ||
54a0048b SL |
230 | pub fn build_impls(cx: &DocContext, |
231 | tcx: &TyCtxt, | |
e9174d1e | 232 | did: DefId) -> Vec<clean::Item> { |
c1a9b12d | 233 | tcx.populate_inherent_implementations_for_type_if_necessary(did); |
1a4d82fc JJ |
234 | let mut impls = Vec::new(); |
235 | ||
54a0048b SL |
236 | if let Some(i) = tcx.inherent_impls.borrow().get(&did) { |
237 | for &did in i.iter() { | |
238 | build_impl(cx, tcx, did, &mut impls); | |
1a4d82fc JJ |
239 | } |
240 | } | |
241 | ||
242 | // If this is the first time we've inlined something from this crate, then | |
243 | // we inline *all* impls from the crate into this crate. Note that there's | |
244 | // currently no way for us to filter this based on type, and we likely need | |
245 | // many impls for a variety of reasons. | |
246 | // | |
247 | // Primarily, the impls will be used to populate the documentation for this | |
248 | // type being inlined, but impls can also be used when generating | |
249 | // documentation for primitives (no way to find those specifically). | |
54a0048b SL |
250 | if !cx.all_crate_impls.borrow_mut().contains_key(&did.krate) { |
251 | let mut impls = Vec::new(); | |
92a42be0 SL |
252 | for item in tcx.sess.cstore.crate_top_level_items(did.krate) { |
253 | populate_impls(cx, tcx, item.def, &mut impls); | |
254 | } | |
54a0048b | 255 | cx.all_crate_impls.borrow_mut().insert(did.krate, impls); |
1a4d82fc | 256 | |
54a0048b | 257 | fn populate_impls(cx: &DocContext, tcx: &TyCtxt, |
92a42be0 | 258 | def: cstore::DefLike, |
d9579d0f | 259 | impls: &mut Vec<clean::Item>) { |
1a4d82fc | 260 | match def { |
92a42be0 | 261 | cstore::DlImpl(did) => build_impl(cx, tcx, did, impls), |
7453a54e SL |
262 | cstore::DlDef(Def::Mod(did)) => { |
263 | // Don't recurse if this is a #[doc(hidden)] module | |
54a0048b | 264 | if load_attrs(cx, tcx, did).list("doc").has_word("hidden") { |
7453a54e SL |
265 | return; |
266 | } | |
267 | ||
92a42be0 SL |
268 | for item in tcx.sess.cstore.item_children(did) { |
269 | populate_impls(cx, tcx, item.def, impls) | |
270 | } | |
1a4d82fc JJ |
271 | } |
272 | _ => {} | |
273 | } | |
274 | } | |
275 | } | |
276 | ||
54a0048b SL |
277 | let mut candidates = cx.all_crate_impls.borrow_mut(); |
278 | let candidates = candidates.get_mut(&did.krate).unwrap(); | |
279 | for i in (0..candidates.len()).rev() { | |
280 | let remove = match candidates[i].inner { | |
281 | clean::ImplItem(ref i) => { | |
282 | i.for_.def_id() == Some(did) || i.for_.primitive_type().is_some() | |
283 | } | |
284 | _ => continue, | |
285 | }; | |
286 | if remove { | |
287 | impls.push(candidates.swap_remove(i)); | |
288 | } | |
289 | } | |
290 | ||
d9579d0f | 291 | return impls; |
1a4d82fc JJ |
292 | } |
293 | ||
d9579d0f | 294 | pub fn build_impl(cx: &DocContext, |
54a0048b | 295 | tcx: &TyCtxt, |
e9174d1e | 296 | did: DefId, |
d9579d0f | 297 | ret: &mut Vec<clean::Item>) { |
1a4d82fc | 298 | if !cx.inlined.borrow_mut().as_mut().unwrap().insert(did) { |
d9579d0f | 299 | return |
1a4d82fc JJ |
300 | } |
301 | ||
c34b1796 | 302 | let attrs = load_attrs(cx, tcx, did); |
92a42be0 | 303 | let associated_trait = tcx.impl_trait_ref(did); |
c34b1796 AL |
304 | if let Some(ref t) = associated_trait { |
305 | // If this is an impl for a #[doc(hidden)] trait, be sure to not inline | |
306 | let trait_attrs = load_attrs(cx, tcx, t.def_id); | |
54a0048b | 307 | if trait_attrs.list("doc").has_word("hidden") { |
d9579d0f | 308 | return |
1a4d82fc | 309 | } |
1a4d82fc JJ |
310 | } |
311 | ||
c34b1796 | 312 | // If this is a defaulted impl, then bail out early here |
92a42be0 | 313 | if tcx.sess.cstore.is_default_impl(did) { |
d9579d0f | 314 | return ret.push(clean::Item { |
c34b1796 AL |
315 | inner: clean::DefaultImplItem(clean::DefaultImpl { |
316 | // FIXME: this should be decoded | |
e9174d1e | 317 | unsafety: hir::Unsafety::Normal, |
c34b1796 AL |
318 | trait_: match associated_trait.as_ref().unwrap().clean(cx) { |
319 | clean::TraitBound(polyt, _) => polyt.trait_, | |
320 | clean::RegionBound(..) => unreachable!(), | |
321 | }, | |
322 | }), | |
323 | source: clean::Span::empty(), | |
324 | name: None, | |
325 | attrs: attrs, | |
e9174d1e | 326 | visibility: Some(hir::Inherited), |
9cc50fc6 SL |
327 | stability: stability::lookup_stability(tcx, did).clean(cx), |
328 | deprecation: stability::lookup_deprecation(tcx, did).clean(cx), | |
c34b1796 AL |
329 | def_id: did, |
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 { |
54a0048b SL |
344 | Some(lookup_const_by_id(tcx, did, None) |
345 | .unwrap().0.span.to_src(cx)) | |
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, | |
9cc50fc6 SL |
358 | stability: stability::lookup_stability(tcx, did).clean(cx), |
359 | deprecation: stability::lookup_deprecation(tcx, 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 { | |
85aaf69f | 370 | unsafety, decl, self_, 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 JJ |
381 | decl: decl, |
382 | self_: self_, | |
383 | generics: generics, | |
85aaf69f | 384 | abi: abi |
1a4d82fc JJ |
385 | }) |
386 | } | |
387 | _ => panic!("not a tymethod"), | |
388 | }; | |
389 | Some(item) | |
390 | } | |
85aaf69f SL |
391 | ty::TypeTraitItem(ref assoc_ty) => { |
392 | let did = assoc_ty.def_id; | |
62682a34 SL |
393 | let type_scheme = ty::TypeScheme { |
394 | ty: assoc_ty.ty.unwrap(), | |
395 | generics: ty::Generics::empty() | |
396 | }; | |
9346a6ac AL |
397 | // Not sure the choice of ParamSpace actually matters here, |
398 | // because an associated type won't have generics on the LHS | |
62682a34 | 399 | let typedef = (type_scheme, ty::GenericPredicates::empty(), |
9346a6ac | 400 | subst::ParamSpace::TypeSpace).clean(cx); |
85aaf69f SL |
401 | Some(clean::Item { |
402 | name: Some(assoc_ty.name.clean(cx)), | |
62682a34 | 403 | inner: clean::TypedefItem(typedef, true), |
85aaf69f SL |
404 | source: clean::Span::empty(), |
405 | attrs: vec![], | |
406 | visibility: None, | |
9cc50fc6 SL |
407 | stability: stability::lookup_stability(tcx, did).clean(cx), |
408 | deprecation: stability::lookup_deprecation(tcx, did).clean(cx), | |
85aaf69f SL |
409 | def_id: did |
410 | }) | |
1a4d82fc JJ |
411 | } |
412 | } | |
d9579d0f | 413 | }).collect::<Vec<_>>(); |
92a42be0 | 414 | let polarity = tcx.trait_impl_polarity(did); |
c1a9b12d | 415 | let ty = tcx.lookup_item_type(did); |
d9579d0f AL |
416 | let trait_ = associated_trait.clean(cx).map(|bound| { |
417 | match bound { | |
418 | clean::TraitBound(polyt, _) => polyt.trait_, | |
419 | clean::RegionBound(..) => unreachable!(), | |
420 | } | |
421 | }); | |
54a0048b SL |
422 | if trait_.def_id() == cx.deref_trait_did.get() { |
423 | super::build_deref_target_impls(cx, &trait_items, ret); | |
d9579d0f | 424 | } |
54a0048b SL |
425 | |
426 | let provided = trait_.def_id().map(|did| { | |
427 | cx.tcx().provided_trait_methods(did) | |
428 | .into_iter() | |
429 | .map(|meth| meth.name.to_string()) | |
430 | .collect() | |
431 | }).unwrap_or(HashSet::new()); | |
432 | ||
d9579d0f | 433 | ret.push(clean::Item { |
1a4d82fc | 434 | inner: clean::ImplItem(clean::Impl { |
e9174d1e | 435 | unsafety: hir::Unsafety::Normal, // FIXME: this should be decoded |
85aaf69f | 436 | derived: clean::detect_derived(&attrs), |
54a0048b | 437 | provided_trait_methods: provided, |
d9579d0f | 438 | trait_: trait_, |
1a4d82fc | 439 | for_: ty.ty.clean(cx), |
85aaf69f | 440 | generics: (&ty.generics, &predicates, subst::TypeSpace).clean(cx), |
1a4d82fc | 441 | items: trait_items, |
85aaf69f | 442 | polarity: polarity.map(|p| { p.clean(cx) }), |
1a4d82fc JJ |
443 | }), |
444 | source: clean::Span::empty(), | |
445 | name: None, | |
446 | attrs: attrs, | |
e9174d1e | 447 | visibility: Some(hir::Inherited), |
9cc50fc6 SL |
448 | stability: stability::lookup_stability(tcx, did).clean(cx), |
449 | deprecation: stability::lookup_deprecation(tcx, did).clean(cx), | |
1a4d82fc JJ |
450 | def_id: did, |
451 | }); | |
7453a54e | 452 | } |
1a4d82fc | 453 | |
54a0048b | 454 | fn build_module(cx: &DocContext, tcx: &TyCtxt, |
e9174d1e | 455 | did: DefId) -> clean::Module { |
1a4d82fc JJ |
456 | let mut items = Vec::new(); |
457 | fill_in(cx, tcx, did, &mut items); | |
458 | return clean::Module { | |
459 | items: items, | |
460 | is_crate: false, | |
461 | }; | |
462 | ||
54a0048b | 463 | fn fill_in(cx: &DocContext, tcx: &TyCtxt, did: DefId, |
1a4d82fc | 464 | items: &mut Vec<clean::Item>) { |
9346a6ac AL |
465 | // If we're reexporting a reexport it may actually reexport something in |
466 | // two namespaces, so the target may be listed twice. Make sure we only | |
467 | // visit each node at most once. | |
468 | let mut visited = HashSet::new(); | |
92a42be0 SL |
469 | for item in tcx.sess.cstore.item_children(did) { |
470 | match item.def { | |
7453a54e | 471 | cstore::DlDef(Def::ForeignMod(did)) => { |
1a4d82fc JJ |
472 | fill_in(cx, tcx, did, items); |
473 | } | |
54a0048b | 474 | cstore::DlDef(def) if item.vis == ty::Visibility::Public => { |
92a42be0 | 475 | if !visited.insert(def) { continue } |
54a0048b SL |
476 | if let Some(i) = try_inline_def(cx, tcx, def) { |
477 | items.extend(i) | |
1a4d82fc JJ |
478 | } |
479 | } | |
92a42be0 | 480 | cstore::DlDef(..) => {} |
1a4d82fc | 481 | // All impls were inlined above |
92a42be0 SL |
482 | cstore::DlImpl(..) => {} |
483 | cstore::DlField => panic!("unimplemented field"), | |
1a4d82fc | 484 | } |
92a42be0 | 485 | } |
1a4d82fc JJ |
486 | } |
487 | } | |
488 | ||
54a0048b | 489 | fn build_const(cx: &DocContext, tcx: &TyCtxt, |
e9174d1e | 490 | did: DefId) -> clean::Constant { |
54a0048b | 491 | use rustc::hir::print as pprust; |
1a4d82fc | 492 | |
54a0048b | 493 | let (expr, ty) = lookup_const_by_id(tcx, did, None).unwrap_or_else(|| { |
1a4d82fc JJ |
494 | panic!("expected lookup_const_by_id to succeed for {:?}", did); |
495 | }); | |
496 | debug!("converting constant expr {:?} to snippet", expr); | |
497 | let sn = pprust::expr_to_string(expr); | |
498 | debug!("got snippet {}", sn); | |
499 | ||
500 | clean::Constant { | |
54a0048b | 501 | type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| tcx.lookup_item_type(did).ty.clean(cx)), |
1a4d82fc JJ |
502 | expr: sn |
503 | } | |
504 | } | |
505 | ||
54a0048b | 506 | fn build_static(cx: &DocContext, tcx: &TyCtxt, |
e9174d1e | 507 | did: DefId, |
1a4d82fc JJ |
508 | mutable: bool) -> clean::Static { |
509 | clean::Static { | |
c1a9b12d | 510 | type_: tcx.lookup_item_type(did).ty.clean(cx), |
1a4d82fc JJ |
511 | mutability: if mutable {clean::Mutable} else {clean::Immutable}, |
512 | expr: "\n\n\n".to_string(), // trigger the "[definition]" links | |
513 | } | |
514 | } | |
9346a6ac AL |
515 | |
516 | /// A trait's generics clause actually contains all of the predicates for all of | |
517 | /// its associated types as well. We specifically move these clauses to the | |
518 | /// associated types instead when displaying, so when we're genering the | |
519 | /// generics for the trait itself we need to be sure to remove them. | |
520 | /// | |
521 | /// The inverse of this filtering logic can be found in the `Clean` | |
522 | /// implementation for `AssociatedType` | |
e9174d1e | 523 | fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) |
9346a6ac AL |
524 | -> clean::Generics { |
525 | g.where_predicates.retain(|pred| { | |
526 | match *pred { | |
527 | clean::WherePredicate::BoundPredicate { | |
528 | ty: clean::QPath { | |
529 | self_type: box clean::Generic(ref s), | |
530 | trait_: box clean::ResolvedPath { did, .. }, | |
531 | name: ref _name, | |
532 | }, .. | |
533 | } => *s != "Self" || did != trait_did, | |
534 | _ => true, | |
535 | } | |
536 | }); | |
537 | return g; | |
538 | } | |
539 | ||
540 | /// Supertrait bounds for a trait are also listed in the generics coming from | |
541 | /// the metadata for a crate, so we want to separate those out and create a new | |
542 | /// list of explicit supertrait bounds to render nicely. | |
543 | fn separate_supertrait_bounds(mut g: clean::Generics) | |
544 | -> (clean::Generics, Vec<clean::TyParamBound>) { | |
545 | let mut ty_bounds = Vec::new(); | |
546 | g.where_predicates.retain(|pred| { | |
547 | match *pred { | |
548 | clean::WherePredicate::BoundPredicate { | |
549 | ty: clean::Generic(ref s), | |
550 | ref bounds | |
551 | } if *s == "Self" => { | |
552 | ty_bounds.extend(bounds.iter().cloned()); | |
553 | false | |
554 | } | |
555 | _ => true, | |
556 | } | |
557 | }); | |
558 | (g, ty_bounds) | |
559 | } |