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