Skip to content

Commit ee58559

Browse files
authored
Rollup merge of rust-lang#65857 - kinnison:kinnison/issue-55364, r=Manisheart,GuillaumeGomez
rustdoc: Resolve module-level doc references more locally Module level docs should resolve intra-doc links as locally as possible. As such, this commit alters the heuristic for finding intra-doc links such that we attempt to resolve names mentioned in *inner* documentation comments within the (sub-)module rather that from the context of its parent. I'm hoping that this fixes rust-lang#55364 though right now I'm not sure it's the right fix. r? @GuillaumeGomez
2 parents 19550e4 + c24a099 commit ee58559

File tree

2 files changed

+109
-4
lines changed

2 files changed

+109
-4
lines changed

src/librustdoc/passes/collect_intra_doc_links.rs

+21-4
Original file line numberDiff line numberDiff line change
@@ -322,9 +322,26 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
322322
continue;
323323
}
324324

325+
// In order to correctly resolve intra-doc-links we need to
326+
// pick a base AST node to work from. If the documentation for
327+
// this module came from an inner comment (//!) then we anchor
328+
// our name resolution *inside* the module. If, on the other
329+
// hand it was an outer comment (///) then we anchor the name
330+
// resolution in the parent module on the basis that the names
331+
// used are more likely to be intended to be parent names. For
332+
// this, we set base_node to None for inner comments since
333+
// we've already pushed this node onto the resolution stack but
334+
// for outer comments we explicitly try and resolve against the
335+
// parent_node first.
336+
let base_node = if item.is_mod() && item.attrs.inner_docs {
337+
None
338+
} else {
339+
parent_node
340+
};
341+
325342
match kind {
326343
Some(ns @ ValueNS) => {
327-
if let Ok(res) = self.resolve(path_str, ns, &current_item, parent_node) {
344+
if let Ok(res) = self.resolve(path_str, ns, &current_item, base_node) {
328345
res
329346
} else {
330347
resolution_failure(cx, &item, path_str, &dox, link_range);
@@ -335,7 +352,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
335352
}
336353
}
337354
Some(ns @ TypeNS) => {
338-
if let Ok(res) = self.resolve(path_str, ns, &current_item, parent_node) {
355+
if let Ok(res) = self.resolve(path_str, ns, &current_item, base_node) {
339356
res
340357
} else {
341358
resolution_failure(cx, &item, path_str, &dox, link_range);
@@ -348,10 +365,10 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
348365
let candidates = PerNS {
349366
macro_ns: macro_resolve(cx, path_str).map(|res| (res, None)),
350367
type_ns: self
351-
.resolve(path_str, TypeNS, &current_item, parent_node)
368+
.resolve(path_str, TypeNS, &current_item, base_node)
352369
.ok(),
353370
value_ns: self
354-
.resolve(path_str, ValueNS, &current_item, parent_node)
371+
.resolve(path_str, ValueNS, &current_item, base_node)
355372
.ok()
356373
.and_then(|(res, fragment)| {
357374
// Constructors are picked up in the type namespace.

src/test/rustdoc/issue-55364.rs

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// ignore-tidy-linelength
2+
3+
// First a module with inner documentation
4+
5+
// @has issue_55364/subone/index.html
6+
// These foo/bar links in the module's documentation should refer inside `subone`
7+
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subone/fn.foo.html"]' 'foo'
8+
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subone/fn.bar.html"]' 'bar'
9+
pub mod subone {
10+
//! See either [foo] or [bar].
11+
12+
// This should refer to subone's `bar`
13+
// @has issue_55364/subone/fn.foo.html
14+
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subone/fn.bar.html"]' 'bar'
15+
/// See [bar]
16+
pub fn foo() {}
17+
// This should refer to subone's `foo`
18+
// @has issue_55364/subone/fn.bar.html
19+
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subone/fn.foo.html"]' 'foo'
20+
/// See [foo]
21+
pub fn bar() {}
22+
}
23+
24+
// A module with outer documentation
25+
26+
// @has issue_55364/subtwo/index.html
27+
// These foo/bar links in the module's documentation should not reference inside `subtwo`
28+
// @!has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subtwo/fn.foo.html"]' 'foo'
29+
// @!has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subtwo/fn.bar.html"]' 'bar'
30+
// Instead it should be referencing the top level functions
31+
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/fn.foo.html"]' 'foo'
32+
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/fn.bar.html"]' 'bar'
33+
// Though there should be such links later
34+
// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td/a[@class="fn"][@href="fn.foo.html"]' 'foo'
35+
// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td/a[@class="fn"][@href="fn.bar.html"]' 'bar'
36+
/// See either [foo] or [bar].
37+
pub mod subtwo {
38+
39+
// Despite the module's docs referring to the top level foo/bar,
40+
// this should refer to subtwo's `bar`
41+
// @has issue_55364/subtwo/fn.foo.html
42+
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subtwo/fn.bar.html"]' 'bar'
43+
/// See [bar]
44+
pub fn foo() {}
45+
// Despite the module's docs referring to the top level foo/bar,
46+
// this should refer to subtwo's `foo`
47+
// @has issue_55364/subtwo/fn.bar.html
48+
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subtwo/fn.foo.html"]' 'foo'
49+
/// See [foo]
50+
pub fn bar() {}
51+
}
52+
53+
// These are the function referred to by the module above with outer docs
54+
55+
/// See [bar]
56+
pub fn foo() {}
57+
/// See [foo]
58+
pub fn bar() {}
59+
60+
// This module refers to the outer foo/bar by means of `super::`
61+
62+
// @has issue_55364/subthree/index.html
63+
// This module should also refer to the top level foo/bar
64+
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/fn.foo.html"]' 'foo'
65+
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/fn.bar.html"]' 'bar'
66+
pub mod subthree {
67+
//! See either [foo][super::foo] or [bar][super::bar]
68+
}
69+
70+
// Next we go *deeper* - In order to ensure it's not just "this or parent"
71+
// we test `crate::` and a `super::super::...` chain
72+
// @has issue_55364/subfour/subfive/subsix/subseven/subeight/index.html
73+
// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td[@class="docblock-short"]//a[@href="../../../../../../issue_55364/subone/fn.foo.html"]' 'other foo'
74+
// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td[@class="docblock-short"]//a[@href="../../../../../../issue_55364/subtwo/fn.bar.html"]' 'other bar'
75+
pub mod subfour {
76+
pub mod subfive {
77+
pub mod subsix {
78+
pub mod subseven {
79+
pub mod subeight {
80+
/// See [other foo][crate::subone::foo]
81+
pub fn foo() {}
82+
/// See [other bar][super::super::super::super::super::subtwo::bar]
83+
pub fn bar() {}
84+
}
85+
}
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)