Skip to content

Commit 9be4ffa

Browse files
committed
rustdoc::hidden_intra_doc_links now correctly handles indirect modules
1 parent ad92ea5 commit 9be4ffa

File tree

7 files changed

+239
-41
lines changed

7 files changed

+239
-41
lines changed

src/librustdoc/html/format.rs

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use std::cmp::Ordering;
1111
use std::fmt::{self, Display, Write};
1212
use std::iter::{self, once};
13+
use std::ops::ControlFlow;
1314
use std::slice;
1415

1516
use itertools::{Either, Itertools};
@@ -21,7 +22,7 @@ use rustc_hir::def::DefKind;
2122
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
2223
use rustc_hir::{ConstStability, StabilityLevel, StableSince};
2324
use rustc_metadata::creader::{CStore, LoadedMacro};
24-
use rustc_middle::ty::{self, TyCtxt, TypingMode};
25+
use rustc_middle::ty::{self, ImplSubject, TyCtxt, TypingMode};
2526
use rustc_span::symbol::kw;
2627
use rustc_span::{Symbol, sym};
2728
use tracing::{debug, trace};
@@ -483,22 +484,80 @@ fn generate_item_def_id_path(
483484

484485
/// Checks if the given defid refers to an item that is unnamable, such as one defined in a const block.
485486
fn is_unnamable(tcx: TyCtxt<'_>, did: DefId) -> bool {
487+
traverse_parent(tcx, did, false, true, &|_| ControlFlow::Continue(()))
488+
}
489+
490+
pub(crate) fn traverse_parent(
491+
tcx: TyCtxt<'_>,
492+
did: DefId,
493+
if_noparent: bool,
494+
if_unnamable: bool,
495+
callback: &dyn Fn(DefId) -> ControlFlow<bool>,
496+
) -> bool {
486497
let mut cur_did = did;
487498
while let Some(parent) = tcx.opt_parent(cur_did) {
499+
if let ControlFlow::Break(x) = callback(cur_did) {
500+
return x;
501+
}
488502
match tcx.def_kind(parent) {
489503
// items defined in these can be linked to, as long as they are visible
490-
DefKind::Mod | DefKind::ForeignMod => cur_did = parent,
491-
// items in impls can be linked to,
492-
// as long as we can link to the item the impl is on.
493-
// since associated traits are not a thing,
494-
// it should not be possible to refer to an impl item if
495-
// the base type is not namable.
496-
DefKind::Impl { .. } => return false,
504+
DefKind::Mod | DefKind::ForeignMod | DefKind::Trait => cur_did = parent,
505+
// this serves both to future-proof is_unnamable for associated trait aliases,
506+
// and traverses upwards to see if the trait or type is doc(hidden)
507+
DefKind::Impl { .. } => {
508+
match tcx.impl_subject(parent).as_ref().skip_binder() {
509+
ImplSubject::Trait(trait_ref) => {
510+
// first, check if the trait fufills the criteria
511+
if traverse_parent(
512+
tcx,
513+
trait_ref.def_id,
514+
if_noparent,
515+
if_unnamable,
516+
callback,
517+
) {
518+
return true;
519+
}
520+
521+
// for trait impls on local types, we also check if the type matches the criteria
522+
if let Some(hir::Node::Item(hir::Item {
523+
kind: hir::ItemKind::Impl(hir::Impl { self_ty, .. }),
524+
..
525+
})) = tcx.hir_get_if_local(parent)
526+
&& let hir::Ty {
527+
kind:
528+
hir::TyKind::Path(hir::QPath::Resolved(
529+
_,
530+
hir::Path {
531+
res: hir::def::Res::Def(_, self_ty_def_id),
532+
..
533+
},
534+
)),
535+
..
536+
} = self_ty.peel_refs()
537+
/*&& let Some(local_def_id) = parent.as_local()
538+
&& let Some(self_ty_def_id) = tcx.typeck(local_def_id).type_dependent_def_id(self_ty.hir_id)*/
539+
{
540+
cur_did = *self_ty_def_id;
541+
continue;
542+
}
543+
return if_noparent;
544+
}
545+
ImplSubject::Inherent(ty) => {
546+
if let Some(def_id) =
547+
rustc_middle::ty::print::characteristic_def_id_of_type(ty.peel_refs())
548+
{
549+
cur_did = def_id;
550+
} else {
551+
return if_noparent;
552+
}
553+
}
554+
}
555+
}
497556
// everything else does not have docs generated for it
498-
_ => return true,
557+
_ => return if_unnamable,
499558
}
500559
}
501-
return false;
560+
return if_noparent;
502561
}
503562

504563
fn to_module_fqp(shortty: ItemType, fqp: &[Symbol]) -> &[Symbol] {

src/librustdoc/passes/collect_intra_doc_links.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use std::borrow::Cow;
66
use std::fmt::Display;
77
use std::mem;
8-
use std::ops::Range;
8+
use std::ops::{ControlFlow, Range};
99

1010
use pulldown_cmark::LinkType;
1111
use rustc_ast::util::comments::may_have_doc_links;
@@ -1351,7 +1351,8 @@ impl LinkCollector<'_, '_> {
13511351
privacy_error(self.cx, diag_info, path_str, PrivacyErrorKind::Private);
13521352
}
13531353

1354-
if self.cx.tcx.is_doc_hidden(id) && !self.cx.tcx.is_doc_hidden(src_def_id) {
1354+
if is_effectively_hidden(self.cx.tcx, id) && !is_effectively_hidden(self.cx.tcx, src_def_id)
1355+
{
13551356
privacy_error(self.cx, diag_info, path_str, PrivacyErrorKind::Hidden);
13561357
}
13571358

@@ -1596,6 +1597,13 @@ fn range_between_backticks(ori_link_range: &MarkdownLinkRange, dox: &str) -> Mar
15961597
)
15971598
}
15981599

1600+
/// Is this item or any of its ancestors doc(hidden)?
1601+
fn is_effectively_hidden(tcx: TyCtxt<'_>, id: DefId) -> bool {
1602+
crate::html::format::traverse_parent(tcx, id, false, false, &|id| {
1603+
if tcx.is_doc_hidden(id) { ControlFlow::Break(true) } else { ControlFlow::Continue(()) }
1604+
})
1605+
}
1606+
15991607
/// Returns true if we should ignore `link` due to it being unlikely
16001608
/// that it is an intra-doc link. `link` should still have disambiguators
16011609
/// if there were any.

tests/rustdoc-ui/intra-doc/link-to-hidden-144664.doc-both.stderr

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ LL | #![deny(rustdoc::hidden_intra_doc_links)]
1212
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1313

1414
error: public documentation for `link_to_hidden_144664` links to private item `crate::local_private_hidden_fn`
15-
--> $DIR/link-to-hidden-144664.rs:16:8
15+
--> $DIR/link-to-hidden-144664.rs:18:8
1616
|
1717
LL | //! * [crate::local_private_hidden_fn]
1818
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this item is private
@@ -25,31 +25,31 @@ LL | #![deny(rustdoc::private_intra_doc_links)]
2525
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2626

2727
error: non-hidden documentation for `link_to_hidden_144664` links to hidden item `crate::local_private_hidden_fn`
28-
--> $DIR/link-to-hidden-144664.rs:16:8
28+
--> $DIR/link-to-hidden-144664.rs:18:8
2929
|
3030
LL | //! * [crate::local_private_hidden_fn]
3131
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this item is hidden
3232
|
3333
= note: this link resolves only because you passed `--document-hidden-items`, but will break without
3434

3535
error: public documentation for `link_to_hidden_144664` links to private item `crate::local_private_non_hidden_fn`
36-
--> $DIR/link-to-hidden-144664.rs:19:8
36+
--> $DIR/link-to-hidden-144664.rs:22:8
3737
|
3838
LL | //! * [crate::local_private_non_hidden_fn]
3939
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this item is private
4040
|
4141
= note: this link resolves only because you passed `--document-private-items`, but will break without
4242

4343
error: non-hidden documentation for `link_to_hidden_144664` links to hidden item `nonlocal::public_hidden_fn`
44-
--> $DIR/link-to-hidden-144664.rs:21:8
44+
--> $DIR/link-to-hidden-144664.rs:24:8
4545
|
4646
LL | //! * [nonlocal::public_hidden_fn]
4747
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ this item is hidden
4848
|
4949
= note: this link resolves only because you passed `--document-hidden-items`, but will break without
5050

5151
error: unresolved link to `nonlocal::private_hidden_fn`
52-
--> $DIR/link-to-hidden-144664.rs:24:8
52+
--> $DIR/link-to-hidden-144664.rs:28:8
5353
|
5454
LL | //! * [nonlocal::private_hidden_fn]
5555
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `private_hidden_fn` in module `hidden`
@@ -61,10 +61,32 @@ LL | #![deny(rustdoc::broken_intra_doc_links)]
6161
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6262

6363
error: unresolved link to `nonlocal::private_non_hidden_fn`
64-
--> $DIR/link-to-hidden-144664.rs:26:8
64+
--> $DIR/link-to-hidden-144664.rs:30:8
6565
|
6666
LL | //! * [nonlocal::private_non_hidden_fn]
6767
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `private_non_hidden_fn` in module `hidden`
6868

69-
error: aborting due to 7 previous errors
69+
error: unresolved link to `crate::hidden_mod::a`
70+
--> $DIR/link-to-hidden-144664.rs:32:8
71+
|
72+
LL | //! * [crate::hidden_mod::a]
73+
| ^^^^^^^^^^^^^^^^^^^^ no item named `a` in module `hidden_mod`
74+
75+
error: non-hidden documentation for `link_to_hidden_144664` links to hidden item `crate::hidden_mod::b`
76+
--> $DIR/link-to-hidden-144664.rs:34:8
77+
|
78+
LL | //! * [crate::hidden_mod::b]
79+
| ^^^^^^^^^^^^^^^^^^^^ this item is hidden
80+
|
81+
= note: this link resolves only because you passed `--document-hidden-items`, but will break without
82+
83+
error: non-hidden documentation for `link_to_hidden_144664` links to hidden item `crate::hidden_mod::c`
84+
--> $DIR/link-to-hidden-144664.rs:36:8
85+
|
86+
LL | //! * [crate::hidden_mod::c]
87+
| ^^^^^^^^^^^^^^^^^^^^ this item is hidden
88+
|
89+
= note: this link resolves only because you passed `--document-hidden-items`, but will break without
90+
91+
error: aborting due to 10 previous errors
7092

tests/rustdoc-ui/intra-doc/link-to-hidden-144664.doc-hidden.stderr

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ LL | #![deny(rustdoc::hidden_intra_doc_links)]
1212
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1313

1414
error: public documentation for `link_to_hidden_144664` links to private item `crate::local_private_hidden_fn`
15-
--> $DIR/link-to-hidden-144664.rs:16:8
15+
--> $DIR/link-to-hidden-144664.rs:18:8
1616
|
1717
LL | //! * [crate::local_private_hidden_fn]
1818
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this item is private
@@ -25,31 +25,31 @@ LL | #![deny(rustdoc::private_intra_doc_links)]
2525
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2626

2727
error: non-hidden documentation for `link_to_hidden_144664` links to hidden item `crate::local_private_hidden_fn`
28-
--> $DIR/link-to-hidden-144664.rs:16:8
28+
--> $DIR/link-to-hidden-144664.rs:18:8
2929
|
3030
LL | //! * [crate::local_private_hidden_fn]
3131
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this item is hidden
3232
|
3333
= note: this link will resolve properly if you pass `--document-hidden-items`
3434

3535
error: public documentation for `link_to_hidden_144664` links to private item `crate::local_private_non_hidden_fn`
36-
--> $DIR/link-to-hidden-144664.rs:19:8
36+
--> $DIR/link-to-hidden-144664.rs:22:8
3737
|
3838
LL | //! * [crate::local_private_non_hidden_fn]
3939
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this item is private
4040
|
4141
= note: this link will resolve properly if you pass `--document-private-items`
4242

4343
error: non-hidden documentation for `link_to_hidden_144664` links to hidden item `nonlocal::public_hidden_fn`
44-
--> $DIR/link-to-hidden-144664.rs:21:8
44+
--> $DIR/link-to-hidden-144664.rs:24:8
4545
|
4646
LL | //! * [nonlocal::public_hidden_fn]
4747
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ this item is hidden
4848
|
4949
= note: this link will resolve properly if you pass `--document-hidden-items`
5050

5151
error: unresolved link to `nonlocal::private_hidden_fn`
52-
--> $DIR/link-to-hidden-144664.rs:24:8
52+
--> $DIR/link-to-hidden-144664.rs:28:8
5353
|
5454
LL | //! * [nonlocal::private_hidden_fn]
5555
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `private_hidden_fn` in module `hidden`
@@ -61,10 +61,32 @@ LL | #![deny(rustdoc::broken_intra_doc_links)]
6161
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6262

6363
error: unresolved link to `nonlocal::private_non_hidden_fn`
64-
--> $DIR/link-to-hidden-144664.rs:26:8
64+
--> $DIR/link-to-hidden-144664.rs:30:8
6565
|
6666
LL | //! * [nonlocal::private_non_hidden_fn]
6767
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `private_non_hidden_fn` in module `hidden`
6868

69-
error: aborting due to 7 previous errors
69+
error: unresolved link to `crate::hidden_mod::a`
70+
--> $DIR/link-to-hidden-144664.rs:32:8
71+
|
72+
LL | //! * [crate::hidden_mod::a]
73+
| ^^^^^^^^^^^^^^^^^^^^ no item named `a` in module `hidden_mod`
74+
75+
error: non-hidden documentation for `link_to_hidden_144664` links to hidden item `crate::hidden_mod::b`
76+
--> $DIR/link-to-hidden-144664.rs:34:8
77+
|
78+
LL | //! * [crate::hidden_mod::b]
79+
| ^^^^^^^^^^^^^^^^^^^^ this item is hidden
80+
|
81+
= note: this link will resolve properly if you pass `--document-hidden-items`
82+
83+
error: non-hidden documentation for `link_to_hidden_144664` links to hidden item `crate::hidden_mod::c`
84+
--> $DIR/link-to-hidden-144664.rs:36:8
85+
|
86+
LL | //! * [crate::hidden_mod::c]
87+
| ^^^^^^^^^^^^^^^^^^^^ this item is hidden
88+
|
89+
= note: this link will resolve properly if you pass `--document-hidden-items`
90+
91+
error: aborting due to 10 previous errors
7092

tests/rustdoc-ui/intra-doc/link-to-hidden-144664.doc-priv.stderr

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ LL | #![deny(rustdoc::hidden_intra_doc_links)]
1212
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1313

1414
error: public documentation for `link_to_hidden_144664` links to private item `crate::local_private_hidden_fn`
15-
--> $DIR/link-to-hidden-144664.rs:16:8
15+
--> $DIR/link-to-hidden-144664.rs:18:8
1616
|
1717
LL | //! * [crate::local_private_hidden_fn]
1818
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this item is private
@@ -25,31 +25,31 @@ LL | #![deny(rustdoc::private_intra_doc_links)]
2525
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2626

2727
error: non-hidden documentation for `link_to_hidden_144664` links to hidden item `crate::local_private_hidden_fn`
28-
--> $DIR/link-to-hidden-144664.rs:16:8
28+
--> $DIR/link-to-hidden-144664.rs:18:8
2929
|
3030
LL | //! * [crate::local_private_hidden_fn]
3131
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this item is hidden
3232
|
3333
= note: this link resolves only because you passed `--document-hidden-items`, but will break without
3434

3535
error: public documentation for `link_to_hidden_144664` links to private item `crate::local_private_non_hidden_fn`
36-
--> $DIR/link-to-hidden-144664.rs:19:8
36+
--> $DIR/link-to-hidden-144664.rs:22:8
3737
|
3838
LL | //! * [crate::local_private_non_hidden_fn]
3939
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this item is private
4040
|
4141
= note: this link resolves only because you passed `--document-private-items`, but will break without
4242

4343
error: non-hidden documentation for `link_to_hidden_144664` links to hidden item `nonlocal::public_hidden_fn`
44-
--> $DIR/link-to-hidden-144664.rs:21:8
44+
--> $DIR/link-to-hidden-144664.rs:24:8
4545
|
4646
LL | //! * [nonlocal::public_hidden_fn]
4747
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ this item is hidden
4848
|
4949
= note: this link resolves only because you passed `--document-hidden-items`, but will break without
5050

5151
error: unresolved link to `nonlocal::private_hidden_fn`
52-
--> $DIR/link-to-hidden-144664.rs:24:8
52+
--> $DIR/link-to-hidden-144664.rs:28:8
5353
|
5454
LL | //! * [nonlocal::private_hidden_fn]
5555
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `private_hidden_fn` in module `hidden`
@@ -61,10 +61,32 @@ LL | #![deny(rustdoc::broken_intra_doc_links)]
6161
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6262

6363
error: unresolved link to `nonlocal::private_non_hidden_fn`
64-
--> $DIR/link-to-hidden-144664.rs:26:8
64+
--> $DIR/link-to-hidden-144664.rs:30:8
6565
|
6666
LL | //! * [nonlocal::private_non_hidden_fn]
6767
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `private_non_hidden_fn` in module `hidden`
6868

69-
error: aborting due to 7 previous errors
69+
error: unresolved link to `crate::hidden_mod::a`
70+
--> $DIR/link-to-hidden-144664.rs:32:8
71+
|
72+
LL | //! * [crate::hidden_mod::a]
73+
| ^^^^^^^^^^^^^^^^^^^^ no item named `a` in module `hidden_mod`
74+
75+
error: non-hidden documentation for `link_to_hidden_144664` links to hidden item `crate::hidden_mod::b`
76+
--> $DIR/link-to-hidden-144664.rs:34:8
77+
|
78+
LL | //! * [crate::hidden_mod::b]
79+
| ^^^^^^^^^^^^^^^^^^^^ this item is hidden
80+
|
81+
= note: this link resolves only because you passed `--document-hidden-items`, but will break without
82+
83+
error: non-hidden documentation for `link_to_hidden_144664` links to hidden item `crate::hidden_mod::c`
84+
--> $DIR/link-to-hidden-144664.rs:36:8
85+
|
86+
LL | //! * [crate::hidden_mod::c]
87+
| ^^^^^^^^^^^^^^^^^^^^ this item is hidden
88+
|
89+
= note: this link resolves only because you passed `--document-hidden-items`, but will break without
90+
91+
error: aborting due to 10 previous errors
7092

0 commit comments

Comments
 (0)