Allow doc alias attributes to use both list and value
This commit is contained in:
parent
4b9f5cc4c1
commit
bbbefa3edc
|
@ -390,10 +390,25 @@ 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 {
|
||||||
if doc_alias.is_empty() {
|
if doc_alias.is_empty() {
|
||||||
self.doc_attr_str_error(meta, "alias");
|
self.tcx
|
||||||
|
.sess
|
||||||
|
.struct_span_err(
|
||||||
|
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
|
||||||
|
&format!(
|
||||||
|
"`#[doc(alias{})]` attribute cannot have empty value",
|
||||||
|
if is_list { "(\"...\")" } else { " = \"...\"" },
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if let Some(c) =
|
if let Some(c) =
|
||||||
|
@ -403,7 +418,11 @@ impl CheckAttrVisitor<'tcx> {
|
||||||
.sess
|
.sess
|
||||||
.struct_span_err(
|
.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{})]`",
|
||||||
|
c,
|
||||||
|
if is_list { "(\"...\")" } else { " = \"...\"" },
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
return false;
|
return false;
|
||||||
|
@ -413,7 +432,10 @@ impl CheckAttrVisitor<'tcx> {
|
||||||
.sess
|
.sess
|
||||||
.struct_span_err(
|
.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 ' '",
|
&format!(
|
||||||
|
"`#[doc(alias{})]` cannot start or end with ' '",
|
||||||
|
if is_list { "(\"...\")" } else { " = \"...\"" },
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
return false;
|
return false;
|
||||||
|
@ -446,7 +468,11 @@ impl CheckAttrVisitor<'tcx> {
|
||||||
.sess
|
.sess
|
||||||
.struct_span_err(
|
.struct_span_err(
|
||||||
meta.span(),
|
meta.span(),
|
||||||
&format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err),
|
&format!(
|
||||||
|
"`#[doc(alias{})]` isn't allowed on {}",
|
||||||
|
if is_list { "(\"...\")" } else { " = \"...\"" },
|
||||||
|
err,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
return false;
|
return false;
|
||||||
|
@ -457,7 +483,10 @@ impl CheckAttrVisitor<'tcx> {
|
||||||
.sess
|
.sess
|
||||||
.struct_span_err(
|
.struct_span_err(
|
||||||
meta.span(),
|
meta.span(),
|
||||||
&format!("`#[doc(alias = \"...\")]` is the same as the item's name"),
|
&format!(
|
||||||
|
"`#[doc(alias{})]` is the same as the item's name",
|
||||||
|
if is_list { "(\"...\")" } else { " = \"...\"" },
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
return false;
|
return false;
|
||||||
|
@ -465,6 +494,56 @@ impl CheckAttrVisitor<'tcx> {
|
||||||
true
|
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(),
|
||||||
|
"doc alias attribute expects a string `#[doc(alias = \"a\")]` or a list of \
|
||||||
|
strings: `#[doc(alias(\"a\", \"b\")]`",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
|
fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
|
||||||
let doc_keyword = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new);
|
let doc_keyword = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new);
|
||||||
if doc_keyword.is_empty() {
|
if doc_keyword.is_empty() {
|
||||||
|
|
|
@ -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;
|
||||||
|
```
|
||||||
|
|
|
@ -914,8 +914,20 @@ impl Attributes {
|
||||||
self.other_attrs
|
self.other_attrs
|
||||||
.lists(sym::doc)
|
.lists(sym::doc)
|
||||||
.filter(|a| a.has_name(sym::alias))
|
.filter(|a| a.has_name(sym::alias))
|
||||||
.filter_map(|a| a.value_str().map(|s| s.to_string()))
|
.map(|a| {
|
||||||
.filter(|v| !v.is_empty())
|
if let Some(values) = a.meta_item_list() {
|
||||||
|
values
|
||||||
|
.iter()
|
||||||
|
.map(|l| match l.literal().unwrap().kind {
|
||||||
|
ast::LitKind::Str(s, _) => s.as_str().to_string(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
} else {
|
||||||
|
vec![a.value_str().map(|s| s.to_string()).unwrap()]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
.collect::<FxHashSet<_>>()
|
.collect::<FxHashSet<_>>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue