Skip to content

Commit 00973d1

Browse files
committed
add new rustdoc::hidden_intra_doc_links lint
1 parent 3fb1b53 commit 00973d1

File tree

3 files changed

+40
-9
lines changed

3 files changed

+40
-9
lines changed

src/librustdoc/lint.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,17 @@ declare_rustdoc_lint! {
9797
"linking from a public item to a private one"
9898
}
9999

100+
declare_rustdoc_lint! {
101+
/// This is a subset of `broken_intra_doc_links` that warns when linking from
102+
/// a non-hidden item to a hidden one. This is a `rustdoc` only lint, see the
103+
/// documentation in the [rustdoc book].
104+
///
105+
/// [rustdoc book]: ../../../rustdoc/lints.html#hidden_intra_doc_links
106+
HIDDEN_INTRA_DOC_LINKS,
107+
Warn,
108+
"linking from a non-hidden item to a hidden one"
109+
}
110+
100111
declare_rustdoc_lint! {
101112
/// The `invalid_codeblock_attributes` lint detects code block attributes
102113
/// in documentation examples that have potentially mis-typed values. This
@@ -199,6 +210,7 @@ declare_rustdoc_lint! {
199210
pub(crate) static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
200211
vec![
201212
BROKEN_INTRA_DOC_LINKS,
213+
HIDDEN_INTRA_DOC_LINKS,
202214
PRIVATE_INTRA_DOC_LINKS,
203215
MISSING_DOC_CODE_EXAMPLES,
204216
PRIVATE_DOC_TESTS,

src/librustdoc/passes/collect_intra_doc_links.rs

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use crate::clean::utils::find_nearest_parent_module;
3434
use crate::clean::{self, Crate, Item, ItemId, ItemLink, PrimitiveType};
3535
use crate::core::DocContext;
3636
use crate::html::markdown::{MarkdownLink, MarkdownLinkRange, markdown_links};
37-
use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS};
37+
use crate::lint::{BROKEN_INTRA_DOC_LINKS, HIDDEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS};
3838
use crate::passes::Pass;
3939
use crate::visit::DocVisitor;
4040

@@ -1341,13 +1341,20 @@ impl LinkCollector<'_, '_> {
13411341
}
13421342
}
13431343

1344+
let src_def_id = diag_info.item.item_id.expect_def_id();
13441345
// item can be non-local e.g. when using `#[rustc_doc_primitive = "pointer"]`
13451346
if let Some(dst_id) = id.as_local()
1346-
&& let Some(src_id) = diag_info.item.item_id.expect_def_id().as_local()
1347+
&& let Some(src_id) = src_def_id.as_local()
13471348
&& self.cx.tcx.effective_visibilities(()).is_exported(src_id)
13481349
&& !self.cx.tcx.effective_visibilities(()).is_exported(dst_id)
13491350
{
1350-
privacy_error(self.cx, diag_info, path_str);
1351+
privacy_error(self.cx, diag_info, path_str, PrivacyErrorKind::Private);
1352+
}
1353+
1354+
if self.cx.tcx.is_doc_hidden(id)
1355+
&& !self.cx.tcx.is_doc_hidden(src_def_id)
1356+
{
1357+
privacy_error(self.cx, diag_info, path_str, PrivacyErrorKind::Hidden);
13511358
}
13521359

13531360
Some(())
@@ -2334,8 +2341,15 @@ fn suggest_disambiguator(
23342341
}
23352342
}
23362343

2344+
#[derive(Copy, Clone)]
2345+
enum PrivacyErrorKind {
2346+
Private,
2347+
Hidden,
2348+
}
2349+
23372350
/// Report a link from a public item to a private one.
2338-
fn privacy_error(cx: &DocContext<'_>, diag_info: &DiagnosticInfo<'_>, path_str: &str) {
2351+
fn privacy_error(cx: &DocContext<'_>, diag_info: &DiagnosticInfo<'_>, path_str: &str, kind: PrivacyErrorKind) {
2352+
use PrivacyErrorKind::*;
23392353
let sym;
23402354
let item_name = match diag_info.item.name {
23412355
Some(name) => {
@@ -2344,17 +2358,21 @@ fn privacy_error(cx: &DocContext<'_>, diag_info: &DiagnosticInfo<'_>, path_str:
23442358
}
23452359
None => "<unknown>",
23462360
};
2347-
let msg = format!("public documentation for `{item_name}` links to private item `{path_str}`");
2361+
let (public, private, flag, lint) = match kind {
2362+
Private => ("public", "private", "--document-private-items", PRIVATE_INTRA_DOC_LINKS),
2363+
Hidden => ("non-hidden", "hidden", "--document-hidden-items", HIDDEN_INTRA_DOC_LINKS),
2364+
};
2365+
let msg = format!("{public} documentation for `{item_name}` links to {private} item `{path_str}`");
23482366

2349-
report_diagnostic(cx.tcx, PRIVATE_INTRA_DOC_LINKS, msg, diag_info, |diag, sp, _link_range| {
2367+
report_diagnostic(cx.tcx, lint, msg, diag_info, |diag, sp, _link_range| {
23502368
if let Some(sp) = sp {
2351-
diag.span_label(sp, "this item is private");
2369+
diag.span_label(sp, format!("this item is {private}"));
23522370
}
23532371

23542372
let note_msg = if cx.render_options.document_private {
2355-
"this link resolves only because you passed `--document-private-items`, but will break without"
2373+
format!("this link resolves only because you passed `{flag}`, but will break without")
23562374
} else {
2357-
"this link will resolve properly if you pass `--document-private-items`"
2375+
format!("this link will resolve properly if you pass `{flag}`")
23582376
};
23592377
diag.note(note_msg);
23602378
});

src/librustdoc/visit_lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub(crate) struct RustdocEffectiveVisibilities {
1111
extern_public: DefIdSet,
1212
}
1313

14+
1415
macro_rules! define_method {
1516
($method:ident) => {
1617
pub(crate) fn $method(&self, tcx: TyCtxt<'_>, def_id: DefId) -> bool {

0 commit comments

Comments
 (0)