Skip to content

Commit 6d7aa47

Browse files
committed
Auto merge of rust-lang#93605 - notriddle:notriddle/rustdoc-html-tags-resolve, r=GuillaumeGomez
rustdoc: resolve intra-doc links when checking HTML Similar to rust-lang#86451 CC rust-lang#67799 Given this test case: ```rust #![warn(rustdoc::invalid_html_tags)] #![warn(rustdoc::broken_intra_doc_links)] pub struct ExistentStruct<T>(T); /// This [test][ExistentStruct<i32>] thing! pub struct NoError; ``` This pull request silences the following, spurious warning: ```text warning: unclosed HTML tag `i32` --> test.rs:6:31 | 6 | /// This [test][ExistentStruct<i32>] thing! | ^^^^^ | note: the lint level is defined here --> test.rs:1:9 | 1 | #![warn(rustdoc::invalid_html_tags)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try marking as source code | 6 | /// This [test][`ExistentStruct<i32>`] thing! | + + warning: 1 warning emitted ```
2 parents a6fe969 + 1a6d41c commit 6d7aa47

File tree

3 files changed

+120
-2
lines changed

3 files changed

+120
-2
lines changed

src/librustdoc/passes/html_tags.rs

+26-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::core::DocContext;
55
use crate::html::markdown::main_body_opts;
66
use crate::visit::DocVisitor;
77

8-
use pulldown_cmark::{Event, Parser, Tag};
8+
use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag};
99

1010
use std::iter::Peekable;
1111
use std::ops::Range;
@@ -249,7 +249,31 @@ impl<'a, 'tcx> DocVisitor for InvalidHtmlTagsLinter<'a, 'tcx> {
249249
let mut is_in_comment = None;
250250
let mut in_code_block = false;
251251

252-
let p = Parser::new_ext(&dox, main_body_opts()).into_offset_iter();
252+
let link_names = item.link_names(&self.cx.cache);
253+
254+
let mut replacer = |broken_link: BrokenLink<'_>| {
255+
if let Some(link) =
256+
link_names.iter().find(|link| *link.original_text == *broken_link.reference)
257+
{
258+
Some((link.href.as_str().into(), link.new_text.as_str().into()))
259+
} else if matches!(
260+
&broken_link.link_type,
261+
LinkType::Reference | LinkType::ReferenceUnknown
262+
) {
263+
// If the link is shaped [like][this], suppress any broken HTML in the [this] part.
264+
// The `broken_intra_doc_links` will report typos in there anyway.
265+
Some((
266+
broken_link.reference.to_string().into(),
267+
broken_link.reference.to_string().into(),
268+
))
269+
} else {
270+
None
271+
}
272+
};
273+
274+
let p =
275+
Parser::new_with_broken_link_callback(&dox, main_body_opts(), Some(&mut replacer))
276+
.into_offset_iter();
253277

254278
for (event, range) in p {
255279
match event {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#![deny(rustdoc::invalid_html_tags)]
2+
#![deny(rustdoc::broken_intra_doc_links)]
3+
4+
pub struct ExistentStruct<T>(T);
5+
6+
/// This [test][ExistentStruct<i32>] thing!
7+
pub struct NoError;
8+
9+
/// This [ExistentStruct<i32>] thing!
10+
//~^ ERROR unclosed HTML tag `i32`
11+
pub struct PartialErrorOnlyHtml;
12+
13+
/// This [test][NonExistentStruct<i32>] thing!
14+
//~^ ERROR unresolved link
15+
pub struct PartialErrorOnlyResolve;
16+
17+
/// This [NonExistentStruct2<i32>] thing!
18+
//~^ ERROR unclosed HTML tag `i32`
19+
//~| ERROR unresolved link
20+
pub struct YesError;
21+
22+
/// This [NonExistentStruct3<i32>][] thing!
23+
//~^ ERROR unclosed HTML tag `i32`
24+
//~| ERROR unresolved link
25+
pub struct YesErrorCollapsed;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
error: unresolved link to `NonExistentStruct`
2+
--> $DIR/html-as-generics-intra-doc.rs:13:17
3+
|
4+
LL | /// This [test][NonExistentStruct<i32>] thing!
5+
| ^^^^^^^^^^^^^^^^^^^^^^ no item named `NonExistentStruct` in scope
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/html-as-generics-intra-doc.rs:2:9
9+
|
10+
LL | #![deny(rustdoc::broken_intra_doc_links)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
13+
14+
error: unresolved link to `NonExistentStruct2`
15+
--> $DIR/html-as-generics-intra-doc.rs:17:11
16+
|
17+
LL | /// This [NonExistentStruct2<i32>] thing!
18+
| ^^^^^^^^^^^^^^^^^^^^^^^ no item named `NonExistentStruct2` in scope
19+
|
20+
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
21+
22+
error: unresolved link to `NonExistentStruct3`
23+
--> $DIR/html-as-generics-intra-doc.rs:22:11
24+
|
25+
LL | /// This [NonExistentStruct3<i32>][] thing!
26+
| ^^^^^^^^^^^^^^^^^^^^^^^ no item named `NonExistentStruct3` in scope
27+
|
28+
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
29+
30+
error: unclosed HTML tag `i32`
31+
--> $DIR/html-as-generics-intra-doc.rs:9:25
32+
|
33+
LL | /// This [ExistentStruct<i32>] thing!
34+
| ^^^^^
35+
|
36+
note: the lint level is defined here
37+
--> $DIR/html-as-generics-intra-doc.rs:1:9
38+
|
39+
LL | #![deny(rustdoc::invalid_html_tags)]
40+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
41+
help: try marking as source code
42+
|
43+
LL | /// This [`ExistentStruct<i32>`] thing!
44+
| + +
45+
46+
error: unclosed HTML tag `i32`
47+
--> $DIR/html-as-generics-intra-doc.rs:17:29
48+
|
49+
LL | /// This [NonExistentStruct2<i32>] thing!
50+
| ^^^^^
51+
|
52+
help: try marking as source code
53+
|
54+
LL | /// This [`NonExistentStruct2<i32>`] thing!
55+
| + +
56+
57+
error: unclosed HTML tag `i32`
58+
--> $DIR/html-as-generics-intra-doc.rs:22:29
59+
|
60+
LL | /// This [NonExistentStruct3<i32>][] thing!
61+
| ^^^^^
62+
|
63+
help: try marking as source code
64+
|
65+
LL | /// This [`NonExistentStruct3<i32>`][] thing!
66+
| + +
67+
68+
error: aborting due to 6 previous errors
69+

0 commit comments

Comments
 (0)