diff options
| author | Dylan DPC <dylan.dpc@gmail.com> | 2021-03-19 15:03:21 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-03-19 15:03:21 +0100 |
| commit | 61372e1af6a100aedc203d0739073b42f8977e4e (patch) | |
| tree | e03d9ecf658034f333855d44b9904a445f6c0c76 /compiler | |
| parent | 29609711a58312fc105a589e353d2ae197532fd5 (diff) | |
| parent | 1d26e6b632c78dedff2dd19d93d0687b2c97717d (diff) | |
| download | rust-61372e1af6a100aedc203d0739073b42f8977e4e.tar.gz rust-61372e1af6a100aedc203d0739073b42f8977e4e.zip | |
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``
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_passes/src/check_attr.rs | 113 |
1 files changed, 83 insertions, 30 deletions
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 775e27e68f8..d91d0e1765b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -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 { |
