diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index f2751947c7eb9..f9559bb19658b 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1221,50 +1221,80 @@ impl clean::FnDecl {
}
}
+pub(crate) enum VisibilityScope {
+ Inherited,
+ Crate,
+ Super,
+ Path(Vec),
+}
+
+impl VisibilityScope {
+ crate fn new<'tcx>(vis_did: DefId, item_did: DefId, tcx: TyCtxt<'tcx>) -> VisibilityScope {
+ // FIXME(camelid): This may not work correctly if `item_did` is a module.
+ // However, rustdoc currently never displays a module's
+ // visibility, so it shouldn't matter.
+ let parent_module = find_nearest_parent_module(tcx, item_did);
+
+ if vis_did.index == CRATE_DEF_INDEX {
+ VisibilityScope::Crate
+ } else if parent_module == Some(vis_did) {
+ // `pub(in foo)` where `foo` is the parent module
+ // is the same as no visibility modifier
+ VisibilityScope::Inherited
+ } else if parent_module.map(|parent| find_nearest_parent_module(tcx, parent)).flatten()
+ == Some(vis_did)
+ {
+ VisibilityScope::Super
+ } else {
+ let path = tcx.def_path(vis_did);
+ debug!("path={:?}", path);
+ let mut components: Vec = vec![];
+ for seg in &path.data {
+ components.push(seg.data.get_opt_name().unwrap().to_string());
+ }
+ VisibilityScope::Path(components)
+ }
+ }
+}
+
+impl fmt::Display for VisibilityScope {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ VisibilityScope::Inherited => f.write_str(""),
+ VisibilityScope::Crate => f.write_str("crate"),
+ VisibilityScope::Super => f.write_str("super"),
+ VisibilityScope::Path(components) => {
+ f.write_str("in ")?;
+ for (i, c) in components.iter().enumerate() {
+ if i > 0 {
+ f.write_str("::")?;
+ }
+ f.write_str(c)?;
+ }
+ Ok(())
+ }
+ }
+ }
+}
+
impl clean::Visibility {
crate fn print_with_space<'a, 'tcx: 'a>(
self,
item_did: ItemId,
cx: &'a Context<'tcx>,
) -> impl fmt::Display + 'a + Captures<'tcx> {
- let to_print = match self {
- clean::Public => "pub ".to_owned(),
- clean::Inherited => String::new(),
+ display_fn(move |f| match self {
+ clean::Public => write!(f, "pub "),
+ clean::Inherited => write!(f, ""),
clean::Visibility::Restricted(vis_did) => {
- // FIXME(camelid): This may not work correctly if `item_did` is a module.
- // However, rustdoc currently never displays a module's
- // visibility, so it shouldn't matter.
- let parent_module = find_nearest_parent_module(cx.tcx(), item_did.expect_def_id());
-
- if vis_did.index == CRATE_DEF_INDEX {
- "pub(crate) ".to_owned()
- } else if parent_module == Some(vis_did) {
- // `pub(in foo)` where `foo` is the parent module
- // is the same as no visibility modifier
- String::new()
- } else if parent_module
- .map(|parent| find_nearest_parent_module(cx.tcx(), parent))
- .flatten()
- == Some(vis_did)
- {
- "pub(super) ".to_owned()
- } else {
- let path = cx.tcx().def_path(vis_did);
- debug!("path={:?}", path);
- // modified from `resolved_path()` to work with `DefPathData`
- let last_name = path.data.last().unwrap().data.get_opt_name().unwrap();
- let anchor = anchor(vis_did, &last_name.as_str(), cx).to_string();
-
- let mut s = "pub(in ".to_owned();
- for seg in &path.data[..path.data.len() - 1] {
- s.push_str(&format!("{}::", seg.data.get_opt_name().unwrap()));
- }
- s.push_str(&format!("{}) ", anchor));
- s
+ let mut scope = VisibilityScope::new(vis_did, item_did.expect_def_id(), cx.tcx());
+ if let VisibilityScope::Path(ref mut components) = scope {
+ let last_name = components.pop().unwrap();
+ components.push(anchor(vis_did, &last_name.as_str(), cx).to_string());
}
+ write!(f, "pub({}) ", scope)
}
- };
- display_fn(move |f| f.write_str(&to_print))
+ })
}
/// This function is the same as print_with_space, except that it renders no links.
@@ -1275,33 +1305,14 @@ impl clean::Visibility {
tcx: TyCtxt<'tcx>,
item_did: DefId,
) -> impl fmt::Display + 'a + Captures<'tcx> {
- let to_print = match self {
- clean::Public => "pub ".to_owned(),
- clean::Inherited => String::new(),
+ display_fn(move |f| match self {
+ clean::Public => write!(f, "pub "),
+ clean::Inherited => write!(f, ""),
clean::Visibility::Restricted(vis_did) => {
- // FIXME(camelid): This may not work correctly if `item_did` is a module.
- // However, rustdoc currently never displays a module's
- // visibility, so it shouldn't matter.
- let parent_module = find_nearest_parent_module(tcx, item_did);
-
- if vis_did.index == CRATE_DEF_INDEX {
- "pub(crate) ".to_owned()
- } else if parent_module == Some(vis_did) {
- // `pub(in foo)` where `foo` is the parent module
- // is the same as no visibility modifier
- String::new()
- } else if parent_module
- .map(|parent| find_nearest_parent_module(tcx, parent))
- .flatten()
- == Some(vis_did)
- {
- "pub(super) ".to_owned()
- } else {
- format!("pub(in {}) ", tcx.def_path_str(vis_did))
- }
+ let scope = VisibilityScope::new(vis_did, item_did, tcx);
+ write!(f, "pub({}) ", scope)
}
- };
- display_fn(move |f| f.write_str(&to_print))
+ })
}
}
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 69c5c2c4abc2a..f87ece0cbd5a1 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -66,7 +66,7 @@ use crate::formats::{AssocItemRender, Impl, RenderMode};
use crate::html::escape::Escape;
use crate::html::format::{
href, print_abi_with_space, print_constness_with_space, print_default_space,
- print_generic_bounds, print_where_clause, Buffer, HrefError, PrintWithSpace,
+ print_generic_bounds, print_where_clause, Buffer, HrefError, PrintWithSpace, VisibilityScope,
};
use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine};
@@ -589,6 +589,7 @@ fn document_full_inner(
/// Add extra information about an item such as:
///
+/// * Visibility
/// * Stability
/// * Deprecated
/// * Required features (through the `doc_cfg` feature)
@@ -619,6 +620,49 @@ fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option{}", cfg?.render_long_html()))
}
+fn visibility(
+ item: &clean::Item,
+ cx: &Context<'_>,
+ parent: Option<&clean::Item>,
+) -> Option {
+ // For now, we only render visibility tags for methods and struct fields.
+ match *item.kind {
+ clean::ItemKind::MethodItem(_, _) | clean::ItemKind::StructFieldItem(_) => {}
+ _ => return None,
+ }
+
+ fn tag(contents: impl fmt::Display) -> Option {
+ Some(format!(
+ r#"🙈 Visibility: {}
"#,
+ contents
+ ))
+ }
+ const PRIVATE: &str = "private";
+
+ use clean::ItemKind::*;
+ use clean::Visibility::*;
+
+ match item.visibility {
+ Public => None,
+ // By default, everything in Rust is private, with two exceptions:
+ // Associated items in a pub Trait are public by default;
+ // Enum variants in a pub enum are also public by default.
+ // https://doc.rust-lang.org/reference/visibility-and-privacy.html
+ // Therefore we don't put "private" annotations on traits, trait impls,
+ // or enum variant fields.
+ Inherited => match parent.map(|p| &*p.kind) {
+ Some(TraitItem(_) | ImplItem(_) | VariantItem(_)) => None,
+ _ => tag(PRIVATE),
+ },
+ Restricted(vis_did) => {
+ match VisibilityScope::new(vis_did, item.def_id.expect_def_id(), cx.tcx()) {
+ VisibilityScope::Inherited => tag(PRIVATE),
+ scope => tag(scope),
+ }
+ }
+ }
+}
+
/// Render the stability, deprecation and portability information that is displayed at the top of
/// the item's documentation.
fn short_item_info(
@@ -629,6 +673,10 @@ fn short_item_info(
let mut extra_info = vec![];
let error_codes = cx.shared.codes;
+ if let Some(visibility) = visibility(item, cx, parent) {
+ extra_info.push(visibility)
+ }
+
if let Some(depr @ Deprecation { note, since, is_since_rustc_version: _, suggestion: _ }) =
item.deprecation(cx.tcx())
{
@@ -903,7 +951,6 @@ fn render_assoc_item(
}
}
};
- let vis = meth.visibility.print_with_space(meth.def_id, cx).to_string();
let constness =
print_constness_with_space(&header.constness, meth.const_stability(cx.tcx()));
let asyncness = header.asyncness.print_with_space();
@@ -914,7 +961,6 @@ fn render_assoc_item(
// NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
let generics_len = format!("{:#}", g.print(cx)).len();
let mut header_len = "fn ".len()
- + vis.len()
+ constness.len()
+ asyncness.len()
+ unsafety.len()
@@ -935,10 +981,9 @@ fn render_assoc_item(
w.reserve(header_len + "{".len() + "".len());
write!(
w,
- "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn {name}\
+ "{indent}{constness}{asyncness}{unsafety}{defaultness}{abi}fn {name}\
{generics}{decl}{notable_traits}{where_clause}",
indent = indent_str,
- vis = vis,
constness = constness,
asyncness = asyncness,
unsafety = unsafety,
@@ -1477,6 +1522,7 @@ fn render_impl(
}
w.push_buffer(info_buffer);
+
if toggled {
w.write_str("");
w.push_buffer(doc_buffer);
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index e41c993a5285d..74f20a8c2c564 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -956,10 +956,12 @@ body.blur > :not(#help) {
padding: 0 20px 20px 17px;;
}
-.item-info .stab {
+.item-info .stab,
+.item-info .visibility {
display: table;
}
-.stab {
+.stab,
+.visibility {
border-width: 1px;
border-style: solid;
padding: 3px;
@@ -971,7 +973,8 @@ body.blur > :not(#help) {
display: inline;
}
-.stab .emoji {
+.stab .emoji
+.visibility .emoji {
font-size: 1.5em;
}
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index fba8231caac31..0dfc5e0336c50 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -222,6 +222,7 @@ details.undocumented > summary::before {
color: #000;
}
+.visibility { background: #FFF5D6; border-color: #FFC600; }
.stab.unstable { background: #FFF5D6; border-color: #FFC600; }
.stab.deprecated { background: #ffc4c4; border-color: #db7b7b; }
.stab.portability { background: #F3DFFF; border-color: #b07bdb; }
diff --git a/src/test/rustdoc/document-private.rs b/src/test/rustdoc/document-private.rs
new file mode 100644
index 0000000000000..36faf31fb24f1
--- /dev/null
+++ b/src/test/rustdoc/document-private.rs
@@ -0,0 +1,213 @@
+// compile-flags: --document-private-items
+#![crate_name = "foo"]
+
+pub mod outmost_mod {
+ pub mod outer_mod {
+ pub mod inner_mod {
+ /// This function is visible within `outer_mod`
+ pub(in crate::outmost_mod::outer_mod) fn outer_mod_visible_fn() {}
+
+ /// This function is visible to the entire crate
+ pub(crate) fn crate_visible_fn() {}
+
+ /// This function is visible within `outer_mod`
+ pub(super) fn super_mod_visible_fn() {
+ /// This function is visible since we're in the same `mod`
+ inner_mod_visible_fn();
+ }
+
+ /// This function is visible only within `inner_mod`,
+ /// which is the same as leaving it private.
+ pub(self) fn inner_mod_visible_fn() {}
+
+ pub mod inmost_mod {
+ // @has 'foo/outmost_mod/outer_mod/inner_mod/inmost_mod/struct.Foo.html'
+ // @count - '//*[@class="visibility"]' 7
+ pub struct Boo {
+ /// rhubarb rhubarb rhubarb
+ // @matches - '//*[@class="visibility"]' 'Visibility: private'
+ alpha: usize,
+ /// durian durian durian
+ pub beta: usize,
+ /// sasquatch sasquatch sasquatch
+ pub(crate) gamma: usize,
+ }
+
+ impl Boo {
+ /// Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium
+ /// doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore
+ /// veritatis et quasi architecto
+ pub fn new() -> Foo {
+ Foo(0)
+ }
+
+ /// beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia
+ /// sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos,
+ /// qui ratione voluptatem sequi
+ ///
+ /// # Examples:
+ ///
+ ///
+ /// ```no_run
+ /// not_pub()
+ /// ```
+ #[deprecated(since = "0.2.1", note = "The rust_foo version is more advanced")]
+ fn not_pub() {}
+
+ /// beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia
+ /// sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos,
+ /// qui ratione voluptatem sequi
+ pub(crate) fn pub_crate() {}
+
+ /// beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia
+ /// sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos,
+ /// qui ratione voluptatem sequi
+ pub(super) fn pub_super() {}
+
+ /// beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia
+ /// sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos,
+ /// qui ratione voluptatem sequi
+ pub(self) fn pub_self() {}
+
+ /// beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia
+ /// sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos,
+ /// qui ratione voluptatem sequi
+ pub(in crate::outmost_mod::outer_mod) fn pub_inner_mod() {}
+ }
+
+ pub struct Foo(
+ /// rhubarb rhubarb rhubarb
+ usize,
+ /// durian durian durian
+ pub usize,
+ /// sasquatch sasqutch sasquatch
+ pub(crate) usize,
+ );
+
+ impl Foo {
+ /// Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium
+ /// doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore
+ /// veritatis et quasi architecto
+ pub fn new() -> Foo {
+ Foo(0)
+ }
+
+ /// beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia
+ /// sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos,
+ /// qui ratione voluptatem sequi
+ ///
+ /// # Examples:
+ ///
+ ///
+ /// ```no_run
+ /// not_pub()
+ /// ```
+ #[deprecated(since = "0.2.1", note = "The rust_foo version is more advanced")]
+ fn not_pub() {}
+
+ /// beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia
+ /// sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos,
+ /// qui ratione voluptatem sequi
+ pub(crate) fn pub_crate() {}
+
+ /// beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia
+ /// sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos,
+ /// qui ratione voluptatem sequi
+ pub(super) fn pub_super() {}
+
+ /// beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia
+ /// sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos,
+ /// qui ratione voluptatem sequi
+ pub(self) fn pub_self() {}
+
+ /// beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia
+ /// sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos,
+ /// qui ratione voluptatem sequi
+ pub(in crate::outmost_mod::outer_mod) fn pub_inner_mod() {}
+ }
+
+ /// ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
+ /// Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam
+ /// nihil molestiae consequatur,
+ pub enum Baz {
+ Size(usize),
+ }
+
+ pub enum Bar {
+ /// ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi
+ /// Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam
+ /// nihil molestiae consequatur,
+ Fizz,
+ /// ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi
+ /// Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam
+ /// nihil molestiae consequatur,
+ Pop,
+ /// ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi
+ /// Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam
+ /// nihil molestiae consequatur,
+ Bang,
+ }
+
+ impl Bar {
+ /// Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium
+ /// doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore
+ /// veritatis et quasi architecto
+ pub fn new() -> Bar {
+ Fizz
+ }
+
+ /// beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia
+ /// sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos,
+ /// qui ratione voluptatem sequi
+ ///
+ /// # Examples:
+ ///
+ ///
+ /// ```no_run
+ /// not_pub()
+ /// ```
+ #[deprecated(since = "0.2.1", note = "The rust_foo version is more advanced")]
+ fn not_pub() {}
+
+ /// beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia
+ /// sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos,
+ /// qui ratione voluptatem sequi
+ pub(crate) fn pub_crate() {}
+
+ /// beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia
+ /// sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos,
+ /// qui ratione voluptatem sequi
+ pub(super) fn pub_super() {}
+
+ /// beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia
+ /// sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos,
+ /// qui ratione voluptatem sequi
+ pub(self) fn pub_self() {}
+
+ /// beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia
+ /// sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos,
+ /// qui ratione voluptatem sequi
+ pub(in crate::outmost_mod::outer_mod) fn pub_inner_mod() {}
+ }
+
+ pub trait Zepp {
+ fn required_method();
+
+ fn optional_method() {}
+ }
+
+ /// beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas
+ /// sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos,
+ /// qui ratione voluptatem sequi
+ pub struct Zeppish;
+
+ impl Zepp for Zeppish {
+ /// beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia
+ /// sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos,
+ /// qui ratione voluptatem sequi
+ fn required_method() {}
+ }
+ }
+ }
+ }
+}