Skip to content

Commit

Permalink
Auto merge of rust-lang#93605 - notriddle:notriddle/rustdoc-html-tags…
Browse files Browse the repository at this point in the history
…-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
```
  • Loading branch information
bors committed Feb 20, 2022
2 parents a6fe969 + 1a6d41c commit 6d7aa47
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 2 deletions.
28 changes: 26 additions & 2 deletions src/librustdoc/passes/html_tags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::core::DocContext;
use crate::html::markdown::main_body_opts;
use crate::visit::DocVisitor;

use pulldown_cmark::{Event, Parser, Tag};
use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag};

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

let p = Parser::new_ext(&dox, main_body_opts()).into_offset_iter();
let link_names = item.link_names(&self.cx.cache);

let mut replacer = |broken_link: BrokenLink<'_>| {
if let Some(link) =
link_names.iter().find(|link| *link.original_text == *broken_link.reference)
{
Some((link.href.as_str().into(), link.new_text.as_str().into()))
} else if matches!(
&broken_link.link_type,
LinkType::Reference | LinkType::ReferenceUnknown
) {
// If the link is shaped [like][this], suppress any broken HTML in the [this] part.
// The `broken_intra_doc_links` will report typos in there anyway.
Some((
broken_link.reference.to_string().into(),
broken_link.reference.to_string().into(),
))
} else {
None
}
};

let p =
Parser::new_with_broken_link_callback(&dox, main_body_opts(), Some(&mut replacer))
.into_offset_iter();

for (event, range) in p {
match event {
Expand Down
25 changes: 25 additions & 0 deletions src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#![deny(rustdoc::invalid_html_tags)]
#![deny(rustdoc::broken_intra_doc_links)]

pub struct ExistentStruct<T>(T);

/// This [test][ExistentStruct<i32>] thing!
pub struct NoError;

/// This [ExistentStruct<i32>] thing!
//~^ ERROR unclosed HTML tag `i32`
pub struct PartialErrorOnlyHtml;

/// This [test][NonExistentStruct<i32>] thing!
//~^ ERROR unresolved link
pub struct PartialErrorOnlyResolve;

/// This [NonExistentStruct2<i32>] thing!
//~^ ERROR unclosed HTML tag `i32`
//~| ERROR unresolved link
pub struct YesError;

/// This [NonExistentStruct3<i32>][] thing!
//~^ ERROR unclosed HTML tag `i32`
//~| ERROR unresolved link
pub struct YesErrorCollapsed;
69 changes: 69 additions & 0 deletions src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
error: unresolved link to `NonExistentStruct`
--> $DIR/html-as-generics-intra-doc.rs:13:17
|
LL | /// This [test][NonExistentStruct<i32>] thing!
| ^^^^^^^^^^^^^^^^^^^^^^ no item named `NonExistentStruct` in scope
|
note: the lint level is defined here
--> $DIR/html-as-generics-intra-doc.rs:2:9
|
LL | #![deny(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`

error: unresolved link to `NonExistentStruct2`
--> $DIR/html-as-generics-intra-doc.rs:17:11
|
LL | /// This [NonExistentStruct2<i32>] thing!
| ^^^^^^^^^^^^^^^^^^^^^^^ no item named `NonExistentStruct2` in scope
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`

error: unresolved link to `NonExistentStruct3`
--> $DIR/html-as-generics-intra-doc.rs:22:11
|
LL | /// This [NonExistentStruct3<i32>][] thing!
| ^^^^^^^^^^^^^^^^^^^^^^^ no item named `NonExistentStruct3` in scope
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`

error: unclosed HTML tag `i32`
--> $DIR/html-as-generics-intra-doc.rs:9:25
|
LL | /// This [ExistentStruct<i32>] thing!
| ^^^^^
|
note: the lint level is defined here
--> $DIR/html-as-generics-intra-doc.rs:1:9
|
LL | #![deny(rustdoc::invalid_html_tags)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
help: try marking as source code
|
LL | /// This [`ExistentStruct<i32>`] thing!
| + +

error: unclosed HTML tag `i32`
--> $DIR/html-as-generics-intra-doc.rs:17:29
|
LL | /// This [NonExistentStruct2<i32>] thing!
| ^^^^^
|
help: try marking as source code
|
LL | /// This [`NonExistentStruct2<i32>`] thing!
| + +

error: unclosed HTML tag `i32`
--> $DIR/html-as-generics-intra-doc.rs:22:29
|
LL | /// This [NonExistentStruct3<i32>][] thing!
| ^^^^^
|
help: try marking as source code
|
LL | /// This [`NonExistentStruct3<i32>`][] thing!
| + +

error: aborting due to 6 previous errors

0 comments on commit 6d7aa47

Please sign in to comment.