rustdoc: Fully escape link section and export name

Escape "special characters" (e.g., double quotes `"` and line breaks `\n`).
Escape HTML.

Lastly, add regression tests and clean up existing tests.
This commit is contained in:
León Orell Valerian Liehr
2025-09-14 01:32:20 +02:00
parent 88e797784e
commit d7d7725b8c
7 changed files with 38 additions and 46 deletions

View File

@@ -2935,11 +2935,11 @@ fn render_attributes_in_code(
let hir::Attribute::Parsed(kind) = attr else { continue };
let attr = match kind {
AttributeKind::LinkSection { name, .. } => {
Cow::Owned(format!("#[unsafe(link_section = \"{name}\")]"))
Cow::Owned(format!("#[unsafe(link_section = {})]", Escape(&format!("{name:?}"))))
}
AttributeKind::NoMangle(..) => Cow::Borrowed("#[unsafe(no_mangle)]"),
AttributeKind::ExportName { name, .. } => {
Cow::Owned(format!("#[unsafe(export_name = \"{name}\")]"))
Cow::Owned(format!("#[unsafe(export_name = {})]", Escape(&format!("{name:?}"))))
}
AttributeKind::NonExhaustive(..) => Cow::Borrowed("#[non_exhaustive]"),
_ => continue,

View File

@@ -1,8 +0,0 @@
#![crate_name = "foo"]
//@ has 'foo/fn.f.html'
//@ has - //*[@'class="code-attribute"]' '#[unsafe(export_name = "f")]'
//@ has - //*[@'class="rust item-decl"]' 'pub fn f()'
#[unsafe(export_name = "\
f")]
pub fn f() {}

View File

@@ -9,6 +9,18 @@ pub extern "C" fn f() {}
#[unsafe(export_name = "bar")]
pub extern "C" fn g() {}
//@ has foo/fn.escape_special.html '//*[@class="code-attribute"]' \
// '#[unsafe(export_name = "\n\"\n")]'
#[unsafe(export_name = "\n\"
")]
pub extern "C" fn escape_special() {}
// issue: <https://github.com/rust-lang/rust/issues/142835>
//@ has foo/fn.escape_html.html '//*[@class="code-attribute"]' \
// '#[unsafe(export_name = "<script>alert()</script>")]'
#[unsafe(export_name = "<script>alert()</script>")]
pub extern "C" fn escape_html() {}
//@ has foo/fn.example.html '//*[@class="code-attribute"]' '#[unsafe(link_section = ".text")]'
#[unsafe(link_section = ".text")]
pub extern "C" fn example() {}

View File

@@ -1,7 +1,20 @@
// Ensure that we render attributes on inlined cross-crate re-exported items.
// issue: <https://github.com/rust-lang/rust/issues/144004>
//@ aux-crate:attributes=attributes.rs
//@ edition:2021
#![crate_name = "user"]
//@ has 'user/struct.NonExhaustive.html'
//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[non_exhaustive]'
//@ has 'user/fn.no_mangle.html' '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]'
pub use attributes::no_mangle;
//@ has 'user/fn.link_section.html' '//pre[@class="rust item-decl"]' \
// '#[unsafe(link_section = ".here")]'
pub use attributes::link_section;
//@ has 'user/fn.export_name.html' '//pre[@class="rust item-decl"]' \
// '#[unsafe(export_name = "exonym")]'
pub use attributes::export_name;
//@ has 'user/struct.NonExhaustive.html' '//pre[@class="rust item-decl"]' '#[non_exhaustive]'
pub use attributes::NonExhaustive;

View File

@@ -1,2 +1,11 @@
#[unsafe(no_mangle)]
pub fn no_mangle() {}
#[unsafe(link_section = ".here")]
pub fn link_section() {}
#[unsafe(export_name = "exonym")]
pub fn export_name() {}
#[non_exhaustive]
pub struct NonExhaustive;

View File

@@ -1,14 +0,0 @@
#[unsafe(no_mangle)]
pub fn f0() {}
#[unsafe(link_section = ".here")]
pub fn f1() {}
#[unsafe(export_name = "f2export")]
pub fn f2() {}
#[repr(u8)]
pub enum T0 { V1 }
#[non_exhaustive]
pub enum T1 {}

View File

@@ -1,20 +0,0 @@
//@ aux-build: reexports-attrs.rs
#![crate_name = "foo"]
extern crate reexports_attrs;
//@ has 'foo/fn.f0.html' '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]'
pub use reexports_attrs::f0;
//@ has 'foo/fn.f1.html' '//pre[@class="rust item-decl"]' '#[unsafe(link_section = ".here")]'
pub use reexports_attrs::f1;
//@ has 'foo/fn.f2.html' '//pre[@class="rust item-decl"]' '#[unsafe(export_name = "f2export")]'
pub use reexports_attrs::f2;
//@ has 'foo/enum.T0.html' '//pre[@class="rust item-decl"]' '#[repr(u8)]'
pub use reexports_attrs::T0;
//@ has 'foo/enum.T1.html' '//pre[@class="rust item-decl"]' '#[non_exhaustive]'
pub use reexports_attrs::T1;