Rollup merge of #82846 - GuillaumeGomez:doc-alias-list, r=jyn514
rustdoc: allow list syntax for #[doc(alias)] attributes Fixes https://github.com/rust-lang/rust/issues/81205. It now allows to have: ```rust #[doc(alias = "x")] // and: #[doc(alias("y", "z"))] ``` cc ``@jplatte`` r? ``@jyn514``
This commit is contained in:
commit
61372e1af6
7 changed files with 255 additions and 60 deletions
|
@ -394,33 +394,50 @@ impl CheckAttrVisitor<'tcx> {
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_doc_alias(&self, meta: &NestedMetaItem, hir_id: HirId, target: Target) -> bool {
|
fn check_doc_alias_value(
|
||||||
let doc_alias = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new);
|
&self,
|
||||||
|
meta: &NestedMetaItem,
|
||||||
|
doc_alias: &str,
|
||||||
|
hir_id: HirId,
|
||||||
|
target: Target,
|
||||||
|
is_list: bool,
|
||||||
|
) -> bool {
|
||||||
|
let tcx = self.tcx;
|
||||||
|
let err_fn = move |span: Span, msg: &str| {
|
||||||
|
tcx.sess.span_err(
|
||||||
|
span,
|
||||||
|
&format!(
|
||||||
|
"`#[doc(alias{})]` {}",
|
||||||
|
if is_list { "(\"...\")" } else { " = \"...\"" },
|
||||||
|
msg,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
false
|
||||||
|
};
|
||||||
if doc_alias.is_empty() {
|
if doc_alias.is_empty() {
|
||||||
self.doc_attr_str_error(meta, "alias");
|
return err_fn(
|
||||||
return false;
|
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
|
||||||
|
"attribute cannot have empty value",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if let Some(c) =
|
if let Some(c) =
|
||||||
doc_alias.chars().find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' '))
|
doc_alias.chars().find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' '))
|
||||||
{
|
{
|
||||||
self.tcx
|
self.tcx.sess.span_err(
|
||||||
.sess
|
|
||||||
.struct_span_err(
|
|
||||||
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
|
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
|
||||||
&format!("{:?} character isn't allowed in `#[doc(alias = \"...\")]`", c),
|
&format!(
|
||||||
)
|
"{:?} character isn't allowed in `#[doc(alias{})]`",
|
||||||
.emit();
|
c,
|
||||||
|
if is_list { "(\"...\")" } else { " = \"...\"" },
|
||||||
|
),
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') {
|
if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') {
|
||||||
self.tcx
|
return err_fn(
|
||||||
.sess
|
|
||||||
.struct_span_err(
|
|
||||||
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
|
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
|
||||||
"`#[doc(alias = \"...\")]` cannot start or end with ' '",
|
"cannot start or end with ' '",
|
||||||
)
|
);
|
||||||
.emit();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if let Some(err) = match target {
|
if let Some(err) = match target {
|
||||||
Target::Impl => Some("implementation block"),
|
Target::Impl => Some("implementation block"),
|
||||||
|
@ -446,27 +463,63 @@ impl CheckAttrVisitor<'tcx> {
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
} {
|
} {
|
||||||
self.tcx
|
return err_fn(meta.span(), &format!("isn't allowed on {}", err));
|
||||||
.sess
|
|
||||||
.struct_span_err(
|
|
||||||
meta.span(),
|
|
||||||
&format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err),
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
let item_name = self.tcx.hir().name(hir_id);
|
let item_name = self.tcx.hir().name(hir_id);
|
||||||
if &*item_name.as_str() == doc_alias {
|
if &*item_name.as_str() == doc_alias {
|
||||||
|
return err_fn(meta.span(), "is the same as the item's name");
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_doc_alias(&self, meta: &NestedMetaItem, hir_id: HirId, target: Target) -> bool {
|
||||||
|
if let Some(values) = meta.meta_item_list() {
|
||||||
|
let mut errors = 0;
|
||||||
|
for v in values {
|
||||||
|
match v.literal() {
|
||||||
|
Some(l) => match l.kind {
|
||||||
|
LitKind::Str(s, _) => {
|
||||||
|
if !self.check_doc_alias_value(v, &s.as_str(), hir_id, target, true) {
|
||||||
|
errors += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.tcx
|
||||||
|
.sess
|
||||||
|
.struct_span_err(
|
||||||
|
v.span(),
|
||||||
|
"`#[doc(alias(\"a\"))]` expects string literals",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
errors += 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
self.tcx
|
||||||
|
.sess
|
||||||
|
.struct_span_err(
|
||||||
|
v.span(),
|
||||||
|
"`#[doc(alias(\"a\"))]` expects string literals",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
errors += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errors == 0
|
||||||
|
} else if let Some(doc_alias) = meta.value_str().map(|s| s.to_string()) {
|
||||||
|
self.check_doc_alias_value(meta, &doc_alias, hir_id, target, false)
|
||||||
|
} else {
|
||||||
self.tcx
|
self.tcx
|
||||||
.sess
|
.sess
|
||||||
.struct_span_err(
|
.struct_span_err(
|
||||||
meta.span(),
|
meta.span(),
|
||||||
&format!("`#[doc(alias = \"...\")]` is the same as the item's name"),
|
"doc alias attribute expects a string `#[doc(alias = \"a\")]` or a list of \
|
||||||
|
strings `#[doc(alias(\"a\", \"b\"))]`",
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
return false;
|
false
|
||||||
}
|
}
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
|
fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
|
||||||
|
|
|
@ -81,3 +81,10 @@ Then, when looking for it through the `rustdoc` search, if you enter "x" or
|
||||||
"big", search will show the `BigX` struct first.
|
"big", search will show the `BigX` struct first.
|
||||||
|
|
||||||
There are some limitations on the doc alias names though: you can't use `"` or whitespace.
|
There are some limitations on the doc alias names though: you can't use `"` or whitespace.
|
||||||
|
|
||||||
|
You can add multiple aliases at the same time by using a list:
|
||||||
|
|
||||||
|
```rust,no_run
|
||||||
|
#[doc(alias("x", "big"))]
|
||||||
|
pub struct BigX;
|
||||||
|
```
|
||||||
|
|
|
@ -910,12 +910,23 @@ impl Attributes {
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn get_doc_aliases(&self) -> FxHashSet<String> {
|
crate fn get_doc_aliases(&self) -> FxHashSet<String> {
|
||||||
self.other_attrs
|
let mut aliases = FxHashSet::default();
|
||||||
.lists(sym::doc)
|
|
||||||
.filter(|a| a.has_name(sym::alias))
|
for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) {
|
||||||
.filter_map(|a| a.value_str().map(|s| s.to_string()))
|
if let Some(values) = attr.meta_item_list() {
|
||||||
.filter(|v| !v.is_empty())
|
for l in values {
|
||||||
.collect::<FxHashSet<_>>()
|
match l.literal().unwrap().kind {
|
||||||
|
ast::LitKind::Str(s, _) => {
|
||||||
|
aliases.insert(s.as_str().to_string());
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
aliases.insert(attr.value_str().map(|s| s.to_string()).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aliases
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
#[doc(alias = "foo")] // ok!
|
#[doc(alias = "foo")] // ok!
|
||||||
|
#[doc(alias("bar", "baz"))] // ok!
|
||||||
pub struct Bar;
|
pub struct Bar;
|
||||||
|
|
||||||
#[doc(alias)] //~ ERROR
|
#[doc(alias)] //~ ERROR
|
||||||
#[doc(alias = 0)] //~ ERROR
|
#[doc(alias = 0)] //~ ERROR
|
||||||
#[doc(alias("bar"))] //~ ERROR
|
|
||||||
#[doc(alias = "\"")] //~ ERROR
|
#[doc(alias = "\"")] //~ ERROR
|
||||||
#[doc(alias = "\n")] //~ ERROR
|
#[doc(alias = "\n")] //~ ERROR
|
||||||
#[doc(alias = "
|
#[doc(alias = "
|
||||||
|
@ -13,4 +13,16 @@ pub struct Bar;
|
||||||
#[doc(alias = "\t")] //~ ERROR
|
#[doc(alias = "\t")] //~ ERROR
|
||||||
#[doc(alias = " hello")] //~ ERROR
|
#[doc(alias = " hello")] //~ ERROR
|
||||||
#[doc(alias = "hello ")] //~ ERROR
|
#[doc(alias = "hello ")] //~ ERROR
|
||||||
|
#[doc(alias = "")] //~ ERROR
|
||||||
pub struct Foo;
|
pub struct Foo;
|
||||||
|
|
||||||
|
#[doc(alias(0))] //~ ERROR
|
||||||
|
#[doc(alias("\""))] //~ ERROR
|
||||||
|
#[doc(alias("\n"))] //~ ERROR
|
||||||
|
#[doc(alias("
|
||||||
|
"))] //~^ ERROR
|
||||||
|
#[doc(alias("\t"))] //~ ERROR
|
||||||
|
#[doc(alias(" hello"))] //~ ERROR
|
||||||
|
#[doc(alias("hello "))] //~ ERROR
|
||||||
|
#[doc(alias(""))] //~ ERROR
|
||||||
|
pub struct Foo2;
|
||||||
|
|
|
@ -1,21 +1,15 @@
|
||||||
error: doc alias attribute expects a string: #[doc(alias = "a")]
|
error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]`
|
||||||
--> $DIR/check-doc-alias-attr.rs:6:7
|
--> $DIR/check-doc-alias-attr.rs:7:7
|
||||||
|
|
|
|
||||||
LL | #[doc(alias)]
|
LL | #[doc(alias)]
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: doc alias attribute expects a string: #[doc(alias = "a")]
|
error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]`
|
||||||
--> $DIR/check-doc-alias-attr.rs:7:7
|
--> $DIR/check-doc-alias-attr.rs:8:7
|
||||||
|
|
|
|
||||||
LL | #[doc(alias = 0)]
|
LL | #[doc(alias = 0)]
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: doc alias attribute expects a string: #[doc(alias = "a")]
|
|
||||||
--> $DIR/check-doc-alias-attr.rs:8:7
|
|
||||||
|
|
|
||||||
LL | #[doc(alias("bar"))]
|
|
||||||
| ^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: '\"' character isn't allowed in `#[doc(alias = "...")]`
|
error: '\"' character isn't allowed in `#[doc(alias = "...")]`
|
||||||
--> $DIR/check-doc-alias-attr.rs:9:15
|
--> $DIR/check-doc-alias-attr.rs:9:15
|
||||||
|
|
|
|
||||||
|
@ -54,5 +48,61 @@ error: `#[doc(alias = "...")]` cannot start or end with ' '
|
||||||
LL | #[doc(alias = "hello ")]
|
LL | #[doc(alias = "hello ")]
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 9 previous errors
|
error: `#[doc(alias = "...")]` attribute cannot have empty value
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:16:15
|
||||||
|
|
|
||||||
|
LL | #[doc(alias = "")]
|
||||||
|
| ^^
|
||||||
|
|
||||||
|
error: `#[doc(alias("a"))]` expects string literals
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:19:13
|
||||||
|
|
|
||||||
|
LL | #[doc(alias(0))]
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: '\"' character isn't allowed in `#[doc(alias("..."))]`
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:20:13
|
||||||
|
|
|
||||||
|
LL | #[doc(alias("\""))]
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error: '\n' character isn't allowed in `#[doc(alias("..."))]`
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:21:13
|
||||||
|
|
|
||||||
|
LL | #[doc(alias("\n"))]
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error: '\n' character isn't allowed in `#[doc(alias("..."))]`
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:22:13
|
||||||
|
|
|
||||||
|
LL | #[doc(alias("
|
||||||
|
| _____________^
|
||||||
|
LL | | "))]
|
||||||
|
| |_^
|
||||||
|
|
||||||
|
error: '\t' character isn't allowed in `#[doc(alias("..."))]`
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:24:13
|
||||||
|
|
|
||||||
|
LL | #[doc(alias("\t"))]
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error: `#[doc(alias("..."))]` cannot start or end with ' '
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:25:13
|
||||||
|
|
|
||||||
|
LL | #[doc(alias(" hello"))]
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
|
error: `#[doc(alias("..."))]` cannot start or end with ' '
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:26:13
|
||||||
|
|
|
||||||
|
LL | #[doc(alias("hello "))]
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
|
error: `#[doc(alias("..."))]` attribute cannot have empty value
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:27:13
|
||||||
|
|
|
||||||
|
LL | #[doc(alias(""))]
|
||||||
|
| ^^
|
||||||
|
|
||||||
|
error: aborting due to 17 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
#[doc(alias = "foo")] // ok!
|
#[doc(alias = "foo")] // ok!
|
||||||
|
#[doc(alias("bar", "baz"))] // ok!
|
||||||
pub struct Bar;
|
pub struct Bar;
|
||||||
|
|
||||||
#[doc(alias)] //~ ERROR
|
#[doc(alias)] //~ ERROR
|
||||||
#[doc(alias = 0)] //~ ERROR
|
#[doc(alias = 0)] //~ ERROR
|
||||||
#[doc(alias("bar"))] //~ ERROR
|
|
||||||
#[doc(alias = "\"")] //~ ERROR
|
#[doc(alias = "\"")] //~ ERROR
|
||||||
#[doc(alias = "\n")] //~ ERROR
|
#[doc(alias = "\n")] //~ ERROR
|
||||||
#[doc(alias = "
|
#[doc(alias = "
|
||||||
|
@ -13,4 +13,16 @@ pub struct Bar;
|
||||||
#[doc(alias = "\t")] //~ ERROR
|
#[doc(alias = "\t")] //~ ERROR
|
||||||
#[doc(alias = " hello")] //~ ERROR
|
#[doc(alias = " hello")] //~ ERROR
|
||||||
#[doc(alias = "hello ")] //~ ERROR
|
#[doc(alias = "hello ")] //~ ERROR
|
||||||
|
#[doc(alias = "")] //~ ERROR
|
||||||
pub struct Foo;
|
pub struct Foo;
|
||||||
|
|
||||||
|
#[doc(alias(0))] //~ ERROR
|
||||||
|
#[doc(alias("\""))] //~ ERROR
|
||||||
|
#[doc(alias("\n"))] //~ ERROR
|
||||||
|
#[doc(alias("
|
||||||
|
"))] //~^ ERROR
|
||||||
|
#[doc(alias("\t"))] //~ ERROR
|
||||||
|
#[doc(alias(" hello"))] //~ ERROR
|
||||||
|
#[doc(alias("hello "))] //~ ERROR
|
||||||
|
#[doc(alias(""))] //~ ERROR
|
||||||
|
pub struct Foo2;
|
||||||
|
|
|
@ -1,21 +1,15 @@
|
||||||
error: doc alias attribute expects a string: #[doc(alias = "a")]
|
error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]`
|
||||||
--> $DIR/check-doc-alias-attr.rs:6:7
|
--> $DIR/check-doc-alias-attr.rs:7:7
|
||||||
|
|
|
|
||||||
LL | #[doc(alias)]
|
LL | #[doc(alias)]
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: doc alias attribute expects a string: #[doc(alias = "a")]
|
error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]`
|
||||||
--> $DIR/check-doc-alias-attr.rs:7:7
|
--> $DIR/check-doc-alias-attr.rs:8:7
|
||||||
|
|
|
|
||||||
LL | #[doc(alias = 0)]
|
LL | #[doc(alias = 0)]
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: doc alias attribute expects a string: #[doc(alias = "a")]
|
|
||||||
--> $DIR/check-doc-alias-attr.rs:8:7
|
|
||||||
|
|
|
||||||
LL | #[doc(alias("bar"))]
|
|
||||||
| ^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: '\"' character isn't allowed in `#[doc(alias = "...")]`
|
error: '\"' character isn't allowed in `#[doc(alias = "...")]`
|
||||||
--> $DIR/check-doc-alias-attr.rs:9:15
|
--> $DIR/check-doc-alias-attr.rs:9:15
|
||||||
|
|
|
|
||||||
|
@ -54,5 +48,61 @@ error: `#[doc(alias = "...")]` cannot start or end with ' '
|
||||||
LL | #[doc(alias = "hello ")]
|
LL | #[doc(alias = "hello ")]
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 9 previous errors
|
error: `#[doc(alias = "...")]` attribute cannot have empty value
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:16:15
|
||||||
|
|
|
||||||
|
LL | #[doc(alias = "")]
|
||||||
|
| ^^
|
||||||
|
|
||||||
|
error: `#[doc(alias("a"))]` expects string literals
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:19:13
|
||||||
|
|
|
||||||
|
LL | #[doc(alias(0))]
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: '\"' character isn't allowed in `#[doc(alias("..."))]`
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:20:13
|
||||||
|
|
|
||||||
|
LL | #[doc(alias("\""))]
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error: '\n' character isn't allowed in `#[doc(alias("..."))]`
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:21:13
|
||||||
|
|
|
||||||
|
LL | #[doc(alias("\n"))]
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error: '\n' character isn't allowed in `#[doc(alias("..."))]`
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:22:13
|
||||||
|
|
|
||||||
|
LL | #[doc(alias("
|
||||||
|
| _____________^
|
||||||
|
LL | | "))]
|
||||||
|
| |_^
|
||||||
|
|
||||||
|
error: '\t' character isn't allowed in `#[doc(alias("..."))]`
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:24:13
|
||||||
|
|
|
||||||
|
LL | #[doc(alias("\t"))]
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error: `#[doc(alias("..."))]` cannot start or end with ' '
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:25:13
|
||||||
|
|
|
||||||
|
LL | #[doc(alias(" hello"))]
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
|
error: `#[doc(alias("..."))]` cannot start or end with ' '
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:26:13
|
||||||
|
|
|
||||||
|
LL | #[doc(alias("hello "))]
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
|
error: `#[doc(alias("..."))]` attribute cannot have empty value
|
||||||
|
--> $DIR/check-doc-alias-attr.rs:27:13
|
||||||
|
|
|
||||||
|
LL | #[doc(alias(""))]
|
||||||
|
| ^^
|
||||||
|
|
||||||
|
error: aborting due to 17 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue