Skip to content

Commit bbbefa3

Browse files
Allow doc alias attributes to use both list and value
1 parent 4b9f5cc commit bbbefa3

File tree

3 files changed

+107
-9
lines changed

3 files changed

+107
-9
lines changed

compiler/rustc_passes/src/check_attr.rs

Lines changed: 86 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -390,10 +390,25 @@ impl CheckAttrVisitor<'tcx> {
390390
.emit();
391391
}
392392

393-
fn check_doc_alias(&self, meta: &NestedMetaItem, hir_id: HirId, target: Target) -> bool {
394-
let doc_alias = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new);
393+
fn check_doc_alias_value(
394+
&self,
395+
meta: &NestedMetaItem,
396+
doc_alias: &str,
397+
hir_id: HirId,
398+
target: Target,
399+
is_list: bool,
400+
) -> bool {
395401
if doc_alias.is_empty() {
396-
self.doc_attr_str_error(meta, "alias");
402+
self.tcx
403+
.sess
404+
.struct_span_err(
405+
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
406+
&format!(
407+
"`#[doc(alias{})]` attribute cannot have empty value",
408+
if is_list { "(\"...\")" } else { " = \"...\"" },
409+
),
410+
)
411+
.emit();
397412
return false;
398413
}
399414
if let Some(c) =
@@ -403,7 +418,11 @@ impl CheckAttrVisitor<'tcx> {
403418
.sess
404419
.struct_span_err(
405420
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
406-
&format!("{:?} character isn't allowed in `#[doc(alias = \"...\")]`", c),
421+
&format!(
422+
"{:?} character isn't allowed in `#[doc(alias{})]`",
423+
c,
424+
if is_list { "(\"...\")" } else { " = \"...\"" },
425+
),
407426
)
408427
.emit();
409428
return false;
@@ -413,7 +432,10 @@ impl CheckAttrVisitor<'tcx> {
413432
.sess
414433
.struct_span_err(
415434
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
416-
"`#[doc(alias = \"...\")]` cannot start or end with ' '",
435+
&format!(
436+
"`#[doc(alias{})]` cannot start or end with ' '",
437+
if is_list { "(\"...\")" } else { " = \"...\"" },
438+
),
417439
)
418440
.emit();
419441
return false;
@@ -446,7 +468,11 @@ impl CheckAttrVisitor<'tcx> {
446468
.sess
447469
.struct_span_err(
448470
meta.span(),
449-
&format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err),
471+
&format!(
472+
"`#[doc(alias{})]` isn't allowed on {}",
473+
if is_list { "(\"...\")" } else { " = \"...\"" },
474+
err,
475+
),
450476
)
451477
.emit();
452478
return false;
@@ -457,14 +483,67 @@ impl CheckAttrVisitor<'tcx> {
457483
.sess
458484
.struct_span_err(
459485
meta.span(),
460-
&format!("`#[doc(alias = \"...\")]` is the same as the item's name"),
486+
&format!(
487+
"`#[doc(alias{})]` is the same as the item's name",
488+
if is_list { "(\"...\")" } else { " = \"...\"" },
489+
),
461490
)
462491
.emit();
463492
return false;
464493
}
465494
true
466495
}
467496

497+
fn check_doc_alias(&self, meta: &NestedMetaItem, hir_id: HirId, target: Target) -> bool {
498+
if let Some(values) = meta.meta_item_list() {
499+
let mut errors = 0;
500+
for v in values {
501+
match v.literal() {
502+
Some(l) => match l.kind {
503+
LitKind::Str(s, _) => {
504+
if !self.check_doc_alias_value(v, &s.as_str(), hir_id, target, true) {
505+
errors += 1;
506+
}
507+
}
508+
_ => {
509+
self.tcx
510+
.sess
511+
.struct_span_err(
512+
v.span(),
513+
"`#[doc(alias(\"a\")]` expects string literals",
514+
)
515+
.emit();
516+
errors += 1;
517+
}
518+
},
519+
None => {
520+
self.tcx
521+
.sess
522+
.struct_span_err(
523+
v.span(),
524+
"`#[doc(alias(\"a\")]` expects string literals",
525+
)
526+
.emit();
527+
errors += 1;
528+
}
529+
}
530+
}
531+
errors == 0
532+
} else if let Some(doc_alias) = meta.value_str().map(|s| s.to_string()) {
533+
self.check_doc_alias_value(meta, &doc_alias, hir_id, target, false)
534+
} else {
535+
self.tcx
536+
.sess
537+
.struct_span_err(
538+
meta.span(),
539+
"doc alias attribute expects a string `#[doc(alias = \"a\")]` or a list of \
540+
strings: `#[doc(alias(\"a\", \"b\")]`",
541+
)
542+
.emit();
543+
false
544+
}
545+
}
546+
468547
fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
469548
let doc_keyword = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new);
470549
if doc_keyword.is_empty() {

src/doc/rustdoc/src/advanced-features.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,10 @@ Then, when looking for it through the `rustdoc` search, if you enter "x" or
8181
"big", search will show the `BigX` struct first.
8282

8383
There are some limitations on the doc alias names though: you can't use `"` or whitespace.
84+
85+
You can add multiple aliases at the same time by using a list:
86+
87+
```rust,no_run
88+
#[doc(alias("x", "big"))]
89+
pub struct BigX;
90+
```

src/librustdoc/clean/types.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -914,8 +914,20 @@ impl Attributes {
914914
self.other_attrs
915915
.lists(sym::doc)
916916
.filter(|a| a.has_name(sym::alias))
917-
.filter_map(|a| a.value_str().map(|s| s.to_string()))
918-
.filter(|v| !v.is_empty())
917+
.map(|a| {
918+
if let Some(values) = a.meta_item_list() {
919+
values
920+
.iter()
921+
.map(|l| match l.literal().unwrap().kind {
922+
ast::LitKind::Str(s, _) => s.as_str().to_string(),
923+
_ => unreachable!(),
924+
})
925+
.collect::<Vec<_>>()
926+
} else {
927+
vec![a.value_str().map(|s| s.to_string()).unwrap()]
928+
}
929+
})
930+
.flatten()
919931
.collect::<FxHashSet<_>>()
920932
}
921933
}

0 commit comments

Comments
 (0)