2014-05-24 11:56:38 -07:00
|
|
|
//! Support for inlining external documentation into the current AST.
|
|
|
|
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
use std::iter::once;
|
2015-04-07 16:18:49 -07:00
|
|
|
|
2020-04-27 23:26:11 +05:30
|
|
|
use rustc_ast as ast;
|
2020-01-05 02:37:57 +01:00
|
|
|
use rustc_data_structures::fx::FxHashSet;
|
|
|
|
use rustc_hir as hir;
|
|
|
|
use rustc_hir::def::{CtorKind, DefKind, Res};
|
2020-05-30 12:30:58 +01:00
|
|
|
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
|
2020-01-05 02:37:57 +01:00
|
|
|
use rustc_hir::Mutability;
|
|
|
|
use rustc_metadata::creader::LoadedMacro;
|
2020-03-29 16:41:09 +02:00
|
|
|
use rustc_middle::ty;
|
2020-01-01 18:06:00 +01:00
|
|
|
use rustc_mir::const_eval::is_min_const_fn;
|
2019-12-31 20:15:40 +03:00
|
|
|
use rustc_span::hygiene::MacroKind;
|
2020-12-16 17:21:08 +01:00
|
|
|
use rustc_span::symbol::{kw, sym, Symbol};
|
2019-12-31 20:15:40 +03:00
|
|
|
use rustc_span::Span;
|
2014-05-24 11:56:38 -07:00
|
|
|
|
2020-10-03 20:06:30 -04:00
|
|
|
use crate::clean::{self, Attributes, GetDefId, ToSource, TypeKind};
|
2019-07-24 17:26:21 -04:00
|
|
|
use crate::core::DocContext;
|
2019-02-23 16:40:07 +09:00
|
|
|
use crate::doctree;
|
2014-05-24 11:56:38 -07:00
|
|
|
|
2016-05-03 13:09:42 +02:00
|
|
|
use super::Clean;
|
2014-05-24 11:56:38 -07:00
|
|
|
|
2020-03-29 16:41:09 +02:00
|
|
|
type Attrs<'hir> = rustc_middle::ty::Attributes<'hir>;
|
Use doc comments from 'pub use' statements
Split off from #62855
Currently, rustdoc ignores any doc comments found on 'pub use'
statements. As described in issue #58700, this makes it impossible to
properly document procedural macros. Any doc comments must be written on
the procedural macro definition, which must occur in a dedicated
proc-macro crate. This means that any doc comments or doc tests cannot
reference items defined in re-exporting crate, despite the fact that
such items may be required to use the procedural macro.
To solve this issue, this commit allows doc comments to be written on
'pub use' statements. For consistency, this applies to *all* 'pub use'
statements, not just those importing procedural macros.
When inlining documentation, documentation on 'pub use' statements will
be prepended to the documentation of the inlined item. For example,
the following items:
```rust
mod other_mod {
/// Doc comment from definition
pub struct MyStruct;
}
/// Doc comment from 'pub use'
///
pub use other_mod::MyStruct;
```
will caues the documentation for the re-export of 'MyStruct' to be
rendered as:
```
Doc comment from 'pub use'
Doc comment from definition
```
Note the empty line in the 'pub use' doc comments - because doc comments
are concatenated as-is, this ensure that the doc comments on the
definition start on a new line.
2019-07-27 14:18:50 -04:00
|
|
|
|
2016-11-25 13:21:19 +02:00
|
|
|
/// Attempt to inline a definition into this AST.
|
2014-05-24 11:56:38 -07:00
|
|
|
///
|
2016-11-25 13:21:19 +02:00
|
|
|
/// This function will fetch the definition specified, and if it is
|
|
|
|
/// from another crate it will attempt to inline the documentation
|
|
|
|
/// from the other crate into this crate.
|
2014-05-24 11:56:38 -07:00
|
|
|
///
|
|
|
|
/// This is primarily used for `pub use` statements which are, in general,
|
|
|
|
/// implementation details. Inlining the documentation should help provide a
|
|
|
|
/// better experience when reading the documentation in this use case.
|
|
|
|
///
|
2016-11-25 13:21:19 +02:00
|
|
|
/// The returned value is `None` if the definition could not be inlined,
|
|
|
|
/// and `Some` of a vector of items if it was successfully expanded.
|
2020-10-03 20:06:30 -04:00
|
|
|
///
|
|
|
|
/// `parent_module` refers to the parent of the *re-export*, not the original item.
|
2020-10-25 05:18:44 -04:00
|
|
|
crate fn try_inline(
|
2018-12-08 20:30:23 +01:00
|
|
|
cx: &DocContext<'_>,
|
2020-10-03 20:06:30 -04:00
|
|
|
parent_module: DefId,
|
2019-04-20 19:36:05 +03:00
|
|
|
res: Res,
|
2020-04-19 13:00:18 +02:00
|
|
|
name: Symbol,
|
Use doc comments from 'pub use' statements
Split off from #62855
Currently, rustdoc ignores any doc comments found on 'pub use'
statements. As described in issue #58700, this makes it impossible to
properly document procedural macros. Any doc comments must be written on
the procedural macro definition, which must occur in a dedicated
proc-macro crate. This means that any doc comments or doc tests cannot
reference items defined in re-exporting crate, despite the fact that
such items may be required to use the procedural macro.
To solve this issue, this commit allows doc comments to be written on
'pub use' statements. For consistency, this applies to *all* 'pub use'
statements, not just those importing procedural macros.
When inlining documentation, documentation on 'pub use' statements will
be prepended to the documentation of the inlined item. For example,
the following items:
```rust
mod other_mod {
/// Doc comment from definition
pub struct MyStruct;
}
/// Doc comment from 'pub use'
///
pub use other_mod::MyStruct;
```
will caues the documentation for the re-export of 'MyStruct' to be
rendered as:
```
Doc comment from 'pub use'
Doc comment from definition
```
Note the empty line in the 'pub use' doc comments - because doc comments
are concatenated as-is, this ensure that the doc comments on the
definition start on a new line.
2019-07-27 14:18:50 -04:00
|
|
|
attrs: Option<Attrs<'_>>,
|
2019-12-22 17:42:04 -05:00
|
|
|
visited: &mut FxHashSet<DefId>,
|
2019-04-20 19:36:05 +03:00
|
|
|
) -> Option<Vec<clean::Item>> {
|
2020-03-05 21:50:44 +01:00
|
|
|
let did = res.opt_def_id()?;
|
2019-12-22 17:42:04 -05:00
|
|
|
if did.is_local() {
|
|
|
|
return None;
|
|
|
|
}
|
2014-05-24 11:56:38 -07:00
|
|
|
let mut ret = Vec::new();
|
Use doc comments from 'pub use' statements
Split off from #62855
Currently, rustdoc ignores any doc comments found on 'pub use'
statements. As described in issue #58700, this makes it impossible to
properly document procedural macros. Any doc comments must be written on
the procedural macro definition, which must occur in a dedicated
proc-macro crate. This means that any doc comments or doc tests cannot
reference items defined in re-exporting crate, despite the fact that
such items may be required to use the procedural macro.
To solve this issue, this commit allows doc comments to be written on
'pub use' statements. For consistency, this applies to *all* 'pub use'
statements, not just those importing procedural macros.
When inlining documentation, documentation on 'pub use' statements will
be prepended to the documentation of the inlined item. For example,
the following items:
```rust
mod other_mod {
/// Doc comment from definition
pub struct MyStruct;
}
/// Doc comment from 'pub use'
///
pub use other_mod::MyStruct;
```
will caues the documentation for the re-export of 'MyStruct' to be
rendered as:
```
Doc comment from 'pub use'
Doc comment from definition
```
Note the empty line in the 'pub use' doc comments - because doc comments
are concatenated as-is, this ensure that the doc comments on the
definition start on a new line.
2019-07-27 14:18:50 -04:00
|
|
|
|
2020-10-03 20:06:30 -04:00
|
|
|
debug!("attrs={:?}", attrs);
|
2020-04-16 00:00:22 +02:00
|
|
|
let attrs_clone = attrs;
|
Use doc comments from 'pub use' statements
Split off from #62855
Currently, rustdoc ignores any doc comments found on 'pub use'
statements. As described in issue #58700, this makes it impossible to
properly document procedural macros. Any doc comments must be written on
the procedural macro definition, which must occur in a dedicated
proc-macro crate. This means that any doc comments or doc tests cannot
reference items defined in re-exporting crate, despite the fact that
such items may be required to use the procedural macro.
To solve this issue, this commit allows doc comments to be written on
'pub use' statements. For consistency, this applies to *all* 'pub use'
statements, not just those importing procedural macros.
When inlining documentation, documentation on 'pub use' statements will
be prepended to the documentation of the inlined item. For example,
the following items:
```rust
mod other_mod {
/// Doc comment from definition
pub struct MyStruct;
}
/// Doc comment from 'pub use'
///
pub use other_mod::MyStruct;
```
will caues the documentation for the re-export of 'MyStruct' to be
rendered as:
```
Doc comment from 'pub use'
Doc comment from definition
```
Note the empty line in the 'pub use' doc comments - because doc comments
are concatenated as-is, this ensure that the doc comments on the
definition start on a new line.
2019-07-27 14:18:50 -04:00
|
|
|
|
2020-11-14 03:45:10 -05:00
|
|
|
let kind = match res {
|
2019-04-20 19:36:05 +03:00
|
|
|
Res::Def(DefKind::Trait, did) => {
|
2016-10-01 00:34:00 -04:00
|
|
|
record_extern_fqn(cx, did, clean::TypeKind::Trait);
|
2020-10-03 20:06:30 -04:00
|
|
|
ret.extend(build_impls(cx, Some(parent_module), did, attrs));
|
2016-11-20 03:42:54 +02:00
|
|
|
clean::TraitItem(build_external_trait(cx, did))
|
2014-05-24 11:56:38 -07:00
|
|
|
}
|
2019-04-20 19:36:05 +03:00
|
|
|
Res::Def(DefKind::Fn, did) => {
|
2016-10-01 00:34:00 -04:00
|
|
|
record_extern_fqn(cx, did, clean::TypeKind::Function);
|
2016-11-20 03:42:54 +02:00
|
|
|
clean::FunctionItem(build_external_function(cx, did))
|
2014-05-24 11:56:38 -07:00
|
|
|
}
|
2019-04-20 19:36:05 +03:00
|
|
|
Res::Def(DefKind::Struct, did) => {
|
2016-10-01 00:34:00 -04:00
|
|
|
record_extern_fqn(cx, did, clean::TypeKind::Struct);
|
2020-10-03 20:06:30 -04:00
|
|
|
ret.extend(build_impls(cx, Some(parent_module), did, attrs));
|
2016-11-20 03:42:54 +02:00
|
|
|
clean::StructItem(build_struct(cx, did))
|
2014-05-24 11:56:38 -07:00
|
|
|
}
|
2019-04-20 19:36:05 +03:00
|
|
|
Res::Def(DefKind::Union, did) => {
|
2016-10-01 00:34:00 -04:00
|
|
|
record_extern_fqn(cx, did, clean::TypeKind::Union);
|
2020-10-03 20:06:30 -04:00
|
|
|
ret.extend(build_impls(cx, Some(parent_module), did, attrs));
|
2016-11-20 03:42:54 +02:00
|
|
|
clean::UnionItem(build_union(cx, did))
|
2016-08-10 21:00:17 +03:00
|
|
|
}
|
2019-04-20 19:36:05 +03:00
|
|
|
Res::Def(DefKind::TyAlias, did) => {
|
2016-10-01 00:34:00 -04:00
|
|
|
record_extern_fqn(cx, did, clean::TypeKind::Typedef);
|
2020-10-03 20:06:30 -04:00
|
|
|
ret.extend(build_impls(cx, Some(parent_module), did, attrs));
|
2016-11-20 03:42:54 +02:00
|
|
|
clean::TypedefItem(build_type_alias(cx, did), false)
|
2014-09-16 09:13:00 +12:00
|
|
|
}
|
2019-04-20 19:36:05 +03:00
|
|
|
Res::Def(DefKind::Enum, did) => {
|
2016-10-01 00:34:00 -04:00
|
|
|
record_extern_fqn(cx, did, clean::TypeKind::Enum);
|
2020-10-03 20:06:30 -04:00
|
|
|
ret.extend(build_impls(cx, Some(parent_module), did, attrs));
|
2016-11-20 03:42:54 +02:00
|
|
|
clean::EnumItem(build_enum(cx, did))
|
2014-05-24 11:56:38 -07:00
|
|
|
}
|
2019-04-20 19:36:05 +03:00
|
|
|
Res::Def(DefKind::ForeignTy, did) => {
|
2017-11-15 17:31:23 +08:00
|
|
|
record_extern_fqn(cx, did, clean::TypeKind::Foreign);
|
2020-10-03 20:06:30 -04:00
|
|
|
ret.extend(build_impls(cx, Some(parent_module), did, attrs));
|
2017-11-15 17:31:23 +08:00
|
|
|
clean::ForeignTypeItem
|
|
|
|
}
|
2018-01-12 16:41:25 -05:00
|
|
|
// Never inline enum variants but leave them shown as re-exports.
|
2019-04-20 19:36:05 +03:00
|
|
|
Res::Def(DefKind::Variant, _) => return None,
|
2018-01-12 16:41:25 -05:00
|
|
|
// Assume that enum variants and struct types are re-exported next to
|
2017-06-12 19:00:09 +01:00
|
|
|
// their constructors.
|
2019-04-20 19:36:05 +03:00
|
|
|
Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => return Some(Vec::new()),
|
|
|
|
Res::Def(DefKind::Mod, did) => {
|
2016-10-01 00:34:00 -04:00
|
|
|
record_extern_fqn(cx, did, clean::TypeKind::Module);
|
2018-04-28 21:56:38 +02:00
|
|
|
clean::ModuleItem(build_module(cx, did, visited))
|
2014-05-24 11:56:38 -07:00
|
|
|
}
|
2019-04-20 19:36:05 +03:00
|
|
|
Res::Def(DefKind::Static, did) => {
|
2016-10-01 00:34:00 -04:00
|
|
|
record_extern_fqn(cx, did, clean::TypeKind::Static);
|
2019-04-19 23:32:26 +03:00
|
|
|
clean::StaticItem(build_static(cx, did, cx.tcx.is_mutable_static(did)))
|
2014-06-05 17:20:59 -07:00
|
|
|
}
|
2019-04-20 19:36:05 +03:00
|
|
|
Res::Def(DefKind::Const, did) => {
|
2016-10-01 00:34:00 -04:00
|
|
|
record_extern_fqn(cx, did, clean::TypeKind::Const);
|
2016-11-20 03:42:54 +02:00
|
|
|
clean::ConstantItem(build_const(cx, did))
|
2014-12-12 04:13:36 -08:00
|
|
|
}
|
2019-07-20 16:34:41 -04:00
|
|
|
Res::Def(DefKind::Macro(kind), did) => {
|
2018-09-25 16:15:32 -05:00
|
|
|
let mac = build_macro(cx, did, name);
|
2019-07-20 16:34:41 -04:00
|
|
|
|
|
|
|
let type_kind = match kind {
|
|
|
|
MacroKind::Bang => TypeKind::Macro,
|
|
|
|
MacroKind::Attr => TypeKind::Attr,
|
2019-12-22 17:42:04 -05:00
|
|
|
MacroKind::Derive => TypeKind::Derive,
|
2019-07-20 16:34:41 -04:00
|
|
|
};
|
|
|
|
record_extern_fqn(cx, did, type_kind);
|
|
|
|
mac
|
2018-06-17 14:54:28 -05:00
|
|
|
}
|
2014-05-24 11:56:38 -07:00
|
|
|
_ => return None,
|
|
|
|
};
|
Use doc comments from 'pub use' statements
Split off from #62855
Currently, rustdoc ignores any doc comments found on 'pub use'
statements. As described in issue #58700, this makes it impossible to
properly document procedural macros. Any doc comments must be written on
the procedural macro definition, which must occur in a dedicated
proc-macro crate. This means that any doc comments or doc tests cannot
reference items defined in re-exporting crate, despite the fact that
such items may be required to use the procedural macro.
To solve this issue, this commit allows doc comments to be written on
'pub use' statements. For consistency, this applies to *all* 'pub use'
statements, not just those importing procedural macros.
When inlining documentation, documentation on 'pub use' statements will
be prepended to the documentation of the inlined item. For example,
the following items:
```rust
mod other_mod {
/// Doc comment from definition
pub struct MyStruct;
}
/// Doc comment from 'pub use'
///
pub use other_mod::MyStruct;
```
will caues the documentation for the re-export of 'MyStruct' to be
rendered as:
```
Doc comment from 'pub use'
Doc comment from definition
```
Note the empty line in the 'pub use' doc comments - because doc comments
are concatenated as-is, this ensure that the doc comments on the
definition start on a new line.
2019-07-27 14:18:50 -04:00
|
|
|
|
|
|
|
let target_attrs = load_attrs(cx, did);
|
2020-10-03 20:06:30 -04:00
|
|
|
let attrs = merge_attrs(cx, Some(parent_module), target_attrs, attrs_clone);
|
Use doc comments from 'pub use' statements
Split off from #62855
Currently, rustdoc ignores any doc comments found on 'pub use'
statements. As described in issue #58700, this makes it impossible to
properly document procedural macros. Any doc comments must be written on
the procedural macro definition, which must occur in a dedicated
proc-macro crate. This means that any doc comments or doc tests cannot
reference items defined in re-exporting crate, despite the fact that
such items may be required to use the procedural macro.
To solve this issue, this commit allows doc comments to be written on
'pub use' statements. For consistency, this applies to *all* 'pub use'
statements, not just those importing procedural macros.
When inlining documentation, documentation on 'pub use' statements will
be prepended to the documentation of the inlined item. For example,
the following items:
```rust
mod other_mod {
/// Doc comment from definition
pub struct MyStruct;
}
/// Doc comment from 'pub use'
///
pub use other_mod::MyStruct;
```
will caues the documentation for the re-export of 'MyStruct' to be
rendered as:
```
Doc comment from 'pub use'
Doc comment from definition
```
Note the empty line in the 'pub use' doc comments - because doc comments
are concatenated as-is, this ensure that the doc comments on the
definition start on a new line.
2019-07-27 14:18:50 -04:00
|
|
|
|
2016-04-07 05:59:02 +02:00
|
|
|
cx.renderinfo.borrow_mut().inlined.insert(did);
|
2020-12-14 19:30:36 -05:00
|
|
|
let what_rustc_thinks = clean::Item::from_def_id_and_parts(did, Some(name), kind, cx);
|
2020-11-15 14:09:26 -05:00
|
|
|
ret.push(clean::Item { attrs, ..what_rustc_thinks });
|
2014-05-24 11:56:38 -07:00
|
|
|
Some(ret)
|
|
|
|
}
|
|
|
|
|
2020-10-25 05:18:44 -04:00
|
|
|
crate fn try_inline_glob(
|
2019-12-22 17:42:04 -05:00
|
|
|
cx: &DocContext<'_>,
|
|
|
|
res: Res,
|
|
|
|
visited: &mut FxHashSet<DefId>,
|
|
|
|
) -> Option<Vec<clean::Item>> {
|
|
|
|
if res == Res::Err {
|
|
|
|
return None;
|
|
|
|
}
|
2019-04-20 19:36:05 +03:00
|
|
|
let did = res.def_id();
|
2019-12-22 17:42:04 -05:00
|
|
|
if did.is_local() {
|
|
|
|
return None;
|
|
|
|
}
|
2018-06-15 18:16:43 -05:00
|
|
|
|
2019-04-20 19:36:05 +03:00
|
|
|
match res {
|
|
|
|
Res::Def(DefKind::Mod, did) => {
|
2018-06-15 18:16:43 -05:00
|
|
|
let m = build_module(cx, did, visited);
|
|
|
|
Some(m.items)
|
|
|
|
}
|
|
|
|
// glob imports on things like enums aren't inlined even for local exports, so just bail
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-25 05:18:44 -04:00
|
|
|
crate fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> Attrs<'hir> {
|
Use doc comments from 'pub use' statements
Split off from #62855
Currently, rustdoc ignores any doc comments found on 'pub use'
statements. As described in issue #58700, this makes it impossible to
properly document procedural macros. Any doc comments must be written on
the procedural macro definition, which must occur in a dedicated
proc-macro crate. This means that any doc comments or doc tests cannot
reference items defined in re-exporting crate, despite the fact that
such items may be required to use the procedural macro.
To solve this issue, this commit allows doc comments to be written on
'pub use' statements. For consistency, this applies to *all* 'pub use'
statements, not just those importing procedural macros.
When inlining documentation, documentation on 'pub use' statements will
be prepended to the documentation of the inlined item. For example,
the following items:
```rust
mod other_mod {
/// Doc comment from definition
pub struct MyStruct;
}
/// Doc comment from 'pub use'
///
pub use other_mod::MyStruct;
```
will caues the documentation for the re-export of 'MyStruct' to be
rendered as:
```
Doc comment from 'pub use'
Doc comment from definition
```
Note the empty line in the 'pub use' doc comments - because doc comments
are concatenated as-is, this ensure that the doc comments on the
definition start on a new line.
2019-07-27 14:18:50 -04:00
|
|
|
cx.tcx.get_attrs(did)
|
2014-05-24 11:56:38 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Record an external fully qualified name in the external_paths cache.
|
|
|
|
///
|
|
|
|
/// These names are used later on by HTML rendering to generate things like
|
|
|
|
/// source links back to the original item.
|
2020-10-25 05:18:44 -04:00
|
|
|
crate fn record_extern_fqn(cx: &DocContext<'_>, did: DefId, kind: clean::TypeKind) {
|
2019-08-10 13:44:23 -04:00
|
|
|
let crate_name = cx.tcx.crate_name(did.krate).to_string();
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
|
2016-11-20 03:42:54 +02:00
|
|
|
let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| {
|
|
|
|
// extern blocks have an empty name
|
|
|
|
let s = elem.data.to_string();
|
2019-12-22 17:42:04 -05:00
|
|
|
if !s.is_empty() { Some(s) } else { None }
|
2016-11-20 03:42:54 +02:00
|
|
|
});
|
2018-01-06 14:01:54 +05:30
|
|
|
let fqn = if let clean::TypeKind::Macro = kind {
|
2018-07-29 15:39:51 +02:00
|
|
|
vec![crate_name, relative.last().expect("relative was empty")]
|
2018-01-06 14:01:54 +05:30
|
|
|
} else {
|
|
|
|
once(crate_name).chain(relative).collect()
|
|
|
|
};
|
2018-08-14 14:44:45 -05:00
|
|
|
|
|
|
|
if did.is_local() {
|
|
|
|
cx.renderinfo.borrow_mut().exact_paths.insert(did, fqn);
|
|
|
|
} else {
|
|
|
|
cx.renderinfo.borrow_mut().external_paths.insert(did, (fqn, kind));
|
|
|
|
}
|
2014-05-24 11:56:38 -07:00
|
|
|
}
|
|
|
|
|
2020-10-25 05:18:44 -04:00
|
|
|
crate fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait {
|
2020-02-17 13:09:01 -08:00
|
|
|
let trait_items =
|
|
|
|
cx.tcx.associated_items(did).in_definition_order().map(|item| item.clean(cx)).collect();
|
|
|
|
|
2017-04-24 15:20:46 +03:00
|
|
|
let predicates = cx.tcx.predicates_of(did);
|
2019-10-18 03:14:57 +03:00
|
|
|
let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
|
2015-04-07 00:16:35 -07:00
|
|
|
let generics = filter_non_trait_generics(did, generics);
|
|
|
|
let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
|
2020-07-06 12:53:44 -07:00
|
|
|
let is_spotlight = load_attrs(cx, did).clean(cx).has_doc_flag(sym::spotlight);
|
2018-01-23 01:04:24 +00:00
|
|
|
let is_auto = cx.tcx.trait_is_auto(did);
|
2014-05-24 11:56:38 -07:00
|
|
|
clean::Trait {
|
2017-04-24 15:20:46 +03:00
|
|
|
unsafety: cx.tcx.trait_def(did).unsafety,
|
2017-08-06 22:54:09 -07:00
|
|
|
generics,
|
2015-03-10 12:28:44 +02:00
|
|
|
items: trait_items,
|
2015-04-07 00:16:35 -07:00
|
|
|
bounds: supertrait_bounds,
|
2020-07-06 12:53:44 -07:00
|
|
|
is_spotlight,
|
2018-01-23 01:04:24 +00:00
|
|
|
is_auto,
|
2014-05-24 11:56:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-08 20:30:23 +01:00
|
|
|
fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function {
|
2017-05-13 17:11:52 +03:00
|
|
|
let sig = cx.tcx.fn_sig(did);
|
2015-11-19 16:27:17 +01:00
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
let constness =
|
2020-01-01 18:06:00 +01:00
|
|
|
if is_min_const_fn(cx.tcx, did) { hir::Constness::Const } else { hir::Constness::NotConst };
|
2019-12-22 17:42:04 -05:00
|
|
|
let asyncness = cx.tcx.asyncness(did);
|
2017-04-24 15:20:46 +03:00
|
|
|
let predicates = cx.tcx.predicates_of(did);
|
2019-06-21 12:23:05 +09:00
|
|
|
let (generics, decl) = clean::enter_impl_trait(cx, || {
|
2019-10-18 03:14:57 +03:00
|
|
|
((cx.tcx.generics_of(did), predicates).clean(cx), (did, sig).clean(cx))
|
2019-06-21 12:23:05 +09:00
|
|
|
});
|
2019-03-07 16:47:40 +01:00
|
|
|
let (all_types, ret_types) = clean::get_all_types(&generics, &decl, cx);
|
2014-05-24 11:56:38 -07:00
|
|
|
clean::Function {
|
2019-03-07 02:44:28 +01:00
|
|
|
decl,
|
|
|
|
generics,
|
2019-12-22 17:42:04 -05:00
|
|
|
header: hir::FnHeader { unsafety: sig.unsafety(), abi: sig.abi(), constness, asyncness },
|
2019-03-07 02:44:28 +01:00
|
|
|
all_types,
|
2019-03-07 16:47:40 +01:00
|
|
|
ret_types,
|
2014-05-24 11:56:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-08 20:30:23 +01:00
|
|
|
fn build_enum(cx: &DocContext<'_>, did: DefId) -> clean::Enum {
|
2019-03-31 15:32:25 +02:00
|
|
|
let predicates = cx.tcx.explicit_predicates_of(did);
|
2016-09-19 23:49:01 +03:00
|
|
|
|
|
|
|
clean::Enum {
|
2019-10-18 03:14:57 +03:00
|
|
|
generics: (cx.tcx.generics_of(did), predicates).clean(cx),
|
2016-09-19 23:49:01 +03:00
|
|
|
variants_stripped: false,
|
2017-04-24 15:20:46 +03:00
|
|
|
variants: cx.tcx.adt_def(did).variants.clean(cx),
|
2016-09-19 23:49:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-08 20:30:23 +01:00
|
|
|
fn build_struct(cx: &DocContext<'_>, did: DefId) -> clean::Struct {
|
2019-03-31 15:32:25 +02:00
|
|
|
let predicates = cx.tcx.explicit_predicates_of(did);
|
2018-01-07 22:41:41 +01:00
|
|
|
let variant = cx.tcx.adt_def(did).non_enum_variant();
|
2014-05-24 11:56:38 -07:00
|
|
|
|
|
|
|
clean::Struct {
|
2016-09-15 00:51:46 +03:00
|
|
|
struct_type: match variant.ctor_kind {
|
|
|
|
CtorKind::Fictive => doctree::Plain,
|
|
|
|
CtorKind::Fn => doctree::Tuple,
|
|
|
|
CtorKind::Const => doctree::Unit,
|
2014-05-24 11:56:38 -07:00
|
|
|
},
|
2019-10-18 03:14:57 +03:00
|
|
|
generics: (cx.tcx.generics_of(did), predicates).clean(cx),
|
2015-08-02 22:52:50 +03:00
|
|
|
fields: variant.fields.clean(cx),
|
2014-05-24 11:56:38 -07:00
|
|
|
fields_stripped: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-08 20:30:23 +01:00
|
|
|
fn build_union(cx: &DocContext<'_>, did: DefId) -> clean::Union {
|
2019-03-31 15:32:25 +02:00
|
|
|
let predicates = cx.tcx.explicit_predicates_of(did);
|
2018-01-07 22:41:41 +01:00
|
|
|
let variant = cx.tcx.adt_def(did).non_enum_variant();
|
2016-08-10 21:00:17 +03:00
|
|
|
|
|
|
|
clean::Union {
|
|
|
|
struct_type: doctree::Plain,
|
2019-10-18 03:14:57 +03:00
|
|
|
generics: (cx.tcx.generics_of(did), predicates).clean(cx),
|
2016-08-10 21:00:17 +03:00
|
|
|
fields: variant.fields.clean(cx),
|
|
|
|
fields_stripped: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-08 20:30:23 +01:00
|
|
|
fn build_type_alias(cx: &DocContext<'_>, did: DefId) -> clean::Typedef {
|
2019-03-31 15:32:25 +02:00
|
|
|
let predicates = cx.tcx.explicit_predicates_of(did);
|
2014-05-24 11:56:38 -07:00
|
|
|
|
2016-09-19 23:49:01 +03:00
|
|
|
clean::Typedef {
|
2017-04-24 15:20:46 +03:00
|
|
|
type_: cx.tcx.type_of(did).clean(cx),
|
2019-10-18 03:14:57 +03:00
|
|
|
generics: (cx.tcx.generics_of(did), predicates).clean(cx),
|
2020-01-10 02:07:13 +01:00
|
|
|
item_type: build_type_alias_type(cx, did),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn build_type_alias_type(cx: &DocContext<'_>, did: DefId) -> Option<clean::Type> {
|
|
|
|
let type_ = cx.tcx.type_of(did).clean(cx);
|
|
|
|
type_.def_id().and_then(|did| build_ty(cx, did))
|
|
|
|
}
|
|
|
|
|
2020-10-25 05:18:44 -04:00
|
|
|
crate fn build_ty(cx: &DocContext<'_>, did: DefId) -> Option<clean::Type> {
|
2020-04-17 21:55:17 +03:00
|
|
|
match cx.tcx.def_kind(did) {
|
2020-01-10 14:46:28 +01:00
|
|
|
DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::Const | DefKind::Static => {
|
|
|
|
Some(cx.tcx.type_of(did).clean(cx))
|
|
|
|
}
|
2020-01-10 02:07:13 +01:00
|
|
|
DefKind::TyAlias => build_type_alias_type(cx, did),
|
|
|
|
_ => None,
|
2016-09-19 23:49:01 +03:00
|
|
|
}
|
2014-05-24 11:56:38 -07:00
|
|
|
}
|
|
|
|
|
2020-09-16 09:15:51 +00:00
|
|
|
/// Builds all inherent implementations of an ADT (struct/union/enum) or Trait item/path/reexport.
|
2020-10-25 05:18:44 -04:00
|
|
|
crate fn build_impls(
|
2020-10-03 20:06:30 -04:00
|
|
|
cx: &DocContext<'_>,
|
|
|
|
parent_module: Option<DefId>,
|
|
|
|
did: DefId,
|
|
|
|
attrs: Option<Attrs<'_>>,
|
|
|
|
) -> Vec<clean::Item> {
|
2016-11-20 03:42:54 +02:00
|
|
|
let tcx = cx.tcx;
|
2014-05-24 11:56:38 -07:00
|
|
|
let mut impls = Vec::new();
|
|
|
|
|
2020-09-16 09:15:51 +00:00
|
|
|
// for each implementation of an item represented by `did`, build the clean::Item for that impl
|
2017-04-24 17:23:36 +03:00
|
|
|
for &did in tcx.inherent_impls(did).iter() {
|
2020-10-03 20:06:30 -04:00
|
|
|
build_impl(cx, parent_module, did, attrs, &mut impls);
|
2014-05-24 11:56:38 -07:00
|
|
|
}
|
2017-03-20 18:35:16 -04:00
|
|
|
|
2016-04-20 17:30:26 +02:00
|
|
|
impls
|
2014-05-24 11:56:38 -07:00
|
|
|
}
|
|
|
|
|
2020-10-03 20:06:30 -04:00
|
|
|
/// `parent_module` refers to the parent of the re-export, not the original item
|
2019-12-22 17:42:04 -05:00
|
|
|
fn merge_attrs(
|
|
|
|
cx: &DocContext<'_>,
|
2020-10-03 20:06:30 -04:00
|
|
|
parent_module: Option<DefId>,
|
|
|
|
old_attrs: Attrs<'_>,
|
|
|
|
new_attrs: Option<Attrs<'_>>,
|
Use doc comments from 'pub use' statements
Split off from #62855
Currently, rustdoc ignores any doc comments found on 'pub use'
statements. As described in issue #58700, this makes it impossible to
properly document procedural macros. Any doc comments must be written on
the procedural macro definition, which must occur in a dedicated
proc-macro crate. This means that any doc comments or doc tests cannot
reference items defined in re-exporting crate, despite the fact that
such items may be required to use the procedural macro.
To solve this issue, this commit allows doc comments to be written on
'pub use' statements. For consistency, this applies to *all* 'pub use'
statements, not just those importing procedural macros.
When inlining documentation, documentation on 'pub use' statements will
be prepended to the documentation of the inlined item. For example,
the following items:
```rust
mod other_mod {
/// Doc comment from definition
pub struct MyStruct;
}
/// Doc comment from 'pub use'
///
pub use other_mod::MyStruct;
```
will caues the documentation for the re-export of 'MyStruct' to be
rendered as:
```
Doc comment from 'pub use'
Doc comment from definition
```
Note the empty line in the 'pub use' doc comments - because doc comments
are concatenated as-is, this ensure that the doc comments on the
definition start on a new line.
2019-07-27 14:18:50 -04:00
|
|
|
) -> clean::Attributes {
|
2020-09-18 01:55:40 +00:00
|
|
|
// NOTE: If we have additional attributes (from a re-export),
|
Use doc comments from 'pub use' statements
Split off from #62855
Currently, rustdoc ignores any doc comments found on 'pub use'
statements. As described in issue #58700, this makes it impossible to
properly document procedural macros. Any doc comments must be written on
the procedural macro definition, which must occur in a dedicated
proc-macro crate. This means that any doc comments or doc tests cannot
reference items defined in re-exporting crate, despite the fact that
such items may be required to use the procedural macro.
To solve this issue, this commit allows doc comments to be written on
'pub use' statements. For consistency, this applies to *all* 'pub use'
statements, not just those importing procedural macros.
When inlining documentation, documentation on 'pub use' statements will
be prepended to the documentation of the inlined item. For example,
the following items:
```rust
mod other_mod {
/// Doc comment from definition
pub struct MyStruct;
}
/// Doc comment from 'pub use'
///
pub use other_mod::MyStruct;
```
will caues the documentation for the re-export of 'MyStruct' to be
rendered as:
```
Doc comment from 'pub use'
Doc comment from definition
```
Note the empty line in the 'pub use' doc comments - because doc comments
are concatenated as-is, this ensure that the doc comments on the
definition start on a new line.
2019-07-27 14:18:50 -04:00
|
|
|
// always insert them first. This ensure that re-export
|
|
|
|
// doc comments show up before the original doc comments
|
|
|
|
// when we render them.
|
2020-10-03 20:06:30 -04:00
|
|
|
if let Some(inner) = new_attrs {
|
|
|
|
if let Some(new_id) = parent_module {
|
|
|
|
let diag = cx.sess().diagnostic();
|
|
|
|
Attributes::from_ast(diag, old_attrs, Some((inner, new_id)))
|
|
|
|
} else {
|
|
|
|
let mut both = inner.to_vec();
|
|
|
|
both.extend_from_slice(old_attrs);
|
|
|
|
both.clean(cx)
|
|
|
|
}
|
2020-09-18 01:55:40 +00:00
|
|
|
} else {
|
2020-10-03 20:06:30 -04:00
|
|
|
old_attrs.clean(cx)
|
|
|
|
}
|
Use doc comments from 'pub use' statements
Split off from #62855
Currently, rustdoc ignores any doc comments found on 'pub use'
statements. As described in issue #58700, this makes it impossible to
properly document procedural macros. Any doc comments must be written on
the procedural macro definition, which must occur in a dedicated
proc-macro crate. This means that any doc comments or doc tests cannot
reference items defined in re-exporting crate, despite the fact that
such items may be required to use the procedural macro.
To solve this issue, this commit allows doc comments to be written on
'pub use' statements. For consistency, this applies to *all* 'pub use'
statements, not just those importing procedural macros.
When inlining documentation, documentation on 'pub use' statements will
be prepended to the documentation of the inlined item. For example,
the following items:
```rust
mod other_mod {
/// Doc comment from definition
pub struct MyStruct;
}
/// Doc comment from 'pub use'
///
pub use other_mod::MyStruct;
```
will caues the documentation for the re-export of 'MyStruct' to be
rendered as:
```
Doc comment from 'pub use'
Doc comment from definition
```
Note the empty line in the 'pub use' doc comments - because doc comments
are concatenated as-is, this ensure that the doc comments on the
definition start on a new line.
2019-07-27 14:18:50 -04:00
|
|
|
}
|
|
|
|
|
2020-09-16 09:15:51 +00:00
|
|
|
/// Builds a specific implementation of a type. The `did` could be a type method or trait method.
|
2020-10-25 05:18:44 -04:00
|
|
|
crate fn build_impl(
|
2019-12-22 17:42:04 -05:00
|
|
|
cx: &DocContext<'_>,
|
2020-10-03 20:06:30 -04:00
|
|
|
parent_module: impl Into<Option<DefId>>,
|
2019-12-22 17:42:04 -05:00
|
|
|
did: DefId,
|
|
|
|
attrs: Option<Attrs<'_>>,
|
|
|
|
ret: &mut Vec<clean::Item>,
|
Use doc comments from 'pub use' statements
Split off from #62855
Currently, rustdoc ignores any doc comments found on 'pub use'
statements. As described in issue #58700, this makes it impossible to
properly document procedural macros. Any doc comments must be written on
the procedural macro definition, which must occur in a dedicated
proc-macro crate. This means that any doc comments or doc tests cannot
reference items defined in re-exporting crate, despite the fact that
such items may be required to use the procedural macro.
To solve this issue, this commit allows doc comments to be written on
'pub use' statements. For consistency, this applies to *all* 'pub use'
statements, not just those importing procedural macros.
When inlining documentation, documentation on 'pub use' statements will
be prepended to the documentation of the inlined item. For example,
the following items:
```rust
mod other_mod {
/// Doc comment from definition
pub struct MyStruct;
}
/// Doc comment from 'pub use'
///
pub use other_mod::MyStruct;
```
will caues the documentation for the re-export of 'MyStruct' to be
rendered as:
```
Doc comment from 'pub use'
Doc comment from definition
```
Note the empty line in the 'pub use' doc comments - because doc comments
are concatenated as-is, this ensure that the doc comments on the
definition start on a new line.
2019-07-27 14:18:50 -04:00
|
|
|
) {
|
2016-04-07 05:59:02 +02:00
|
|
|
if !cx.renderinfo.borrow_mut().inlined.insert(did) {
|
2019-12-22 17:42:04 -05:00
|
|
|
return;
|
2014-06-01 11:16:18 -07:00
|
|
|
}
|
|
|
|
|
2016-11-20 03:42:54 +02:00
|
|
|
let tcx = cx.tcx;
|
2015-11-22 21:02:04 +02:00
|
|
|
let associated_trait = tcx.impl_trait_ref(did);
|
2016-04-15 16:34:48 +02:00
|
|
|
|
|
|
|
// Only inline impl if the implemented trait is
|
|
|
|
// reachable in rustdoc generated documentation
|
2018-08-21 16:22:20 -05:00
|
|
|
if !did.is_local() {
|
|
|
|
if let Some(traitref) = associated_trait {
|
2020-09-10 14:05:33 +00:00
|
|
|
let did = traitref.def_id;
|
|
|
|
if !cx.renderinfo.borrow().access_levels.is_public(did) {
|
2019-12-22 17:42:04 -05:00
|
|
|
return;
|
2018-08-21 16:22:20 -05:00
|
|
|
}
|
2020-06-17 15:08:37 -07:00
|
|
|
|
2020-09-10 14:05:33 +00:00
|
|
|
if let Some(stab) = tcx.lookup_stability(did) {
|
|
|
|
if stab.level.is_unstable() && stab.feature == sym::rustc_private {
|
2020-07-19 16:39:20 -04:00
|
|
|
return;
|
|
|
|
}
|
2020-06-17 15:08:37 -07:00
|
|
|
}
|
|
|
|
}
|
2014-07-25 08:26:17 -07:00
|
|
|
}
|
|
|
|
|
2020-09-10 03:10:36 +00:00
|
|
|
let impl_item = match did.as_local() {
|
|
|
|
Some(did) => {
|
|
|
|
let hir_id = tcx.hir().local_def_id_to_hir_id(did);
|
|
|
|
match tcx.hir().expect_item(hir_id).kind {
|
|
|
|
hir::ItemKind::Impl { self_ty, ref generics, ref items, .. } => {
|
|
|
|
Some((self_ty, generics, items))
|
|
|
|
}
|
|
|
|
_ => panic!("`DefID` passed to `build_impl` is not an `impl"),
|
|
|
|
}
|
2020-04-16 20:36:32 +01:00
|
|
|
}
|
2020-09-10 03:10:36 +00:00
|
|
|
None => None,
|
|
|
|
};
|
|
|
|
|
|
|
|
let for_ = match impl_item {
|
|
|
|
Some((self_ty, _, _)) => self_ty.clean(cx),
|
|
|
|
None => tcx.type_of(did).clean(cx),
|
2020-04-16 20:36:32 +01:00
|
|
|
};
|
2016-04-15 16:34:48 +02:00
|
|
|
|
|
|
|
// Only inline impl if the implementing type is
|
|
|
|
// reachable in rustdoc generated documentation
|
2018-08-21 16:22:20 -05:00
|
|
|
if !did.is_local() {
|
|
|
|
if let Some(did) = for_.def_id() {
|
2019-07-24 17:26:21 -04:00
|
|
|
if !cx.renderinfo.borrow().access_levels.is_public(did) {
|
2019-12-22 17:42:04 -05:00
|
|
|
return;
|
2018-08-21 16:22:20 -05:00
|
|
|
}
|
2020-09-10 14:05:33 +00:00
|
|
|
|
|
|
|
if let Some(stab) = tcx.lookup_stability(did) {
|
|
|
|
if stab.level.is_unstable() && stab.feature == sym::rustc_private {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2016-04-15 16:34:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-31 15:32:25 +02:00
|
|
|
let predicates = tcx.explicit_predicates_of(did);
|
2020-09-10 03:10:36 +00:00
|
|
|
let (trait_items, generics) = match impl_item {
|
|
|
|
Some((_, generics, items)) => (
|
|
|
|
items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::<Vec<_>>(),
|
|
|
|
generics.clean(cx),
|
|
|
|
),
|
|
|
|
None => (
|
2019-12-22 17:42:04 -05:00
|
|
|
tcx.associated_items(did)
|
2020-02-17 13:09:01 -08:00
|
|
|
.in_definition_order()
|
2019-12-22 17:42:04 -05:00
|
|
|
.filter_map(|item| {
|
|
|
|
if associated_trait.is_some() || item.vis == ty::Visibility::Public {
|
|
|
|
Some(item.clean(cx))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>(),
|
|
|
|
clean::enter_impl_trait(cx, || (tcx.generics_of(did), predicates).clean(cx)),
|
2020-09-10 03:10:36 +00:00
|
|
|
),
|
2018-08-14 16:42:34 -05:00
|
|
|
};
|
2017-04-24 15:20:46 +03:00
|
|
|
let polarity = tcx.impl_polarity(did);
|
2019-12-22 17:42:04 -05:00
|
|
|
let trait_ = associated_trait.clean(cx).map(|bound| match bound {
|
|
|
|
clean::GenericBound::TraitBound(polyt, _) => polyt.trait_,
|
|
|
|
clean::GenericBound::Outlives(..) => unreachable!(),
|
2015-04-13 16:23:32 -07:00
|
|
|
});
|
2017-08-31 09:19:33 -07:00
|
|
|
if trait_.def_id() == tcx.lang_items().deref_trait() {
|
2016-03-24 06:10:52 +01:00
|
|
|
super::build_deref_target_impls(cx, &trait_items, ret);
|
2015-04-13 16:23:32 -07:00
|
|
|
}
|
2018-01-10 07:05:30 +00:00
|
|
|
if let Some(trait_did) = trait_.def_id() {
|
|
|
|
record_extern_trait(cx, trait_did);
|
|
|
|
}
|
2016-03-24 06:10:52 +01:00
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
let provided = trait_
|
|
|
|
.def_id()
|
2020-02-07 21:33:23 +01:00
|
|
|
.map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect())
|
2019-12-22 17:42:04 -05:00
|
|
|
.unwrap_or_default();
|
2016-03-24 06:10:52 +01:00
|
|
|
|
2018-08-14 14:41:07 -05:00
|
|
|
debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id());
|
|
|
|
|
2020-11-23 13:22:56 +01:00
|
|
|
let mut item = clean::Item::from_def_id_and_parts(
|
2020-11-15 14:09:26 -05:00
|
|
|
did,
|
|
|
|
None,
|
|
|
|
clean::ImplItem(clean::Impl {
|
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
2017-11-22 16:16:55 -05:00
|
|
|
unsafety: hir::Unsafety::Normal,
|
2018-08-14 17:38:41 -05:00
|
|
|
generics,
|
2016-03-24 06:10:52 +01:00
|
|
|
provided_trait_methods: provided,
|
2017-08-06 22:54:09 -07:00
|
|
|
trait_,
|
|
|
|
for_,
|
2014-08-04 13:56:56 -07:00
|
|
|
items: trait_items,
|
2016-09-19 23:49:01 +03:00
|
|
|
polarity: Some(polarity.clean(cx)),
|
2018-02-10 14:34:46 -05:00
|
|
|
synthetic: false,
|
2018-07-27 22:59:16 +02:00
|
|
|
blanket_impl: None,
|
2014-05-24 11:56:38 -07:00
|
|
|
}),
|
2020-11-15 14:09:26 -05:00
|
|
|
cx,
|
2020-11-23 13:22:56 +01:00
|
|
|
);
|
|
|
|
item.attrs = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs);
|
|
|
|
debug!("merged_attrs={:?}", item.attrs);
|
|
|
|
ret.push(item);
|
2016-02-26 01:45:24 +01:00
|
|
|
}
|
2014-07-25 08:26:17 -07:00
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet<DefId>) -> clean::Module {
|
2014-05-24 11:56:38 -07:00
|
|
|
let mut items = Vec::new();
|
2018-04-28 21:56:38 +02:00
|
|
|
fill_in(cx, did, &mut items, visited);
|
2019-12-22 17:42:04 -05:00
|
|
|
return clean::Module { items, is_crate: false };
|
|
|
|
|
|
|
|
fn fill_in(
|
|
|
|
cx: &DocContext<'_>,
|
|
|
|
did: DefId,
|
|
|
|
items: &mut Vec<clean::Item>,
|
|
|
|
visited: &mut FxHashSet<DefId>,
|
|
|
|
) {
|
2018-01-12 16:41:25 -05:00
|
|
|
// If we're re-exporting a re-export it may actually re-export something in
|
2015-04-07 16:18:49 -07:00
|
|
|
// two namespaces, so the target may be listed twice. Make sure we only
|
|
|
|
// visit each node at most once.
|
2017-08-31 08:07:39 -07:00
|
|
|
for &item in cx.tcx.item_children(did).iter() {
|
2017-12-04 21:17:42 -08:00
|
|
|
if item.vis == ty::Visibility::Public {
|
2020-01-26 21:28:09 +00:00
|
|
|
if let Some(def_id) = item.res.mod_def_id() {
|
|
|
|
if did == def_id || !visited.insert(def_id) {
|
|
|
|
continue;
|
|
|
|
}
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2020-01-26 21:28:09 +00:00
|
|
|
if let Res::PrimTy(p) = item.res {
|
|
|
|
// Primitive types can't be inlined so generate an import instead.
|
|
|
|
items.push(clean::Item {
|
|
|
|
name: None,
|
|
|
|
attrs: clean::Attributes::default(),
|
2020-12-12 09:38:35 -05:00
|
|
|
source: clean::Span::dummy(),
|
2020-05-30 12:30:58 +01:00
|
|
|
def_id: DefId::local(CRATE_DEF_INDEX),
|
2020-01-26 21:28:09 +00:00
|
|
|
visibility: clean::Public,
|
|
|
|
stability: None,
|
2020-11-29 21:00:14 -05:00
|
|
|
const_stability: None,
|
2020-01-26 21:28:09 +00:00
|
|
|
deprecation: None,
|
2020-11-14 03:45:10 -05:00
|
|
|
kind: clean::ImportItem(clean::Import::new_simple(
|
2020-12-17 14:02:09 +01:00
|
|
|
item.ident.name,
|
2020-01-26 21:28:09 +00:00
|
|
|
clean::ImportSource {
|
|
|
|
path: clean::Path {
|
|
|
|
global: false,
|
|
|
|
res: item.res,
|
|
|
|
segments: vec![clean::PathSegment {
|
2020-12-17 14:02:09 +01:00
|
|
|
name: clean::PrimitiveType::from(p).as_sym(),
|
2020-01-26 21:28:09 +00:00
|
|
|
args: clean::GenericArgs::AngleBracketed {
|
|
|
|
args: Vec::new(),
|
|
|
|
bindings: Vec::new(),
|
|
|
|
},
|
|
|
|
}],
|
|
|
|
},
|
|
|
|
did: None,
|
|
|
|
},
|
2020-09-29 17:04:40 +02:00
|
|
|
true,
|
2020-01-26 21:28:09 +00:00
|
|
|
)),
|
|
|
|
});
|
2020-10-03 20:06:30 -04:00
|
|
|
} else if let Some(i) =
|
|
|
|
try_inline(cx, did, item.res, item.ident.name, None, visited)
|
|
|
|
{
|
2016-09-15 00:51:46 +03:00
|
|
|
items.extend(i)
|
2014-05-24 11:56:38 -07:00
|
|
|
}
|
|
|
|
}
|
2015-11-22 21:02:04 +02:00
|
|
|
}
|
2014-05-24 11:56:38 -07:00
|
|
|
}
|
|
|
|
}
|
2014-06-05 17:20:59 -07:00
|
|
|
|
2020-10-25 05:18:44 -04:00
|
|
|
crate fn print_inlined_const(cx: &DocContext<'_>, did: DefId) -> String {
|
2020-04-23 20:48:40 +01:00
|
|
|
if let Some(did) = did.as_local() {
|
2020-08-12 12:22:56 +02:00
|
|
|
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(did);
|
2020-03-24 02:44:41 +01:00
|
|
|
rustc_hir_pretty::id_to_string(&cx.tcx.hir(), hir_id)
|
2018-08-07 11:30:57 -05:00
|
|
|
} else {
|
|
|
|
cx.tcx.rendered_const(did)
|
|
|
|
}
|
2016-12-27 11:15:26 +02:00
|
|
|
}
|
|
|
|
|
2018-12-08 20:30:23 +01:00
|
|
|
fn build_const(cx: &DocContext<'_>, did: DefId) -> clean::Constant {
|
2019-12-11 14:50:19 +01:00
|
|
|
clean::Constant {
|
|
|
|
type_: cx.tcx.type_of(did).clean(cx),
|
|
|
|
expr: print_inlined_const(cx, did),
|
|
|
|
value: clean::utils::print_evaluated_const(cx, did),
|
2020-04-12 13:45:41 +01:00
|
|
|
is_literal: did.as_local().map_or(false, |did| {
|
2020-08-12 12:22:56 +02:00
|
|
|
clean::utils::is_literal_expr(cx, cx.tcx.hir().local_def_id_to_hir_id(did))
|
2020-04-12 13:45:41 +01:00
|
|
|
}),
|
2019-12-11 14:50:19 +01:00
|
|
|
}
|
2014-12-12 04:13:36 -08:00
|
|
|
}
|
|
|
|
|
2018-12-08 20:30:23 +01:00
|
|
|
fn build_static(cx: &DocContext<'_>, did: DefId, mutable: bool) -> clean::Static {
|
2014-06-05 17:20:59 -07:00
|
|
|
clean::Static {
|
2017-04-24 15:20:46 +03:00
|
|
|
type_: cx.tcx.type_of(did).clean(cx),
|
2019-12-21 15:47:27 +01:00
|
|
|
mutability: if mutable { Mutability::Mut } else { Mutability::Not },
|
2014-06-05 17:20:59 -07:00
|
|
|
expr: "\n\n\n".to_string(), // trigger the "[definition]" links
|
|
|
|
}
|
|
|
|
}
|
2015-04-07 00:16:35 -07:00
|
|
|
|
2020-11-14 03:45:10 -05:00
|
|
|
fn build_macro(cx: &DocContext<'_>, did: DefId, name: Symbol) -> clean::ItemKind {
|
2018-06-17 14:54:28 -05:00
|
|
|
let imported_from = cx.tcx.original_crate_name(did.krate);
|
2019-10-20 03:28:36 +03:00
|
|
|
match cx.enter_resolver(|r| r.cstore().load_macro_untracked(did, cx.sess())) {
|
|
|
|
LoadedMacro::MacroDef(def, _) => {
|
2019-12-01 17:21:00 +01:00
|
|
|
let matchers: Vec<Span> = if let ast::ItemKind::MacroDef(ref def) = def.kind {
|
2019-12-01 17:53:59 +03:00
|
|
|
let tts: Vec<_> = def.body.inner_tokens().into_trees().collect();
|
2018-09-25 14:56:43 -05:00
|
|
|
tts.chunks(4).map(|arm| arm[0].span()).collect()
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
};
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
let source = format!(
|
|
|
|
"macro_rules! {} {{\n{}}}",
|
|
|
|
name.clean(cx),
|
|
|
|
matchers
|
|
|
|
.iter()
|
|
|
|
.map(|span| { format!(" {} => {{ ... }};\n", span.to_src(cx)) })
|
|
|
|
.collect::<String>()
|
|
|
|
);
|
2018-09-25 14:56:43 -05:00
|
|
|
|
2020-12-17 14:02:09 +01:00
|
|
|
clean::MacroItem(clean::Macro { source, imported_from: Some(imported_from) })
|
2018-09-25 14:56:43 -05:00
|
|
|
}
|
2019-12-22 17:42:04 -05:00
|
|
|
LoadedMacro::ProcMacro(ext) => clean::ProcMacroItem(clean::ProcMacro {
|
|
|
|
kind: ext.macro_kind(),
|
2020-12-17 14:02:09 +01:00
|
|
|
helpers: ext.helper_attrs,
|
2019-12-22 17:42:04 -05:00
|
|
|
}),
|
2018-09-25 14:56:43 -05:00
|
|
|
}
|
2018-06-17 14:54:28 -05:00
|
|
|
}
|
|
|
|
|
2015-04-07 00:16:35 -07:00
|
|
|
/// A trait's generics clause actually contains all of the predicates for all of
|
|
|
|
/// its associated types as well. We specifically move these clauses to the
|
2017-08-11 00:16:18 +02:00
|
|
|
/// associated types instead when displaying, so when we're generating the
|
2015-04-07 00:16:35 -07:00
|
|
|
/// generics for the trait itself we need to be sure to remove them.
|
2016-06-13 20:10:32 +03:00
|
|
|
/// We also need to remove the implied "recursive" Self: Trait bound.
|
2015-04-07 00:16:35 -07:00
|
|
|
///
|
|
|
|
/// The inverse of this filtering logic can be found in the `Clean`
|
|
|
|
/// implementation for `AssociatedType`
|
2017-12-17 14:08:09 +01:00
|
|
|
fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics {
|
2016-06-13 20:10:32 +03:00
|
|
|
for pred in &mut g.where_predicates {
|
|
|
|
match *pred {
|
2019-12-22 17:42:04 -05:00
|
|
|
clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref mut bounds }
|
2020-12-16 17:21:08 +01:00
|
|
|
if *s == kw::SelfUpper =>
|
2019-12-22 17:42:04 -05:00
|
|
|
{
|
|
|
|
bounds.retain(|bound| match *bound {
|
|
|
|
clean::GenericBound::TraitBound(
|
|
|
|
clean::PolyTrait { trait_: clean::ResolvedPath { did, .. }, .. },
|
|
|
|
_,
|
|
|
|
) => did != trait_did,
|
|
|
|
_ => true,
|
2016-06-13 20:10:32 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
g.where_predicates.retain(|pred| match *pred {
|
|
|
|
clean::WherePredicate::BoundPredicate {
|
|
|
|
ty:
|
|
|
|
clean::QPath {
|
2015-04-07 00:16:35 -07:00
|
|
|
self_type: box clean::Generic(ref s),
|
|
|
|
trait_: box clean::ResolvedPath { did, .. },
|
|
|
|
name: ref _name,
|
2019-12-22 17:42:04 -05:00
|
|
|
},
|
|
|
|
ref bounds,
|
2020-12-16 17:21:08 +01:00
|
|
|
} => !(bounds.is_empty() || *s == kw::SelfUpper && did == trait_did),
|
2019-12-22 17:42:04 -05:00
|
|
|
_ => true,
|
2015-04-07 00:16:35 -07:00
|
|
|
});
|
2016-10-01 16:47:43 -04:00
|
|
|
g
|
2015-04-07 00:16:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Supertrait bounds for a trait are also listed in the generics coming from
|
|
|
|
/// the metadata for a crate, so we want to separate those out and create a new
|
|
|
|
/// list of explicit supertrait bounds to render nicely.
|
2019-12-22 17:42:04 -05:00
|
|
|
fn separate_supertrait_bounds(
|
|
|
|
mut g: clean::Generics,
|
|
|
|
) -> (clean::Generics, Vec<clean::GenericBound>) {
|
2015-04-07 00:16:35 -07:00
|
|
|
let mut ty_bounds = Vec::new();
|
2019-12-22 17:42:04 -05:00
|
|
|
g.where_predicates.retain(|pred| match *pred {
|
|
|
|
clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref bounds }
|
2020-12-16 17:21:08 +01:00
|
|
|
if *s == kw::SelfUpper =>
|
2019-12-22 17:42:04 -05:00
|
|
|
{
|
|
|
|
ty_bounds.extend(bounds.iter().cloned());
|
|
|
|
false
|
2015-04-07 00:16:35 -07:00
|
|
|
}
|
2019-12-22 17:42:04 -05:00
|
|
|
_ => true,
|
2015-04-07 00:16:35 -07:00
|
|
|
});
|
|
|
|
(g, ty_bounds)
|
|
|
|
}
|
2018-01-10 07:05:30 +00:00
|
|
|
|
2020-10-25 05:18:44 -04:00
|
|
|
crate fn record_extern_trait(cx: &DocContext<'_>, did: DefId) {
|
2018-08-14 12:08:12 -05:00
|
|
|
if did.is_local() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-02-21 18:33:42 -06:00
|
|
|
{
|
2019-12-22 17:42:04 -05:00
|
|
|
if cx.external_traits.borrow().contains_key(&did)
|
|
|
|
|| cx.active_extern_traits.borrow().contains(&did)
|
2018-09-01 21:20:39 -05:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2018-02-21 17:44:49 -06:00
|
|
|
}
|
|
|
|
|
2020-08-05 00:11:57 -04:00
|
|
|
{
|
|
|
|
cx.active_extern_traits.borrow_mut().insert(did);
|
|
|
|
}
|
2018-02-21 18:33:42 -06:00
|
|
|
|
2018-08-14 14:43:03 -05:00
|
|
|
debug!("record_extern_trait: {:?}", did);
|
2018-02-21 17:44:49 -06:00
|
|
|
let trait_ = build_external_trait(cx, did);
|
|
|
|
|
2019-08-10 17:10:13 -04:00
|
|
|
cx.external_traits.borrow_mut().insert(did, trait_);
|
|
|
|
cx.active_extern_traits.borrow_mut().remove(&did);
|
2018-01-10 07:05:30 +00:00
|
|
|
}
|