1
Fork 0

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:
Dylan DPC 2021-03-19 15:03:21 +01:00 committed by GitHub
commit 61372e1af6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 255 additions and 60 deletions

View file

@ -394,33 +394,50 @@ impl CheckAttrVisitor<'tcx> {
.emit();
}
fn check_doc_alias(&self, meta: &NestedMetaItem, hir_id: HirId, target: Target) -> bool {
let doc_alias = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new);
fn check_doc_alias_value(
&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() {
self.doc_attr_str_error(meta, "alias");
return false;
return err_fn(
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
"attribute cannot have empty value",
);
}
if let Some(c) =
doc_alias.chars().find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' '))
{
self.tcx
.sess
.struct_span_err(
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
&format!("{:?} character isn't allowed in `#[doc(alias = \"...\")]`", c),
)
.emit();
self.tcx.sess.span_err(
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
&format!(
"{:?} character isn't allowed in `#[doc(alias{})]`",
c,
if is_list { "(\"...\")" } else { " = \"...\"" },
),
);
return false;
}
if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') {
self.tcx
.sess
.struct_span_err(
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
"`#[doc(alias = \"...\")]` cannot start or end with ' '",
)
.emit();
return false;
return err_fn(
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
"cannot start or end with ' '",
);
}
if let Some(err) = match target {
Target::Impl => Some("implementation block"),
@ -446,27 +463,63 @@ impl CheckAttrVisitor<'tcx> {
}
_ => None,
} {
self.tcx
.sess
.struct_span_err(
meta.span(),
&format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err),
)
.emit();
return false;
return err_fn(meta.span(), &format!("isn't allowed on {}", err));
}
let item_name = self.tcx.hir().name(hir_id);
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
.sess
.struct_span_err(
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();
return false;
false
}
true
}
fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {