about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustdoc/passes/html_tags.rs55
-rw-r--r--src/test/rustdoc-ui/invalid-html-self-closing-tag.rs70
-rw-r--r--src/test/rustdoc-ui/invalid-html-self-closing-tag.stderr80
3 files changed, 204 insertions, 1 deletions
diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs
index 67fc71665cc..a89ed7c7ed4 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 00000000000..d973a53cbc7
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-html-self-closing-tag.rs
@@ -0,0 +1,70 @@
+#![deny(rustdoc::invalid_html_tags)]
+
+/// <p/>
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct A;
+
+/// <p style/>
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct B;
+
+/// <p style=""/>
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct C;
+
+/// <p style="x"/>
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct D;
+
+/// <p style="x/></p>
+//~^ ERROR unclosed quoted HTML attribute
+pub struct E;
+
+/// <p style='x/></p>
+//~^ ERROR unclosed quoted HTML attribute
+pub struct F;
+
+/// <p style="x/"></p>
+pub struct G;
+
+/// <p style="x/"/>
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct H;
+
+/// <p / >
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct I;
+
+/// <br/>
+pub struct J;
+
+/// <a href=/></a>
+pub struct K;
+
+/// <a href=//></a>
+pub struct L;
+
+/// <a href="/"/>
+//~^ ERROR invalid self-closing HTML tag `a`
+pub struct M;
+
+/// <a href=x />
+//~^ ERROR invalid self-closing HTML tag `a`
+pub struct N;
+
+/// <a href= />
+//~^ ERROR invalid self-closing HTML tag `a`
+pub struct O;
+
+/// <a href=x/></a>
+pub struct P;
+
+/// <svg><rect width=1 height=1 /></svg>
+pub struct Q;
+
+/// <svg><rect width=1 height=/></svg>
+//~^ ERROR unclosed HTML tag `rect`
+pub struct R;
+
+/// <svg / q>
+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 00000000000..e45edfb43ff
--- /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 | /// <p/>
+   |     ^^
+   |
+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 | /// <p style/>
+   |     ^^
+
+error: invalid self-closing HTML tag `p`
+  --> $DIR/invalid-html-self-closing-tag.rs:11:5
+   |
+LL | /// <p style=""/>
+   |     ^^
+
+error: invalid self-closing HTML tag `p`
+  --> $DIR/invalid-html-self-closing-tag.rs:15:5
+   |
+LL | /// <p style="x"/>
+   |     ^^
+
+error: unclosed quoted HTML attribute on tag `p`
+  --> $DIR/invalid-html-self-closing-tag.rs:19:14
+   |
+LL | /// <p style="x/></p>
+   |              ^
+
+error: unclosed quoted HTML attribute on tag `p`
+  --> $DIR/invalid-html-self-closing-tag.rs:23:14
+   |
+LL | /// <p style='x/></p>
+   |              ^
+
+error: invalid self-closing HTML tag `p`
+  --> $DIR/invalid-html-self-closing-tag.rs:30:5
+   |
+LL | /// <p style="x/"/>
+   |     ^^
+
+error: invalid self-closing HTML tag `p`
+  --> $DIR/invalid-html-self-closing-tag.rs:34:5
+   |
+LL | /// <p / >
+   |     ^^
+
+error: invalid self-closing HTML tag `a`
+  --> $DIR/invalid-html-self-closing-tag.rs:47:5
+   |
+LL | /// <a href="/"/>
+   |     ^^
+
+error: invalid self-closing HTML tag `a`
+  --> $DIR/invalid-html-self-closing-tag.rs:51:5
+   |
+LL | /// <a href=x />
+   |     ^^
+
+error: invalid self-closing HTML tag `a`
+  --> $DIR/invalid-html-self-closing-tag.rs:55:5
+   |
+LL | /// <a href= />
+   |     ^^
+
+error: unclosed HTML tag `rect`
+  --> $DIR/invalid-html-self-closing-tag.rs:65:10
+   |
+LL | /// <svg><rect width=1 height=/></svg>
+   |          ^^^^^
+
+error: aborting due to 12 previous errors
+