1 //! Support for inlining external documentation into the current AST.
7 use rustc_data_structures
::fx
::FxHashSet
;
8 use rustc_data_structures
::thin_vec
::ThinVec
;
10 use rustc_hir
::def
::{DefKind, Res}
;
11 use rustc_hir
::def_id
::DefId
;
12 use rustc_hir
::Mutability
;
13 use rustc_metadata
::creader
::{CStore, LoadedMacro}
;
14 use rustc_middle
::ty
::{self, TyCtxt}
;
15 use rustc_span
::hygiene
::MacroKind
;
16 use rustc_span
::symbol
::{kw, sym, Symbol}
;
19 self, clean_fn_decl_from_did_and_sig
, clean_ty_generics
, utils
, Attributes
, AttributesExt
,
20 Clean
, ImplKind
, ItemId
, Type
, Visibility
,
22 use crate::core
::DocContext
;
23 use crate::formats
::item_type
::ItemType
;
25 type Attrs
<'hir
> = rustc_middle
::ty
::Attributes
<'hir
>;
27 /// Attempt to inline a definition into this AST.
29 /// This function will fetch the definition specified, and if it is
30 /// from another crate it will attempt to inline the documentation
31 /// from the other crate into this crate.
33 /// This is primarily used for `pub use` statements which are, in general,
34 /// implementation details. Inlining the documentation should help provide a
35 /// better experience when reading the documentation in this use case.
37 /// The returned value is `None` if the definition could not be inlined,
38 /// and `Some` of a vector of items if it was successfully expanded.
40 /// `parent_module` refers to the parent of the *re-export*, not the original item.
42 cx
: &mut DocContext
<'_
>,
44 import_def_id
: Option
<DefId
>,
47 attrs
: Option
<Attrs
<'_
>>,
48 visited
: &mut FxHashSet
<DefId
>,
49 ) -> Option
<Vec
<clean
::Item
>> {
50 let did
= res
.opt_def_id()?
;
54 let mut ret
= Vec
::new();
56 debug
!("attrs={:?}", attrs
);
57 let attrs_clone
= attrs
;
59 let kind
= match res
{
60 Res
::Def(DefKind
::Trait
, did
) => {
61 record_extern_fqn(cx
, did
, ItemType
::Trait
);
62 build_impls(cx
, Some(parent_module
), did
, attrs
, &mut ret
);
63 clean
::TraitItem(build_external_trait(cx
, did
))
65 Res
::Def(DefKind
::Fn
, did
) => {
66 record_extern_fqn(cx
, did
, ItemType
::Function
);
67 clean
::FunctionItem(build_external_function(cx
, did
))
69 Res
::Def(DefKind
::Struct
, did
) => {
70 record_extern_fqn(cx
, did
, ItemType
::Struct
);
71 build_impls(cx
, Some(parent_module
), did
, attrs
, &mut ret
);
72 clean
::StructItem(build_struct(cx
, did
))
74 Res
::Def(DefKind
::Union
, did
) => {
75 record_extern_fqn(cx
, did
, ItemType
::Union
);
76 build_impls(cx
, Some(parent_module
), did
, attrs
, &mut ret
);
77 clean
::UnionItem(build_union(cx
, did
))
79 Res
::Def(DefKind
::TyAlias
, did
) => {
80 record_extern_fqn(cx
, did
, ItemType
::Typedef
);
81 build_impls(cx
, Some(parent_module
), did
, attrs
, &mut ret
);
82 clean
::TypedefItem(build_type_alias(cx
, did
), false)
84 Res
::Def(DefKind
::Enum
, did
) => {
85 record_extern_fqn(cx
, did
, ItemType
::Enum
);
86 build_impls(cx
, Some(parent_module
), did
, attrs
, &mut ret
);
87 clean
::EnumItem(build_enum(cx
, did
))
89 Res
::Def(DefKind
::ForeignTy
, did
) => {
90 record_extern_fqn(cx
, did
, ItemType
::ForeignType
);
91 build_impls(cx
, Some(parent_module
), did
, attrs
, &mut ret
);
92 clean
::ForeignTypeItem
94 // Never inline enum variants but leave them shown as re-exports.
95 Res
::Def(DefKind
::Variant
, _
) => return None
,
96 // Assume that enum variants and struct types are re-exported next to
97 // their constructors.
98 Res
::Def(DefKind
::Ctor(..), _
) | Res
::SelfCtor(..) => return Some(Vec
::new()),
99 Res
::Def(DefKind
::Mod
, did
) => {
100 record_extern_fqn(cx
, did
, ItemType
::Module
);
101 clean
::ModuleItem(build_module(cx
, did
, visited
))
103 Res
::Def(DefKind
::Static(_
), did
) => {
104 record_extern_fqn(cx
, did
, ItemType
::Static
);
105 clean
::StaticItem(build_static(cx
, did
, cx
.tcx
.is_mutable_static(did
)))
107 Res
::Def(DefKind
::Const
, did
) => {
108 record_extern_fqn(cx
, did
, ItemType
::Constant
);
109 clean
::ConstantItem(build_const(cx
, did
))
111 Res
::Def(DefKind
::Macro(kind
), did
) => {
112 let mac
= build_macro(cx
, did
, name
, import_def_id
);
114 let type_kind
= match kind
{
115 MacroKind
::Bang
=> ItemType
::Macro
,
116 MacroKind
::Attr
=> ItemType
::ProcAttribute
,
117 MacroKind
::Derive
=> ItemType
::ProcDerive
,
119 record_extern_fqn(cx
, did
, type_kind
);
125 let (attrs
, cfg
) = merge_attrs(cx
, Some(parent_module
), load_attrs(cx
, did
), attrs_clone
);
126 cx
.inlined
.insert(did
.into());
128 clean
::Item
::from_def_id_and_attrs_and_parts(did
, Some(name
), kind
, box attrs
, cx
, cfg
);
129 if let Some(import_def_id
) = import_def_id
{
130 // The visibility needs to reflect the one from the reexport and not from the "source" DefId.
131 item
.visibility
= cx
.tcx
.visibility(import_def_id
).clean(cx
);
137 crate fn try_inline_glob(
138 cx
: &mut DocContext
<'_
>,
140 visited
: &mut FxHashSet
<DefId
>,
141 ) -> Option
<Vec
<clean
::Item
>> {
142 let did
= res
.opt_def_id()?
;
148 Res
::Def(DefKind
::Mod
, did
) => {
149 let m
= build_module(cx
, did
, visited
);
152 // glob imports on things like enums aren't inlined even for local exports, so just bail
157 crate fn load_attrs
<'hir
>(cx
: &DocContext
<'hir
>, did
: DefId
) -> Attrs
<'hir
> {
158 cx
.tcx
.get_attrs(did
)
161 /// Record an external fully qualified name in the external_paths cache.
163 /// These names are used later on by HTML rendering to generate things like
164 /// source links back to the original item.
165 crate fn record_extern_fqn(cx
: &mut DocContext
<'_
>, did
: DefId
, kind
: ItemType
) {
166 let crate_name
= cx
.tcx
.crate_name(did
.krate
);
169 cx
.tcx
.def_path(did
).data
.into_iter().filter_map(|elem
| elem
.data
.get_opt_name());
170 let fqn
= if let ItemType
::Macro
= kind
{
171 // Check to see if it is a macro 2.0 or built-in macro
173 CStore
::from_tcx(cx
.tcx
).load_macro_untracked(did
, cx
.sess()),
174 LoadedMacro
::MacroDef(def
, _
)
175 if matches
!(&def
.kind
, ast
::ItemKind
::MacroDef(ast_def
)
176 if !ast_def
.macro_rules
)
178 once(crate_name
).chain(relative
).collect()
180 vec
![crate_name
, relative
.last().expect("relative was empty")]
183 once(crate_name
).chain(relative
).collect()
187 cx
.cache
.exact_paths
.insert(did
, fqn
);
189 cx
.cache
.external_paths
.insert(did
, (fqn
, kind
));
193 crate fn build_external_trait(cx
: &mut DocContext
<'_
>, did
: DefId
) -> clean
::Trait
{
196 .associated_items(did
)
197 .in_definition_order()
199 // When building an external trait, the cleaned trait will have all items public,
200 // which causes methods to have a `pub` prefix, which is invalid since items in traits
201 // can not have a visibility prefix. Thus we override the visibility here manually.
202 // See https://github.com/rust-lang/rust/issues/81274
203 clean
::Item { visibility: Visibility::Inherited, ..item.clean(cx) }
207 let predicates
= cx
.tcx
.predicates_of(did
);
208 let generics
= clean_ty_generics(cx
, cx
.tcx
.generics_of(did
), predicates
);
209 let generics
= filter_non_trait_generics(did
, generics
);
210 let (generics
, supertrait_bounds
) = separate_supertrait_bounds(generics
);
211 let is_auto
= cx
.tcx
.trait_is_auto(did
);
213 unsafety
: cx
.tcx
.trait_def(did
).unsafety
,
216 bounds
: supertrait_bounds
,
221 fn build_external_function(cx
: &mut DocContext
<'_
>, did
: DefId
) -> clean
::Function
{
222 let sig
= cx
.tcx
.fn_sig(did
);
224 let predicates
= cx
.tcx
.predicates_of(did
);
225 let (generics
, decl
) = clean
::enter_impl_trait(cx
, |cx
| {
226 // NOTE: generics need to be cleaned before the decl!
227 let generics
= clean_ty_generics(cx
, cx
.tcx
.generics_of(did
), predicates
);
228 let decl
= clean_fn_decl_from_did_and_sig(cx
, Some(did
), sig
);
231 clean
::Function { decl, generics }
234 fn build_enum(cx
: &mut DocContext
<'_
>, did
: DefId
) -> clean
::Enum
{
235 let predicates
= cx
.tcx
.explicit_predicates_of(did
);
238 generics
: clean_ty_generics(cx
, cx
.tcx
.generics_of(did
), predicates
),
239 variants_stripped
: false,
240 variants
: cx
.tcx
.adt_def(did
).variants().iter().map(|v
| v
.clean(cx
)).collect(),
244 fn build_struct(cx
: &mut DocContext
<'_
>, did
: DefId
) -> clean
::Struct
{
245 let predicates
= cx
.tcx
.explicit_predicates_of(did
);
246 let variant
= cx
.tcx
.adt_def(did
).non_enum_variant();
249 struct_type
: variant
.ctor_kind
,
250 generics
: clean_ty_generics(cx
, cx
.tcx
.generics_of(did
), predicates
),
251 fields
: variant
.fields
.iter().map(|x
| x
.clean(cx
)).collect(),
252 fields_stripped
: false,
256 fn build_union(cx
: &mut DocContext
<'_
>, did
: DefId
) -> clean
::Union
{
257 let predicates
= cx
.tcx
.explicit_predicates_of(did
);
258 let variant
= cx
.tcx
.adt_def(did
).non_enum_variant();
260 let generics
= clean_ty_generics(cx
, cx
.tcx
.generics_of(did
), predicates
);
261 let fields
= variant
.fields
.iter().map(|x
| x
.clean(cx
)).collect();
262 clean
::Union { generics, fields, fields_stripped: false }
265 fn build_type_alias(cx
: &mut DocContext
<'_
>, did
: DefId
) -> clean
::Typedef
{
266 let predicates
= cx
.tcx
.explicit_predicates_of(did
);
267 let type_
= cx
.tcx
.type_of(did
).clean(cx
);
271 generics
: clean_ty_generics(cx
, cx
.tcx
.generics_of(did
), predicates
),
276 /// Builds all inherent implementations of an ADT (struct/union/enum) or Trait item/path/reexport.
277 crate fn build_impls(
278 cx
: &mut DocContext
<'_
>,
279 parent_module
: Option
<DefId
>,
281 attrs
: Option
<Attrs
<'_
>>,
282 ret
: &mut Vec
<clean
::Item
>,
284 let _prof_timer
= cx
.tcx
.sess
.prof
.generic_activity("build_inherent_impls");
287 // for each implementation of an item represented by `did`, build the clean::Item for that impl
288 for &did
in tcx
.inherent_impls(did
).iter() {
289 build_impl(cx
, parent_module
, did
, attrs
, ret
);
293 /// `parent_module` refers to the parent of the re-export, not the original item
295 cx
: &mut DocContext
<'_
>,
296 parent_module
: Option
<DefId
>,
297 old_attrs
: Attrs
<'_
>,
298 new_attrs
: Option
<Attrs
<'_
>>,
299 ) -> (clean
::Attributes
, Option
<Arc
<clean
::cfg
::Cfg
>>) {
300 // NOTE: If we have additional attributes (from a re-export),
301 // always insert them first. This ensure that re-export
302 // doc comments show up before the original doc comments
303 // when we render them.
304 if let Some(inner
) = new_attrs
{
305 let mut both
= inner
.to_vec();
306 both
.extend_from_slice(old_attrs
);
308 if let Some(new_id
) = parent_module
{
309 Attributes
::from_ast(old_attrs
, Some((inner
, new_id
)))
311 Attributes
::from_ast(&both
, None
)
313 both
.cfg(cx
.tcx
, &cx
.cache
.hidden_cfg
),
316 (old_attrs
.clean(cx
), old_attrs
.cfg(cx
.tcx
, &cx
.cache
.hidden_cfg
))
320 /// Inline an `impl`, inherent or of a trait. The `did` must be for an `impl`.
322 cx
: &mut DocContext
<'_
>,
323 parent_module
: Option
<DefId
>,
325 attrs
: Option
<Attrs
<'_
>>,
326 ret
: &mut Vec
<clean
::Item
>,
328 if !cx
.inlined
.insert(did
.into()) {
332 let _prof_timer
= cx
.tcx
.sess
.prof
.generic_activity("build_impl");
335 let associated_trait
= tcx
.impl_trait_ref(did
);
337 // Only inline impl if the implemented trait is
338 // reachable in rustdoc generated documentation
340 if let Some(traitref
) = associated_trait
{
341 let did
= traitref
.def_id
;
342 if !cx
.cache
.access_levels
.is_public(did
) {
346 if let Some(stab
) = tcx
.lookup_stability(did
) {
347 if stab
.level
.is_unstable() && stab
.feature
== sym
::rustc_private
{
354 let impl_item
= match did
.as_local() {
355 Some(did
) => match &tcx
.hir().expect_item(did
).kind
{
356 hir
::ItemKind
::Impl(impl_
) => Some(impl_
),
357 _
=> panic
!("`DefID` passed to `build_impl` is not an `impl"),
362 let for_
= match &impl_item
{
363 Some(impl_
) => impl_
.self_ty
.clean(cx
),
364 None
=> tcx
.type_of(did
).clean(cx
),
367 // Only inline impl if the implementing type is
368 // reachable in rustdoc generated documentation
370 if let Some(did
) = for_
.def_id(&cx
.cache
) {
371 if !cx
.cache
.access_levels
.is_public(did
) {
375 if let Some(stab
) = tcx
.lookup_stability(did
) {
376 if stab
.level
.is_unstable() && stab
.feature
== sym
::rustc_private
{
383 let document_hidden
= cx
.render_options
.document_hidden
;
384 let predicates
= tcx
.explicit_predicates_of(did
);
385 let (trait_items
, generics
) = match impl_item
{
390 .map(|item
| tcx
.hir().impl_item(item
.id
))
392 // Filter out impl items whose corresponding trait item has `doc(hidden)`
393 // not to document such impl items.
394 // For inherent impls, we don't do any filtering, because that's already done in strip_hidden.rs.
396 // When `--document-hidden-items` is passed, we don't
397 // do any filtering, too.
401 if let Some(associated_trait
) = associated_trait
{
402 let assoc_kind
= match item
.kind
{
403 hir
::ImplItemKind
::Const(..) => ty
::AssocKind
::Const
,
404 hir
::ImplItemKind
::Fn(..) => ty
::AssocKind
::Fn
,
405 hir
::ImplItemKind
::TyAlias(..) => ty
::AssocKind
::Type
,
408 .associated_items(associated_trait
.def_id
)
409 .find_by_name_and_kind(
413 associated_trait
.def_id
,
415 .unwrap(); // SAFETY: For all impl items there exists trait item that has the same name.
416 !tcx
.is_doc_hidden(trait_item
.def_id
)
421 .map(|item
| item
.clean(cx
))
422 .collect
::<Vec
<_
>>(),
423 impl_
.generics
.clean(cx
),
426 tcx
.associated_items(did
)
427 .in_definition_order()
429 if associated_trait
.is_some() || item
.vis
.is_public() {
435 .collect
::<Vec
<_
>>(),
436 clean
::enter_impl_trait(cx
, |cx
| {
437 clean_ty_generics(cx
, tcx
.generics_of(did
), predicates
)
441 let polarity
= tcx
.impl_polarity(did
);
442 let trait_
= associated_trait
.map(|t
| t
.clean(cx
));
443 if trait_
.as_ref().map(|t
| t
.def_id()) == tcx
.lang_items().deref_trait() {
444 super::build_deref_target_impls(cx
, &trait_items
, ret
);
447 // Return if the trait itself or any types of the generic parameters are doc(hidden).
448 let mut stack
: Vec
<&Type
> = vec
![&for_
];
450 if let Some(did
) = trait_
.as_ref().map(|t
| t
.def_id()) {
451 if tcx
.is_doc_hidden(did
) {
455 if let Some(generics
) = trait_
.as_ref().and_then(|t
| t
.generics()) {
456 stack
.extend(generics
);
459 while let Some(ty
) = stack
.pop() {
460 if let Some(did
) = ty
.def_id(&cx
.cache
) {
461 if tcx
.is_doc_hidden(did
) {
465 if let Some(generics
) = ty
.generics() {
466 stack
.extend(generics
);
470 if let Some(did
) = trait_
.as_ref().map(|t
| t
.def_id()) {
471 record_extern_trait(cx
, did
);
474 let (merged_attrs
, cfg
) = merge_attrs(cx
, parent_module
, load_attrs(cx
, did
), attrs
);
475 trace
!("merged_attrs={:?}", merged_attrs
);
478 "build_impl: impl {:?} for {:?}",
479 trait_
.as_ref().map(|t
| t
.def_id()),
480 for_
.def_id(&cx
.cache
)
482 ret
.push(clean
::Item
::from_def_id_and_attrs_and_parts(
485 clean
::ImplItem(clean
::Impl
{
486 unsafety
: hir
::Unsafety
::Normal
,
492 kind
: ImplKind
::Normal
,
501 cx
: &mut DocContext
<'_
>,
503 visited
: &mut FxHashSet
<DefId
>,
505 let mut items
= Vec
::new();
507 // If we're re-exporting a re-export it may actually re-export something in
508 // two namespaces, so the target may be listed twice. Make sure we only
509 // visit each node at most once.
510 for &item
in cx
.tcx
.module_children(did
).iter() {
511 if item
.vis
.is_public() {
512 let res
= item
.res
.expect_non_local();
513 if let Some(def_id
) = res
.mod_def_id() {
514 if did
== def_id
|| !visited
.insert(def_id
) {
518 if let Res
::PrimTy(p
) = res
{
519 // Primitive types can't be inlined so generate an import instead.
520 let prim_ty
= clean
::PrimitiveType
::from(p
);
521 items
.push(clean
::Item
{
523 attrs
: box clean
::Attributes
::default(),
524 def_id
: ItemId
::Primitive(prim_ty
, did
.krate
),
525 visibility
: clean
::Public
,
526 kind
: box clean
::ImportItem(clean
::Import
::new_simple(
528 clean
::ImportSource
{
531 segments
: vec
![clean
::PathSegment
{
532 name
: prim_ty
.as_sym(),
533 args
: clean
::GenericArgs
::AngleBracketed
{
535 bindings
: ThinVec
::new(),
545 } else if let Some(i
) = try_inline(cx
, did
, None
, res
, item
.ident
.name
, None
, visited
) {
551 let span
= clean
::Span
::new(cx
.tcx
.def_span(did
));
552 clean
::Module { items, span }
555 crate fn print_inlined_const(tcx
: TyCtxt
<'_
>, did
: DefId
) -> String
{
556 if let Some(did
) = did
.as_local() {
557 let hir_id
= tcx
.hir().local_def_id_to_hir_id(did
);
558 rustc_hir_pretty
::id_to_string(&tcx
.hir(), hir_id
)
560 tcx
.rendered_const(did
).clone()
564 fn build_const(cx
: &mut DocContext
<'_
>, def_id
: DefId
) -> clean
::Constant
{
566 type_
: cx
.tcx
.type_of(def_id
).clean(cx
),
567 kind
: clean
::ConstantKind
::Extern { def_id }
,
571 fn build_static(cx
: &mut DocContext
<'_
>, did
: DefId
, mutable
: bool
) -> clean
::Static
{
573 type_
: cx
.tcx
.type_of(did
).clean(cx
),
574 mutability
: if mutable { Mutability::Mut }
else { Mutability::Not }
,
580 cx
: &mut DocContext
<'_
>,
583 import_def_id
: Option
<DefId
>,
584 ) -> clean
::ItemKind
{
585 match CStore
::from_tcx(cx
.tcx
).load_macro_untracked(def_id
, cx
.sess()) {
586 LoadedMacro
::MacroDef(item_def
, _
) => {
587 if let ast
::ItemKind
::MacroDef(ref def
) = item_def
.kind
{
588 let vis
= cx
.tcx
.visibility(import_def_id
.unwrap_or(def_id
)).clean(cx
);
589 clean
::MacroItem(clean
::Macro
{
590 source
: utils
::display_macro_source(cx
, name
, def
, def_id
, vis
),
596 LoadedMacro
::ProcMacro(ext
) => clean
::ProcMacroItem(clean
::ProcMacro
{
597 kind
: ext
.macro_kind(),
598 helpers
: ext
.helper_attrs
,
603 /// A trait's generics clause actually contains all of the predicates for all of
604 /// its associated types as well. We specifically move these clauses to the
605 /// associated types instead when displaying, so when we're generating the
606 /// generics for the trait itself we need to be sure to remove them.
607 /// We also need to remove the implied "recursive" Self: Trait bound.
609 /// The inverse of this filtering logic can be found in the `Clean`
610 /// implementation for `AssociatedType`
611 fn filter_non_trait_generics(trait_did
: DefId
, mut g
: clean
::Generics
) -> clean
::Generics
{
612 for pred
in &mut g
.where_predicates
{
614 clean
::WherePredicate
::BoundPredicate
{
615 ty
: clean
::Generic(ref s
),
618 } if *s
== kw
::SelfUpper
=> {
619 bounds
.retain(|bound
| match bound
{
620 clean
::GenericBound
::TraitBound(clean
::PolyTrait { trait_, .. }
, _
) => {
621 trait_
.def_id() != trait_did
630 g
.where_predicates
.retain(|pred
| match pred
{
631 clean
::WherePredicate
::BoundPredicate
{
632 ty
: clean
::QPath { self_type: box clean::Generic(ref s), trait_, .. }
,
635 } => !(bounds
.is_empty() || *s
== kw
::SelfUpper
&& trait_
.def_id() == trait_did
),
641 /// Supertrait bounds for a trait are also listed in the generics coming from
642 /// the metadata for a crate, so we want to separate those out and create a new
643 /// list of explicit supertrait bounds to render nicely.
644 fn separate_supertrait_bounds(
645 mut g
: clean
::Generics
,
646 ) -> (clean
::Generics
, Vec
<clean
::GenericBound
>) {
647 let mut ty_bounds
= Vec
::new();
648 g
.where_predicates
.retain(|pred
| match *pred
{
649 clean
::WherePredicate
::BoundPredicate { ty: clean::Generic(ref s), ref bounds, .. }
650 if *s
== kw
::SelfUpper
=>
652 ty_bounds
.extend(bounds
.iter().cloned());
660 crate fn record_extern_trait(cx
: &mut DocContext
<'_
>, did
: DefId
) {
666 if cx
.external_traits
.borrow().contains_key(&did
) || cx
.active_extern_traits
.contains(&did
)
673 cx
.active_extern_traits
.insert(did
);
676 debug
!("record_extern_trait: {:?}", did
);
677 let trait_
= build_external_trait(cx
, did
);
679 let trait_
= clean
::TraitWithExtraInfo
{
681 is_notable
: clean
::utils
::has_doc_flag(cx
.tcx
.get_attrs(did
), sym
::notable_trait
),
683 cx
.external_traits
.borrow_mut().insert(did
, trait_
);
684 cx
.active_extern_traits
.remove(&did
);