mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-04 05:57:36 +00:00
Generate docs for links to private items when passed --document-private
- Pass around document_private a lot more - Add tests + Add tests for intra-doc links to private items + Add ignored tests for warnings in reference links
This commit is contained in:
parent
6f8bec9399
commit
20552c811a
@ -123,10 +123,6 @@ pub struct Options {
|
|||||||
///
|
///
|
||||||
/// Be aware: This option can come both from the CLI and from crate attributes!
|
/// Be aware: This option can come both from the CLI and from crate attributes!
|
||||||
pub default_passes: DefaultPassOption,
|
pub default_passes: DefaultPassOption,
|
||||||
/// Document items that have lower than `pub` visibility.
|
|
||||||
pub document_private: bool,
|
|
||||||
/// Document items that have `doc(hidden)`.
|
|
||||||
pub document_hidden: bool,
|
|
||||||
/// Any passes manually selected by the user.
|
/// Any passes manually selected by the user.
|
||||||
///
|
///
|
||||||
/// Be aware: This option can come both from the CLI and from crate attributes!
|
/// Be aware: This option can come both from the CLI and from crate attributes!
|
||||||
@ -177,8 +173,6 @@ impl fmt::Debug for Options {
|
|||||||
.field("test_args", &self.test_args)
|
.field("test_args", &self.test_args)
|
||||||
.field("persist_doctests", &self.persist_doctests)
|
.field("persist_doctests", &self.persist_doctests)
|
||||||
.field("default_passes", &self.default_passes)
|
.field("default_passes", &self.default_passes)
|
||||||
.field("document_private", &self.document_private)
|
|
||||||
.field("document_hidden", &self.document_hidden)
|
|
||||||
.field("manual_passes", &self.manual_passes)
|
.field("manual_passes", &self.manual_passes)
|
||||||
.field("display_warnings", &self.display_warnings)
|
.field("display_warnings", &self.display_warnings)
|
||||||
.field("show_coverage", &self.show_coverage)
|
.field("show_coverage", &self.show_coverage)
|
||||||
@ -250,6 +244,10 @@ pub struct RenderOptions {
|
|||||||
pub generate_search_filter: bool,
|
pub generate_search_filter: bool,
|
||||||
/// Option (disabled by default) to generate files used by RLS and some other tools.
|
/// Option (disabled by default) to generate files used by RLS and some other tools.
|
||||||
pub generate_redirect_pages: bool,
|
pub generate_redirect_pages: bool,
|
||||||
|
/// Document items that have lower than `pub` visibility.
|
||||||
|
pub document_private: bool,
|
||||||
|
/// Document items that have `doc(hidden)`.
|
||||||
|
pub document_hidden: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Options {
|
impl Options {
|
||||||
@ -567,8 +565,6 @@ impl Options {
|
|||||||
should_test,
|
should_test,
|
||||||
test_args,
|
test_args,
|
||||||
default_passes,
|
default_passes,
|
||||||
document_private,
|
|
||||||
document_hidden,
|
|
||||||
manual_passes,
|
manual_passes,
|
||||||
display_warnings,
|
display_warnings,
|
||||||
show_coverage,
|
show_coverage,
|
||||||
@ -597,6 +593,8 @@ impl Options {
|
|||||||
markdown_playground_url,
|
markdown_playground_url,
|
||||||
generate_search_filter,
|
generate_search_filter,
|
||||||
generate_redirect_pages,
|
generate_redirect_pages,
|
||||||
|
document_private,
|
||||||
|
document_hidden,
|
||||||
},
|
},
|
||||||
output_format,
|
output_format,
|
||||||
})
|
})
|
||||||
|
@ -62,6 +62,8 @@ pub struct DocContext<'tcx> {
|
|||||||
// FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set.
|
// FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set.
|
||||||
pub generated_synthetics: RefCell<FxHashSet<(Ty<'tcx>, DefId)>>,
|
pub generated_synthetics: RefCell<FxHashSet<(Ty<'tcx>, DefId)>>,
|
||||||
pub auto_traits: Vec<DefId>,
|
pub auto_traits: Vec<DefId>,
|
||||||
|
/// The options given to rustdoc that could be relevant to a pass.
|
||||||
|
pub render_options: RenderOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> DocContext<'tcx> {
|
impl<'tcx> DocContext<'tcx> {
|
||||||
@ -281,8 +283,6 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
|||||||
describe_lints,
|
describe_lints,
|
||||||
lint_cap,
|
lint_cap,
|
||||||
mut default_passes,
|
mut default_passes,
|
||||||
mut document_private,
|
|
||||||
document_hidden,
|
|
||||||
mut manual_passes,
|
mut manual_passes,
|
||||||
display_warnings,
|
display_warnings,
|
||||||
render_options,
|
render_options,
|
||||||
@ -448,6 +448,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
|||||||
.cloned()
|
.cloned()
|
||||||
.filter(|trait_def_id| tcx.trait_is_auto(*trait_def_id))
|
.filter(|trait_def_id| tcx.trait_is_auto(*trait_def_id))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
render_options,
|
||||||
};
|
};
|
||||||
debug!("crate: {:?}", tcx.hir().krate());
|
debug!("crate: {:?}", tcx.hir().krate());
|
||||||
|
|
||||||
@ -524,7 +525,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
|||||||
}
|
}
|
||||||
|
|
||||||
if attr.is_word() && name == sym::document_private_items {
|
if attr.is_word() && name == sym::document_private_items {
|
||||||
document_private = true;
|
ctxt.render_options.document_private = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,9 +545,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
|||||||
for p in passes {
|
for p in passes {
|
||||||
let run = match p.condition {
|
let run = match p.condition {
|
||||||
Always => true,
|
Always => true,
|
||||||
WhenDocumentPrivate => document_private,
|
WhenDocumentPrivate => ctxt.render_options.document_private,
|
||||||
WhenNotDocumentPrivate => !document_private,
|
WhenNotDocumentPrivate => !ctxt.render_options.document_private,
|
||||||
WhenNotDocumentHidden => !document_hidden,
|
WhenNotDocumentHidden => !ctxt.render_options.document_hidden,
|
||||||
};
|
};
|
||||||
if run {
|
if run {
|
||||||
debug!("running pass {}", p.pass.name);
|
debug!("running pass {}", p.pass.name);
|
||||||
@ -556,7 +557,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
|||||||
|
|
||||||
ctxt.sess().abort_if_errors();
|
ctxt.sess().abort_if_errors();
|
||||||
|
|
||||||
(krate, ctxt.renderinfo.into_inner(), render_options)
|
(krate, ctxt.renderinfo.into_inner(), ctxt.render_options)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -468,7 +468,7 @@ impl clean::Path {
|
|||||||
|
|
||||||
pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
|
pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
|
||||||
let cache = cache();
|
let cache = cache();
|
||||||
if !did.is_local() && !cache.access_levels.is_public(did) {
|
if !did.is_local() && !cache.access_levels.is_public(did) && !cache.document_private {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,6 +469,7 @@ pub fn run(
|
|||||||
static_root_path,
|
static_root_path,
|
||||||
generate_search_filter,
|
generate_search_filter,
|
||||||
generate_redirect_pages,
|
generate_redirect_pages,
|
||||||
|
document_private,
|
||||||
..
|
..
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
@ -546,7 +547,7 @@ pub fn run(
|
|||||||
scx.ensure_dir(&dst)?;
|
scx.ensure_dir(&dst)?;
|
||||||
krate = sources::render(&dst, &mut scx, krate)?;
|
krate = sources::render(&dst, &mut scx, krate)?;
|
||||||
let (new_crate, index, cache) =
|
let (new_crate, index, cache) =
|
||||||
Cache::from_krate(renderinfo, &extern_html_root_urls, &dst, krate);
|
Cache::from_krate(renderinfo, document_private, &extern_html_root_urls, &dst, krate);
|
||||||
krate = new_crate;
|
krate = new_crate;
|
||||||
let cache = Arc::new(cache);
|
let cache = Arc::new(cache);
|
||||||
let mut cx = Context {
|
let mut cx = Context {
|
||||||
|
@ -91,6 +91,10 @@ crate struct Cache {
|
|||||||
/// The version of the crate being documented, if given from the `--crate-version` flag.
|
/// The version of the crate being documented, if given from the `--crate-version` flag.
|
||||||
pub crate_version: Option<String>,
|
pub crate_version: Option<String>,
|
||||||
|
|
||||||
|
/// Whether to document private items.
|
||||||
|
/// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions.
|
||||||
|
pub document_private: bool,
|
||||||
|
|
||||||
// Private fields only used when initially crawling a crate to build a cache
|
// Private fields only used when initially crawling a crate to build a cache
|
||||||
stack: Vec<String>,
|
stack: Vec<String>,
|
||||||
parent_stack: Vec<DefId>,
|
parent_stack: Vec<DefId>,
|
||||||
@ -126,6 +130,7 @@ crate struct Cache {
|
|||||||
impl Cache {
|
impl Cache {
|
||||||
pub fn from_krate(
|
pub fn from_krate(
|
||||||
renderinfo: RenderInfo,
|
renderinfo: RenderInfo,
|
||||||
|
document_private: bool,
|
||||||
extern_html_root_urls: &BTreeMap<String, String>,
|
extern_html_root_urls: &BTreeMap<String, String>,
|
||||||
dst: &Path,
|
dst: &Path,
|
||||||
mut krate: clean::Crate,
|
mut krate: clean::Crate,
|
||||||
@ -160,6 +165,7 @@ impl Cache {
|
|||||||
stripped_mod: false,
|
stripped_mod: false,
|
||||||
access_levels,
|
access_levels,
|
||||||
crate_version: krate.version.take(),
|
crate_version: krate.version.take(),
|
||||||
|
document_private,
|
||||||
orphan_impl_items: Vec::new(),
|
orphan_impl_items: Vec::new(),
|
||||||
orphan_trait_impls: Vec::new(),
|
orphan_trait_impls: Vec::new(),
|
||||||
traits: krate.external_traits.replace(Default::default()),
|
traits: krate.external_traits.replace(Default::default()),
|
||||||
|
@ -34,7 +34,6 @@ extern crate rustc_metadata;
|
|||||||
extern crate rustc_middle;
|
extern crate rustc_middle;
|
||||||
extern crate rustc_mir;
|
extern crate rustc_mir;
|
||||||
extern crate rustc_parse;
|
extern crate rustc_parse;
|
||||||
extern crate rustc_privacy;
|
|
||||||
extern crate rustc_resolve;
|
extern crate rustc_resolve;
|
||||||
extern crate rustc_session;
|
extern crate rustc_session;
|
||||||
extern crate rustc_span as rustc_span;
|
extern crate rustc_span as rustc_span;
|
||||||
|
@ -204,7 +204,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||||||
return Ok((res, Some(path_str.to_owned())));
|
return Ok((res, Some(path_str.to_owned())));
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
debug!("failed to resolve {} in namespace {:?} (got {:?})", path_str, ns, other);
|
debug!(
|
||||||
|
"failed to resolve {} in namespace {:?} (got {:?})",
|
||||||
|
path_str, ns, other
|
||||||
|
);
|
||||||
debug!("extra_fragment is {:?}", extra_fragment);
|
debug!("extra_fragment is {:?}", extra_fragment);
|
||||||
return Ok((res, extra_fragment.clone()));
|
return Ok((res, extra_fragment.clone()));
|
||||||
}
|
}
|
||||||
@ -564,8 +567,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
|
|||||||
let mut path_str;
|
let mut path_str;
|
||||||
let (res, fragment) = {
|
let (res, fragment) = {
|
||||||
let mut kind = None;
|
let mut kind = None;
|
||||||
path_str = if let Some(prefix) =
|
path_str = if let Some(prefix) = ["struct@", "enum@", "type@", "trait@", "union@"]
|
||||||
["struct@", "enum@", "type@", "trait@", "union@"]
|
|
||||||
.iter()
|
.iter()
|
||||||
.find(|p| link.starts_with(**p))
|
.find(|p| link.starts_with(**p))
|
||||||
{
|
{
|
||||||
@ -766,22 +768,30 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
|
|||||||
if let Res::PrimTy(_) = res {
|
if let Res::PrimTy(_) = res {
|
||||||
item.attrs.links.push((ori_link, None, fragment));
|
item.attrs.links.push((ori_link, None, fragment));
|
||||||
} else {
|
} else {
|
||||||
// ~~WRONG: TODO: I think this happens too late and we need to instead put this in `self.resolve`~~
|
debug!("linked item {} resolved to {:?}", path_str, res);
|
||||||
debug!("item {:?} resolved to {:?}", item, res);
|
|
||||||
if let Some(local) = res.opt_def_id().and_then(|def_id| def_id.as_local()) {
|
if let Some(local) = res.opt_def_id().and_then(|def_id| def_id.as_local()) {
|
||||||
|
use rustc_hir::def_id::LOCAL_CRATE;
|
||||||
|
|
||||||
let hir_id = self.cx.tcx.hir().as_local_hir_id(local);
|
let hir_id = self.cx.tcx.hir().as_local_hir_id(local);
|
||||||
if !self.cx.tcx.privacy_access_levels(rustc_hir::def_id::LOCAL_CRATE).is_exported(hir_id) {
|
if !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_id)
|
||||||
|
&& !self.cx.render_options.document_private
|
||||||
|
{
|
||||||
let item_name = item.name.as_deref().unwrap_or("<unknown>");
|
let item_name = item.name.as_deref().unwrap_or("<unknown>");
|
||||||
|
let err_msg = format!(
|
||||||
|
"public documentation for `{}` links to a private item",
|
||||||
|
item_name
|
||||||
|
);
|
||||||
build_diagnostic(
|
build_diagnostic(
|
||||||
cx,
|
cx,
|
||||||
&item,
|
&item,
|
||||||
path_str,
|
path_str,
|
||||||
&dox,
|
&dox,
|
||||||
link_range,
|
link_range,
|
||||||
&format!("public documentation for `{}` links to a private item", item_name),
|
&err_msg,
|
||||||
"this item is private",
|
"this item is private",
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let id = register_res(cx, res);
|
let id = register_res(cx, res);
|
||||||
|
10
src/test/rustdoc-ui/intra-links-private.public.stderr
Normal file
10
src/test/rustdoc-ui/intra-links-private.public.stderr
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
warning: `[DontDocMe]` public documentation for `DocMe` links to a private item
|
||||||
|
--> $DIR/intra-links-private.rs:6:11
|
||||||
|
|
|
||||||
|
LL | /// docs [DontDocMe]
|
||||||
|
| ^^^^^^^^^ this item is private
|
||||||
|
|
|
||||||
|
= note: `#[warn(intra_doc_link_resolution_failure)]` on by default
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
10
src/test/rustdoc-ui/intra-links-private.rs
Normal file
10
src/test/rustdoc-ui/intra-links-private.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// check-pass
|
||||||
|
// revisions: public private
|
||||||
|
// [private]compile-flags: --document-private-items
|
||||||
|
#![cfg_attr(private, deny(intra_doc_resolution_failure))]
|
||||||
|
|
||||||
|
/// docs [DontDocMe]
|
||||||
|
//[public]~^ WARNING `[DontDocMe]` public documentation for `DocMe` links to a private item
|
||||||
|
// FIXME: for [private] we should also make sure the link was actually generated
|
||||||
|
pub struct DocMe;
|
||||||
|
struct DontDocMe;
|
6
src/test/rustdoc-ui/reference-link-has-one-warning.rs
Normal file
6
src/test/rustdoc-ui/reference-link-has-one-warning.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// ignore-test
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
/// docs [label][with#anchor#error]
|
||||||
|
//~^ WARNING has an issue with the link anchor
|
||||||
|
pub struct S;
|
10
src/test/rustdoc-ui/reference-link-has-one-warning.stderr
Normal file
10
src/test/rustdoc-ui/reference-link-has-one-warning.stderr
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
warning: `[with#anchor#error]` has an issue with the link anchor.
|
||||||
|
--> $DIR/reference-link-has-one-warning.rs:3:18
|
||||||
|
|
|
||||||
|
LL | /// docs [label][with#anchor#error]
|
||||||
|
| ^^^^^^^^^^^^^^^^^ only one `#` is allowed in a link
|
||||||
|
|
|
||||||
|
= note: `#[warn(intra_doc_link_resolution_failure)]` on by default
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
Loading…
Reference in New Issue
Block a user