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