]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //! Support for inlining external documentation into the current AST. |
2 | ||
54a0048b | 3 | use std::iter::once; |
9346a6ac | 4 | |
74b04a01 | 5 | use rustc_ast::ast; |
dfeec247 XL |
6 | use rustc_data_structures::fx::FxHashSet; |
7 | use rustc_hir as hir; | |
8 | use rustc_hir::def::{CtorKind, DefKind, Res}; | |
f9f354fc | 9 | use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; |
dfeec247 XL |
10 | use rustc_hir::Mutability; |
11 | use rustc_metadata::creader::LoadedMacro; | |
ba9703b0 | 12 | use rustc_middle::ty; |
dfeec247 XL |
13 | use rustc_mir::const_eval::is_min_const_fn; |
14 | use rustc_span::hygiene::MacroKind; | |
f9f354fc | 15 | use rustc_span::symbol::Symbol; |
dfeec247 | 16 | use rustc_span::Span; |
54a0048b | 17 | |
dfeec247 | 18 | use crate::clean::{self, GetDefId, ToSource, TypeKind}; |
416331ca | 19 | use crate::core::DocContext; |
9fa01778 | 20 | use crate::doctree; |
1a4d82fc | 21 | |
a7813a04 | 22 | use super::Clean; |
1a4d82fc | 23 | |
ba9703b0 | 24 | type Attrs<'hir> = rustc_middle::ty::Attributes<'hir>; |
416331ca | 25 | |
476ff2be | 26 | /// Attempt to inline a definition into this AST. |
1a4d82fc | 27 | /// |
476ff2be SL |
28 | /// This function will fetch the definition specified, and if it is |
29 | /// from another crate it will attempt to inline the documentation | |
30 | /// from the other crate into this crate. | |
1a4d82fc JJ |
31 | /// |
32 | /// This is primarily used for `pub use` statements which are, in general, | |
33 | /// implementation details. Inlining the documentation should help provide a | |
34 | /// better experience when reading the documentation in this use case. | |
35 | /// | |
476ff2be SL |
36 | /// The returned value is `None` if the definition could not be inlined, |
37 | /// and `Some` of a vector of items if it was successfully expanded. | |
9fa01778 | 38 | pub fn try_inline( |
532ac7d7 | 39 | cx: &DocContext<'_>, |
48663c56 | 40 | res: Res, |
f9f354fc | 41 | name: Symbol, |
416331ca | 42 | attrs: Option<Attrs<'_>>, |
dfeec247 | 43 | visited: &mut FxHashSet<DefId>, |
48663c56 | 44 | ) -> Option<Vec<clean::Item>> { |
ba9703b0 | 45 | let did = res.opt_def_id()?; |
dfeec247 XL |
46 | if did.is_local() { |
47 | return None; | |
48 | } | |
1a4d82fc | 49 | let mut ret = Vec::new(); |
416331ca | 50 | |
ba9703b0 | 51 | let attrs_clone = attrs; |
416331ca | 52 | |
48663c56 XL |
53 | let inner = match res { |
54 | Res::Def(DefKind::Trait, did) => { | |
c30ab7b3 | 55 | record_extern_fqn(cx, did, clean::TypeKind::Trait); |
416331ca | 56 | ret.extend(build_impls(cx, did, attrs)); |
476ff2be | 57 | clean::TraitItem(build_external_trait(cx, did)) |
1a4d82fc | 58 | } |
48663c56 | 59 | Res::Def(DefKind::Fn, did) => { |
c30ab7b3 | 60 | record_extern_fqn(cx, did, clean::TypeKind::Function); |
476ff2be | 61 | clean::FunctionItem(build_external_function(cx, did)) |
1a4d82fc | 62 | } |
48663c56 | 63 | Res::Def(DefKind::Struct, did) => { |
c30ab7b3 | 64 | record_extern_fqn(cx, did, clean::TypeKind::Struct); |
416331ca | 65 | ret.extend(build_impls(cx, did, attrs)); |
476ff2be | 66 | clean::StructItem(build_struct(cx, did)) |
1a4d82fc | 67 | } |
48663c56 | 68 | Res::Def(DefKind::Union, did) => { |
c30ab7b3 | 69 | record_extern_fqn(cx, did, clean::TypeKind::Union); |
416331ca | 70 | ret.extend(build_impls(cx, did, attrs)); |
476ff2be | 71 | clean::UnionItem(build_union(cx, did)) |
9e0c209e | 72 | } |
48663c56 | 73 | Res::Def(DefKind::TyAlias, did) => { |
c30ab7b3 | 74 | record_extern_fqn(cx, did, clean::TypeKind::Typedef); |
416331ca | 75 | ret.extend(build_impls(cx, did, attrs)); |
476ff2be | 76 | clean::TypedefItem(build_type_alias(cx, did), false) |
1a4d82fc | 77 | } |
48663c56 | 78 | Res::Def(DefKind::Enum, did) => { |
c30ab7b3 | 79 | record_extern_fqn(cx, did, clean::TypeKind::Enum); |
416331ca | 80 | ret.extend(build_impls(cx, did, attrs)); |
476ff2be | 81 | clean::EnumItem(build_enum(cx, did)) |
1a4d82fc | 82 | } |
48663c56 | 83 | Res::Def(DefKind::ForeignTy, did) => { |
abe05a73 | 84 | record_extern_fqn(cx, did, clean::TypeKind::Foreign); |
416331ca | 85 | ret.extend(build_impls(cx, did, attrs)); |
abe05a73 XL |
86 | clean::ForeignTypeItem |
87 | } | |
2c00a5a8 | 88 | // Never inline enum variants but leave them shown as re-exports. |
48663c56 | 89 | Res::Def(DefKind::Variant, _) => return None, |
2c00a5a8 | 90 | // Assume that enum variants and struct types are re-exported next to |
041b39d2 | 91 | // their constructors. |
48663c56 XL |
92 | Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => return Some(Vec::new()), |
93 | Res::Def(DefKind::Mod, did) => { | |
c30ab7b3 | 94 | record_extern_fqn(cx, did, clean::TypeKind::Module); |
83c7162d | 95 | clean::ModuleItem(build_module(cx, did, visited)) |
1a4d82fc | 96 | } |
48663c56 | 97 | Res::Def(DefKind::Static, did) => { |
c30ab7b3 | 98 | record_extern_fqn(cx, did, clean::TypeKind::Static); |
48663c56 | 99 | clean::StaticItem(build_static(cx, did, cx.tcx.is_mutable_static(did))) |
1a4d82fc | 100 | } |
48663c56 | 101 | Res::Def(DefKind::Const, did) => { |
c30ab7b3 | 102 | record_extern_fqn(cx, did, clean::TypeKind::Const); |
476ff2be | 103 | clean::ConstantItem(build_const(cx, did)) |
1a4d82fc | 104 | } |
e1599b0c | 105 | Res::Def(DefKind::Macro(kind), did) => { |
0bf4aa26 | 106 | let mac = build_macro(cx, did, name); |
e1599b0c XL |
107 | |
108 | let type_kind = match kind { | |
109 | MacroKind::Bang => TypeKind::Macro, | |
110 | MacroKind::Attr => TypeKind::Attr, | |
dfeec247 | 111 | MacroKind::Derive => TypeKind::Derive, |
e1599b0c XL |
112 | }; |
113 | record_extern_fqn(cx, did, type_kind); | |
114 | mac | |
8faf50e0 | 115 | } |
1a4d82fc JJ |
116 | _ => return None, |
117 | }; | |
416331ca XL |
118 | |
119 | let target_attrs = load_attrs(cx, did); | |
dfeec247 | 120 | let attrs = merge_attrs(cx, target_attrs, attrs_clone); |
416331ca | 121 | |
a7813a04 | 122 | cx.renderinfo.borrow_mut().inlined.insert(did); |
1a4d82fc | 123 | ret.push(clean::Item { |
7cac9316 XL |
124 | source: cx.tcx.def_span(did).clean(cx), |
125 | name: Some(name.clean(cx)), | |
416331ca | 126 | attrs, |
3b2f2976 | 127 | inner, |
e74abb32 | 128 | visibility: clean::Public, |
7cac9316 XL |
129 | stability: cx.tcx.lookup_stability(did).clean(cx), |
130 | deprecation: cx.tcx.lookup_deprecation(did).clean(cx), | |
1a4d82fc JJ |
131 | def_id: did, |
132 | }); | |
133 | Some(ret) | |
134 | } | |
135 | ||
dfeec247 XL |
136 | pub fn try_inline_glob( |
137 | cx: &DocContext<'_>, | |
138 | res: Res, | |
139 | visited: &mut FxHashSet<DefId>, | |
140 | ) -> Option<Vec<clean::Item>> { | |
141 | if res == Res::Err { | |
142 | return None; | |
143 | } | |
48663c56 | 144 | let did = res.def_id(); |
dfeec247 XL |
145 | if did.is_local() { |
146 | return None; | |
147 | } | |
94b46f34 | 148 | |
48663c56 XL |
149 | match res { |
150 | Res::Def(DefKind::Mod, did) => { | |
94b46f34 XL |
151 | let m = build_module(cx, did, visited); |
152 | Some(m.items) | |
153 | } | |
154 | // glob imports on things like enums aren't inlined even for local exports, so just bail | |
155 | _ => None, | |
156 | } | |
157 | } | |
158 | ||
416331ca XL |
159 | pub fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> Attrs<'hir> { |
160 | cx.tcx.get_attrs(did) | |
1a4d82fc JJ |
161 | } |
162 | ||
163 | /// Record an external fully qualified name in the external_paths cache. | |
164 | /// | |
165 | /// These names are used later on by HTML rendering to generate things like | |
166 | /// source links back to the original item. | |
532ac7d7 | 167 | pub fn record_extern_fqn(cx: &DocContext<'_>, did: DefId, kind: clean::TypeKind) { |
416331ca | 168 | let crate_name = cx.tcx.crate_name(did.krate).to_string(); |
0531ce1d | 169 | |
476ff2be SL |
170 | let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| { |
171 | // extern blocks have an empty name | |
172 | let s = elem.data.to_string(); | |
dfeec247 | 173 | if !s.is_empty() { Some(s) } else { None } |
476ff2be | 174 | }); |
2c00a5a8 | 175 | let fqn = if let clean::TypeKind::Macro = kind { |
b7449926 | 176 | vec![crate_name, relative.last().expect("relative was empty")] |
2c00a5a8 XL |
177 | } else { |
178 | once(crate_name).chain(relative).collect() | |
179 | }; | |
0bf4aa26 XL |
180 | |
181 | if did.is_local() { | |
182 | cx.renderinfo.borrow_mut().exact_paths.insert(did, fqn); | |
183 | } else { | |
184 | cx.renderinfo.borrow_mut().external_paths.insert(did, (fqn, kind)); | |
185 | } | |
1a4d82fc JJ |
186 | } |
187 | ||
532ac7d7 | 188 | pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait { |
74b04a01 XL |
189 | let trait_items = |
190 | cx.tcx.associated_items(did).in_definition_order().map(|item| item.clean(cx)).collect(); | |
191 | ||
0531ce1d | 192 | let auto_trait = cx.tcx.trait_def(did).has_auto_impl; |
7cac9316 | 193 | let predicates = cx.tcx.predicates_of(did); |
e74abb32 | 194 | let generics = (cx.tcx.generics_of(did), predicates).clean(cx); |
9346a6ac AL |
195 | let generics = filter_non_trait_generics(did, generics); |
196 | let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); | |
2c00a5a8 | 197 | let is_auto = cx.tcx.trait_is_auto(did); |
1a4d82fc | 198 | clean::Trait { |
0531ce1d | 199 | auto: auto_trait, |
7cac9316 | 200 | unsafety: cx.tcx.trait_def(did).unsafety, |
3b2f2976 | 201 | generics, |
c34b1796 | 202 | items: trait_items, |
9346a6ac | 203 | bounds: supertrait_bounds, |
2c00a5a8 | 204 | is_auto, |
1a4d82fc JJ |
205 | } |
206 | } | |
207 | ||
532ac7d7 | 208 | fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function { |
041b39d2 | 209 | let sig = cx.tcx.fn_sig(did); |
92a42be0 | 210 | |
dfeec247 XL |
211 | let constness = |
212 | if is_min_const_fn(cx.tcx, did) { hir::Constness::Const } else { hir::Constness::NotConst }; | |
213 | let asyncness = cx.tcx.asyncness(did); | |
7cac9316 | 214 | let predicates = cx.tcx.predicates_of(did); |
e1599b0c | 215 | let (generics, decl) = clean::enter_impl_trait(cx, || { |
e74abb32 | 216 | ((cx.tcx.generics_of(did), predicates).clean(cx), (did, sig).clean(cx)) |
e1599b0c | 217 | }); |
532ac7d7 | 218 | let (all_types, ret_types) = clean::get_all_types(&generics, &decl, cx); |
1a4d82fc | 219 | clean::Function { |
532ac7d7 XL |
220 | decl, |
221 | generics, | |
dfeec247 | 222 | header: hir::FnHeader { unsafety: sig.unsafety(), abi: sig.abi(), constness, asyncness }, |
532ac7d7 XL |
223 | all_types, |
224 | ret_types, | |
1a4d82fc JJ |
225 | } |
226 | } | |
227 | ||
532ac7d7 XL |
228 | fn build_enum(cx: &DocContext<'_>, did: DefId) -> clean::Enum { |
229 | let predicates = cx.tcx.explicit_predicates_of(did); | |
9e0c209e SL |
230 | |
231 | clean::Enum { | |
e74abb32 | 232 | generics: (cx.tcx.generics_of(did), predicates).clean(cx), |
9e0c209e | 233 | variants_stripped: false, |
7cac9316 | 234 | variants: cx.tcx.adt_def(did).variants.clean(cx), |
9e0c209e SL |
235 | } |
236 | } | |
237 | ||
532ac7d7 XL |
238 | fn build_struct(cx: &DocContext<'_>, did: DefId) -> clean::Struct { |
239 | let predicates = cx.tcx.explicit_predicates_of(did); | |
2c00a5a8 | 240 | let variant = cx.tcx.adt_def(did).non_enum_variant(); |
1a4d82fc JJ |
241 | |
242 | clean::Struct { | |
c30ab7b3 SL |
243 | struct_type: match variant.ctor_kind { |
244 | CtorKind::Fictive => doctree::Plain, | |
245 | CtorKind::Fn => doctree::Tuple, | |
246 | CtorKind::Const => doctree::Unit, | |
1a4d82fc | 247 | }, |
e74abb32 | 248 | generics: (cx.tcx.generics_of(did), predicates).clean(cx), |
e9174d1e | 249 | fields: variant.fields.clean(cx), |
1a4d82fc JJ |
250 | fields_stripped: false, |
251 | } | |
252 | } | |
253 | ||
532ac7d7 XL |
254 | fn build_union(cx: &DocContext<'_>, did: DefId) -> clean::Union { |
255 | let predicates = cx.tcx.explicit_predicates_of(did); | |
2c00a5a8 | 256 | let variant = cx.tcx.adt_def(did).non_enum_variant(); |
9e0c209e SL |
257 | |
258 | clean::Union { | |
259 | struct_type: doctree::Plain, | |
e74abb32 | 260 | generics: (cx.tcx.generics_of(did), predicates).clean(cx), |
9e0c209e SL |
261 | fields: variant.fields.clean(cx), |
262 | fields_stripped: false, | |
1a4d82fc | 263 | } |
9e0c209e SL |
264 | } |
265 | ||
532ac7d7 XL |
266 | fn build_type_alias(cx: &DocContext<'_>, did: DefId) -> clean::Typedef { |
267 | let predicates = cx.tcx.explicit_predicates_of(did); | |
1a4d82fc | 268 | |
9e0c209e | 269 | clean::Typedef { |
7cac9316 | 270 | type_: cx.tcx.type_of(did).clean(cx), |
e74abb32 | 271 | generics: (cx.tcx.generics_of(did), predicates).clean(cx), |
dfeec247 XL |
272 | item_type: build_type_alias_type(cx, did), |
273 | } | |
274 | } | |
275 | ||
276 | fn build_type_alias_type(cx: &DocContext<'_>, did: DefId) -> Option<clean::Type> { | |
277 | let type_ = cx.tcx.type_of(did).clean(cx); | |
278 | type_.def_id().and_then(|did| build_ty(cx, did)) | |
279 | } | |
280 | ||
281 | pub fn build_ty(cx: &DocContext, did: DefId) -> Option<clean::Type> { | |
f9f354fc | 282 | match cx.tcx.def_kind(did) { |
dfeec247 XL |
283 | DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::Const | DefKind::Static => { |
284 | Some(cx.tcx.type_of(did).clean(cx)) | |
285 | } | |
286 | DefKind::TyAlias => build_type_alias_type(cx, did), | |
287 | _ => None, | |
9e0c209e | 288 | } |
1a4d82fc JJ |
289 | } |
290 | ||
416331ca | 291 | pub fn build_impls(cx: &DocContext<'_>, did: DefId, attrs: Option<Attrs<'_>>) -> Vec<clean::Item> { |
476ff2be | 292 | let tcx = cx.tcx; |
1a4d82fc JJ |
293 | let mut impls = Vec::new(); |
294 | ||
7cac9316 | 295 | for &did in tcx.inherent_impls(did).iter() { |
ba9703b0 | 296 | build_impl(cx, did, attrs, &mut impls); |
1a4d82fc | 297 | } |
cc61c64b | 298 | |
a7813a04 | 299 | impls |
1a4d82fc JJ |
300 | } |
301 | ||
dfeec247 XL |
302 | fn merge_attrs( |
303 | cx: &DocContext<'_>, | |
304 | attrs: Attrs<'_>, | |
305 | other_attrs: Option<Attrs<'_>>, | |
416331ca XL |
306 | ) -> clean::Attributes { |
307 | let mut merged_attrs: Vec<ast::Attribute> = Vec::with_capacity(attrs.len()); | |
308 | // If we have additional attributes (from a re-export), | |
309 | // always insert them first. This ensure that re-export | |
310 | // doc comments show up before the original doc comments | |
311 | // when we render them. | |
312 | if let Some(a) = other_attrs { | |
313 | merged_attrs.extend(a.iter().cloned()); | |
314 | } | |
315 | merged_attrs.extend(attrs.to_vec()); | |
316 | merged_attrs.clean(cx) | |
317 | } | |
318 | ||
dfeec247 XL |
319 | pub fn build_impl( |
320 | cx: &DocContext<'_>, | |
321 | did: DefId, | |
322 | attrs: Option<Attrs<'_>>, | |
323 | ret: &mut Vec<clean::Item>, | |
416331ca | 324 | ) { |
a7813a04 | 325 | if !cx.renderinfo.borrow_mut().inlined.insert(did) { |
dfeec247 | 326 | return; |
1a4d82fc JJ |
327 | } |
328 | ||
416331ca XL |
329 | let attrs = merge_attrs(cx, load_attrs(cx, did), attrs); |
330 | ||
476ff2be | 331 | let tcx = cx.tcx; |
92a42be0 | 332 | let associated_trait = tcx.impl_trait_ref(did); |
a7813a04 XL |
333 | |
334 | // Only inline impl if the implemented trait is | |
335 | // reachable in rustdoc generated documentation | |
0bf4aa26 XL |
336 | if !did.is_local() { |
337 | if let Some(traitref) = associated_trait { | |
416331ca | 338 | if !cx.renderinfo.borrow().access_levels.is_public(traitref.def_id) { |
dfeec247 | 339 | return; |
0bf4aa26 | 340 | } |
1a4d82fc | 341 | } |
1a4d82fc JJ |
342 | } |
343 | ||
f9f354fc XL |
344 | let for_ = if let Some(did) = did.as_local() { |
345 | let hir_id = tcx.hir().as_local_hir_id(did); | |
e74abb32 | 346 | match tcx.hir().expect_item(hir_id).kind { |
dfeec247 | 347 | hir::ItemKind::Impl { self_ty, .. } => self_ty.clean(cx), |
0bf4aa26 XL |
348 | _ => panic!("did given to build_impl was not an impl"), |
349 | } | |
350 | } else { | |
351 | tcx.type_of(did).clean(cx) | |
352 | }; | |
a7813a04 XL |
353 | |
354 | // Only inline impl if the implementing type is | |
355 | // reachable in rustdoc generated documentation | |
0bf4aa26 XL |
356 | if !did.is_local() { |
357 | if let Some(did) = for_.def_id() { | |
416331ca | 358 | if !cx.renderinfo.borrow().access_levels.is_public(did) { |
dfeec247 | 359 | return; |
0bf4aa26 | 360 | } |
a7813a04 XL |
361 | } |
362 | } | |
363 | ||
532ac7d7 | 364 | let predicates = tcx.explicit_predicates_of(did); |
f9f354fc XL |
365 | let (trait_items, generics) = if let Some(did) = did.as_local() { |
366 | let hir_id = tcx.hir().as_local_hir_id(did); | |
e74abb32 | 367 | match tcx.hir().expect_item(hir_id).kind { |
dfeec247 XL |
368 | hir::ItemKind::Impl { ref generics, ref items, .. } => ( |
369 | items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::<Vec<_>>(), | |
370 | generics.clean(cx), | |
371 | ), | |
0bf4aa26 | 372 | _ => panic!("did given to build_impl was not an impl"), |
1a4d82fc | 373 | } |
0bf4aa26 XL |
374 | } else { |
375 | ( | |
dfeec247 | 376 | tcx.associated_items(did) |
74b04a01 | 377 | .in_definition_order() |
dfeec247 XL |
378 | .filter_map(|item| { |
379 | if associated_trait.is_some() || item.vis == ty::Visibility::Public { | |
380 | Some(item.clean(cx)) | |
381 | } else { | |
382 | None | |
383 | } | |
384 | }) | |
385 | .collect::<Vec<_>>(), | |
386 | clean::enter_impl_trait(cx, || (tcx.generics_of(did), predicates).clean(cx)), | |
0bf4aa26 XL |
387 | ) |
388 | }; | |
7cac9316 | 389 | let polarity = tcx.impl_polarity(did); |
dfeec247 XL |
390 | let trait_ = associated_trait.clean(cx).map(|bound| match bound { |
391 | clean::GenericBound::TraitBound(polyt, _) => polyt.trait_, | |
392 | clean::GenericBound::Outlives(..) => unreachable!(), | |
d9579d0f | 393 | }); |
ea8adc8c | 394 | if trait_.def_id() == tcx.lang_items().deref_trait() { |
54a0048b | 395 | super::build_deref_target_impls(cx, &trait_items, ret); |
d9579d0f | 396 | } |
2c00a5a8 XL |
397 | if let Some(trait_did) = trait_.def_id() { |
398 | record_extern_trait(cx, trait_did); | |
399 | } | |
54a0048b | 400 | |
dfeec247 XL |
401 | let provided = trait_ |
402 | .def_id() | |
74b04a01 | 403 | .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect()) |
dfeec247 | 404 | .unwrap_or_default(); |
0bf4aa26 XL |
405 | |
406 | debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id()); | |
54a0048b | 407 | |
d9579d0f | 408 | ret.push(clean::Item { |
1a4d82fc | 409 | inner: clean::ImplItem(clean::Impl { |
0531ce1d | 410 | unsafety: hir::Unsafety::Normal, |
0bf4aa26 | 411 | generics, |
54a0048b | 412 | provided_trait_methods: provided, |
3b2f2976 XL |
413 | trait_, |
414 | for_, | |
1a4d82fc | 415 | items: trait_items, |
9e0c209e | 416 | polarity: Some(polarity.clean(cx)), |
0531ce1d | 417 | synthetic: false, |
8faf50e0 | 418 | blanket_impl: None, |
1a4d82fc | 419 | }), |
476ff2be | 420 | source: tcx.def_span(did).clean(cx), |
1a4d82fc | 421 | name: None, |
3b2f2976 | 422 | attrs, |
e74abb32 | 423 | visibility: clean::Inherited, |
a7813a04 XL |
424 | stability: tcx.lookup_stability(did).clean(cx), |
425 | deprecation: tcx.lookup_deprecation(did).clean(cx), | |
1a4d82fc JJ |
426 | def_id: did, |
427 | }); | |
7453a54e | 428 | } |
1a4d82fc | 429 | |
dfeec247 | 430 | fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet<DefId>) -> clean::Module { |
1a4d82fc | 431 | let mut items = Vec::new(); |
83c7162d | 432 | fill_in(cx, did, &mut items, visited); |
dfeec247 XL |
433 | return clean::Module { items, is_crate: false }; |
434 | ||
435 | fn fill_in( | |
436 | cx: &DocContext<'_>, | |
437 | did: DefId, | |
438 | items: &mut Vec<clean::Item>, | |
439 | visited: &mut FxHashSet<DefId>, | |
440 | ) { | |
2c00a5a8 | 441 | // If we're re-exporting a re-export it may actually re-export something in |
9346a6ac AL |
442 | // two namespaces, so the target may be listed twice. Make sure we only |
443 | // visit each node at most once. | |
ea8adc8c | 444 | for &item in cx.tcx.item_children(did).iter() { |
ff7c6d11 | 445 | if item.vis == ty::Visibility::Public { |
74b04a01 XL |
446 | if let Some(def_id) = item.res.mod_def_id() { |
447 | if did == def_id || !visited.insert(def_id) { | |
448 | continue; | |
449 | } | |
dfeec247 | 450 | } |
74b04a01 XL |
451 | if let Res::PrimTy(p) = item.res { |
452 | // Primitive types can't be inlined so generate an import instead. | |
453 | items.push(clean::Item { | |
454 | name: None, | |
455 | attrs: clean::Attributes::default(), | |
456 | source: clean::Span::empty(), | |
f9f354fc | 457 | def_id: DefId::local(CRATE_DEF_INDEX), |
74b04a01 XL |
458 | visibility: clean::Public, |
459 | stability: None, | |
460 | deprecation: None, | |
461 | inner: clean::ImportItem(clean::Import::Simple( | |
462 | item.ident.to_string(), | |
463 | clean::ImportSource { | |
464 | path: clean::Path { | |
465 | global: false, | |
466 | res: item.res, | |
467 | segments: vec![clean::PathSegment { | |
468 | name: clean::PrimitiveType::from(p).as_str().to_string(), | |
469 | args: clean::GenericArgs::AngleBracketed { | |
470 | args: Vec::new(), | |
471 | bindings: Vec::new(), | |
472 | }, | |
473 | }], | |
474 | }, | |
475 | did: None, | |
476 | }, | |
477 | )), | |
478 | }); | |
479 | } else if let Some(i) = try_inline(cx, item.res, item.ident.name, None, visited) { | |
c30ab7b3 | 480 | items.extend(i) |
1a4d82fc | 481 | } |
1a4d82fc | 482 | } |
92a42be0 | 483 | } |
1a4d82fc JJ |
484 | } |
485 | } | |
486 | ||
532ac7d7 | 487 | pub fn print_inlined_const(cx: &DocContext<'_>, did: DefId) -> String { |
f9f354fc XL |
488 | if let Some(did) = did.as_local() { |
489 | let hir_id = cx.tcx.hir().as_local_hir_id(did); | |
ba9703b0 | 490 | rustc_hir_pretty::id_to_string(&cx.tcx.hir(), hir_id) |
0bf4aa26 XL |
491 | } else { |
492 | cx.tcx.rendered_const(did) | |
493 | } | |
32a655c1 SL |
494 | } |
495 | ||
532ac7d7 | 496 | fn build_const(cx: &DocContext<'_>, did: DefId) -> clean::Constant { |
1a4d82fc | 497 | clean::Constant { |
7cac9316 | 498 | type_: cx.tcx.type_of(did).clean(cx), |
dfeec247 XL |
499 | expr: print_inlined_const(cx, did), |
500 | value: clean::utils::print_evaluated_const(cx, did), | |
f9f354fc XL |
501 | is_literal: did.as_local().map_or(false, |did| { |
502 | clean::utils::is_literal_expr(cx, cx.tcx.hir().as_local_hir_id(did)) | |
503 | }), | |
1a4d82fc JJ |
504 | } |
505 | } | |
506 | ||
532ac7d7 | 507 | fn build_static(cx: &DocContext<'_>, did: DefId, mutable: bool) -> clean::Static { |
1a4d82fc | 508 | clean::Static { |
7cac9316 | 509 | type_: cx.tcx.type_of(did).clean(cx), |
dfeec247 | 510 | mutability: if mutable { Mutability::Mut } else { Mutability::Not }, |
1a4d82fc JJ |
511 | expr: "\n\n\n".to_string(), // trigger the "[definition]" links |
512 | } | |
513 | } | |
9346a6ac | 514 | |
f9f354fc | 515 | fn build_macro(cx: &DocContext<'_>, did: DefId, name: Symbol) -> clean::ItemEnum { |
8faf50e0 | 516 | let imported_from = cx.tcx.original_crate_name(did.krate); |
e74abb32 XL |
517 | match cx.enter_resolver(|r| r.cstore().load_macro_untracked(did, cx.sess())) { |
518 | LoadedMacro::MacroDef(def, _) => { | |
dfeec247 | 519 | let matchers: Vec<Span> = if let ast::ItemKind::MacroDef(ref def) = def.kind { |
60c5eb7d | 520 | let tts: Vec<_> = def.body.inner_tokens().into_trees().collect(); |
0bf4aa26 XL |
521 | tts.chunks(4).map(|arm| arm[0].span()).collect() |
522 | } else { | |
523 | unreachable!() | |
524 | }; | |
525 | ||
dfeec247 XL |
526 | let source = format!( |
527 | "macro_rules! {} {{\n{}}}", | |
528 | name.clean(cx), | |
529 | matchers | |
530 | .iter() | |
531 | .map(|span| { format!(" {} => {{ ... }};\n", span.to_src(cx)) }) | |
532 | .collect::<String>() | |
533 | ); | |
0bf4aa26 | 534 | |
dfeec247 | 535 | clean::MacroItem(clean::Macro { source, imported_from: Some(imported_from).clean(cx) }) |
0bf4aa26 | 536 | } |
dfeec247 XL |
537 | LoadedMacro::ProcMacro(ext) => clean::ProcMacroItem(clean::ProcMacro { |
538 | kind: ext.macro_kind(), | |
539 | helpers: ext.helper_attrs.clean(cx), | |
540 | }), | |
0bf4aa26 | 541 | } |
8faf50e0 XL |
542 | } |
543 | ||
9346a6ac AL |
544 | /// A trait's generics clause actually contains all of the predicates for all of |
545 | /// its associated types as well. We specifically move these clauses to the | |
3b2f2976 | 546 | /// associated types instead when displaying, so when we're generating the |
9346a6ac | 547 | /// generics for the trait itself we need to be sure to remove them. |
9e0c209e | 548 | /// We also need to remove the implied "recursive" Self: Trait bound. |
9346a6ac AL |
549 | /// |
550 | /// The inverse of this filtering logic can be found in the `Clean` | |
551 | /// implementation for `AssociatedType` | |
ff7c6d11 | 552 | fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics { |
9e0c209e SL |
553 | for pred in &mut g.where_predicates { |
554 | match *pred { | |
dfeec247 XL |
555 | clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref mut bounds } |
556 | if *s == "Self" => | |
557 | { | |
558 | bounds.retain(|bound| match *bound { | |
559 | clean::GenericBound::TraitBound( | |
560 | clean::PolyTrait { trait_: clean::ResolvedPath { did, .. }, .. }, | |
561 | _, | |
562 | ) => did != trait_did, | |
563 | _ => true, | |
9e0c209e SL |
564 | }); |
565 | } | |
566 | _ => {} | |
567 | } | |
568 | } | |
569 | ||
dfeec247 XL |
570 | g.where_predicates.retain(|pred| match *pred { |
571 | clean::WherePredicate::BoundPredicate { | |
572 | ty: | |
573 | clean::QPath { | |
9346a6ac AL |
574 | self_type: box clean::Generic(ref s), |
575 | trait_: box clean::ResolvedPath { did, .. }, | |
576 | name: ref _name, | |
dfeec247 XL |
577 | }, |
578 | ref bounds, | |
ba9703b0 | 579 | } => !(bounds.is_empty() || *s == "Self" && did == trait_did), |
dfeec247 | 580 | _ => true, |
9346a6ac | 581 | }); |
c30ab7b3 | 582 | g |
9346a6ac AL |
583 | } |
584 | ||
585 | /// Supertrait bounds for a trait are also listed in the generics coming from | |
586 | /// the metadata for a crate, so we want to separate those out and create a new | |
587 | /// list of explicit supertrait bounds to render nicely. | |
dfeec247 XL |
588 | fn separate_supertrait_bounds( |
589 | mut g: clean::Generics, | |
590 | ) -> (clean::Generics, Vec<clean::GenericBound>) { | |
9346a6ac | 591 | let mut ty_bounds = Vec::new(); |
dfeec247 XL |
592 | g.where_predicates.retain(|pred| match *pred { |
593 | clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref bounds } | |
594 | if *s == "Self" => | |
595 | { | |
596 | ty_bounds.extend(bounds.iter().cloned()); | |
597 | false | |
9346a6ac | 598 | } |
dfeec247 | 599 | _ => true, |
9346a6ac AL |
600 | }); |
601 | (g, ty_bounds) | |
602 | } | |
2c00a5a8 | 603 | |
532ac7d7 | 604 | pub fn record_extern_trait(cx: &DocContext<'_>, did: DefId) { |
0bf4aa26 | 605 | if did.is_local() { |
0531ce1d XL |
606 | return; |
607 | } | |
608 | ||
0bf4aa26 | 609 | { |
dfeec247 XL |
610 | if cx.external_traits.borrow().contains_key(&did) |
611 | || cx.active_extern_traits.borrow().contains(&did) | |
0bf4aa26 XL |
612 | { |
613 | return; | |
614 | } | |
615 | } | |
616 | ||
416331ca | 617 | cx.active_extern_traits.borrow_mut().insert(did); |
0531ce1d | 618 | |
0bf4aa26 | 619 | debug!("record_extern_trait: {:?}", did); |
0531ce1d XL |
620 | let trait_ = build_external_trait(cx, did); |
621 | ||
416331ca XL |
622 | cx.external_traits.borrow_mut().insert(did, trait_); |
623 | cx.active_extern_traits.borrow_mut().remove(&did); | |
2c00a5a8 | 624 | } |