diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs index 67fc71665ccf7..a89ed7c7ed454 100644 --- a/src/librustdoc/passes/html_tags.rs +++ b/src/librustdoc/passes/html_tags.rs @@ -184,7 +184,60 @@ fn extract_html_tag( } drop_tag(tags, tag_name, r, f); } else { - tags.push((tag_name, r)); + let mut is_self_closing = false; + let mut quote_pos = None; + if c != '>' { + let mut quote = None; + let mut after_eq = false; + for (i, c) in text[pos..].char_indices() { + if !c.is_whitespace() { + if let Some(q) = quote { + if c == q { + quote = None; + quote_pos = None; + after_eq = false; + } + } else if c == '>' { + break; + } else if c == '/' && !after_eq { + is_self_closing = true; + } else { + if is_self_closing { + is_self_closing = false; + } + if (c == '"' || c == '\'') && after_eq { + quote = Some(c); + quote_pos = Some(pos + i); + } else if c == '=' { + after_eq = true; + } + } + } else if quote.is_none() { + after_eq = false; + } + } + } + if let Some(quote_pos) = quote_pos { + let qr = Range { start: quote_pos, end: quote_pos }; + f( + &format!("unclosed quoted HTML attribute on tag `{}`", tag_name), + &qr, + false, + ); + } + if is_self_closing { + // https://html.spec.whatwg.org/#parse-error-non-void-html-element-start-tag-with-trailing-solidus + let valid = ALLOWED_UNCLOSED.contains(&&tag_name[..]) + || tags.iter().take(pos + 1).any(|(at, _)| { + let at = at.to_lowercase(); + at == "svg" || at == "math" + }); + if !valid { + f(&format!("invalid self-closing HTML tag `{}`", tag_name), &r, false); + } + } else { + tags.push((tag_name, r)); + } } } break; diff --git a/src/test/rustdoc-ui/invalid-html-self-closing-tag.rs b/src/test/rustdoc-ui/invalid-html-self-closing-tag.rs new file mode 100644 index 0000000000000..d973a53cbc7ce --- /dev/null +++ b/src/test/rustdoc-ui/invalid-html-self-closing-tag.rs @@ -0,0 +1,70 @@ +#![deny(rustdoc::invalid_html_tags)] + +///

+//~^ ERROR invalid self-closing HTML tag `p` +pub struct A; + +///

+//~^ ERROR invalid self-closing HTML tag `p` +pub struct B; + +///

+//~^ ERROR invalid self-closing HTML tag `p` +pub struct C; + +///

+//~^ ERROR invalid self-closing HTML tag `p` +pub struct D; + +///

+pub struct G; + +///

+//~^ ERROR invalid self-closing HTML tag `p` +pub struct H; + +///

+//~^ ERROR invalid self-closing HTML tag `p` +pub struct I; + +///
+pub struct J; + +/// +pub struct K; + +/// +pub struct L; + +/// +//~^ ERROR invalid self-closing HTML tag `a` +pub struct M; + +/// +//~^ ERROR invalid self-closing HTML tag `a` +pub struct N; + +/// +//~^ ERROR invalid self-closing HTML tag `a` +pub struct O; + +/// +pub struct P; + +/// +pub struct Q; + +/// +//~^ ERROR unclosed HTML tag `rect` +pub struct R; + +/// +pub struct S; diff --git a/src/test/rustdoc-ui/invalid-html-self-closing-tag.stderr b/src/test/rustdoc-ui/invalid-html-self-closing-tag.stderr new file mode 100644 index 0000000000000..e45edfb43ff8e --- /dev/null +++ b/src/test/rustdoc-ui/invalid-html-self-closing-tag.stderr @@ -0,0 +1,80 @@ +error: invalid self-closing HTML tag `p` + --> $DIR/invalid-html-self-closing-tag.rs:3:5 + | +LL | ///

+ | ^^ + | +note: the lint level is defined here + --> $DIR/invalid-html-self-closing-tag.rs:1:9 + | +LL | #![deny(rustdoc::invalid_html_tags)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: invalid self-closing HTML tag `p` + --> $DIR/invalid-html-self-closing-tag.rs:7:5 + | +LL | ///

+ | ^^ + +error: invalid self-closing HTML tag `p` + --> $DIR/invalid-html-self-closing-tag.rs:11:5 + | +LL | ///

+ | ^^ + +error: invalid self-closing HTML tag `p` + --> $DIR/invalid-html-self-closing-tag.rs:15:5 + | +LL | ///

+ | ^^ + +error: unclosed quoted HTML attribute on tag `p` + --> $DIR/invalid-html-self-closing-tag.rs:19:14 + | +LL | ///

+ | ^^ + +error: invalid self-closing HTML tag `p` + --> $DIR/invalid-html-self-closing-tag.rs:34:5 + | +LL | ///

+ | ^^ + +error: invalid self-closing HTML tag `a` + --> $DIR/invalid-html-self-closing-tag.rs:47:5 + | +LL | /// + | ^^ + +error: invalid self-closing HTML tag `a` + --> $DIR/invalid-html-self-closing-tag.rs:51:5 + | +LL | /// + | ^^ + +error: invalid self-closing HTML tag `a` + --> $DIR/invalid-html-self-closing-tag.rs:55:5 + | +LL | /// + | ^^ + +error: unclosed HTML tag `rect` + --> $DIR/invalid-html-self-closing-tag.rs:65:10 + | +LL | /// + | ^^^^^ + +error: aborting due to 12 previous errors +