Clean up doc attributes check before adding more
This commit is contained in:
parent
92e4fb0732
commit
5a228263b8
1 changed files with 93 additions and 79 deletions
|
@ -78,7 +78,7 @@ impl CheckAttrVisitor<'tcx> {
|
||||||
} else if self.tcx.sess.check_name(attr, sym::track_caller) {
|
} else if self.tcx.sess.check_name(attr, sym::track_caller) {
|
||||||
self.check_track_caller(&attr.span, attrs, span, target)
|
self.check_track_caller(&attr.span, attrs, span, target)
|
||||||
} else if self.tcx.sess.check_name(attr, sym::doc) {
|
} else if self.tcx.sess.check_name(attr, sym::doc) {
|
||||||
self.check_doc_alias(attr, hir_id, target)
|
self.check_doc_attrs(attr, hir_id, target)
|
||||||
} else if self.tcx.sess.check_name(attr, sym::no_link) {
|
} else if self.tcx.sess.check_name(attr, sym::no_link) {
|
||||||
self.check_no_link(&attr, span, target)
|
self.check_no_link(&attr, span, target)
|
||||||
} else if self.tcx.sess.check_name(attr, sym::export_name) {
|
} else if self.tcx.sess.check_name(attr, sym::export_name) {
|
||||||
|
@ -297,89 +297,103 @@ impl CheckAttrVisitor<'tcx> {
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_doc_alias(&self, attr: &Attribute, hir_id: HirId, target: Target) -> bool {
|
fn check_doc_alias(&self, meta: &NestedMetaItem, hir_id: HirId, target: Target) -> bool {
|
||||||
|
if !meta.is_value_str() {
|
||||||
|
self.doc_alias_str_error(meta);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let doc_alias = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new);
|
||||||
|
if doc_alias.is_empty() {
|
||||||
|
self.doc_alias_str_error(meta);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if let Some(err) = match target {
|
||||||
|
Target::Impl => Some("implementation block"),
|
||||||
|
Target::ForeignMod => Some("extern block"),
|
||||||
|
Target::AssocTy => {
|
||||||
|
let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
|
||||||
|
let containing_item = self.tcx.hir().expect_item(parent_hir_id);
|
||||||
|
if Target::from_item(containing_item) == Target::Impl {
|
||||||
|
Some("type alias in implementation block")
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Target::AssocConst => {
|
||||||
|
let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
|
||||||
|
let containing_item = self.tcx.hir().expect_item(parent_hir_id);
|
||||||
|
// We can't link to trait impl's consts.
|
||||||
|
let err = "associated constant in trait implementation block";
|
||||||
|
match containing_item.kind {
|
||||||
|
ItemKind::Impl { of_trait: Some(_), .. } => Some(err),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
} {
|
||||||
|
self.tcx
|
||||||
|
.sess
|
||||||
|
.struct_span_err(
|
||||||
|
meta.span(),
|
||||||
|
&format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err),
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_attr_crate_level(
|
||||||
|
&self,
|
||||||
|
meta: &NestedMetaItem,
|
||||||
|
hir_id: HirId,
|
||||||
|
attr_name: &str,
|
||||||
|
) -> bool {
|
||||||
|
if CRATE_HIR_ID == hir_id {
|
||||||
|
self.tcx
|
||||||
|
.sess
|
||||||
|
.struct_span_err(
|
||||||
|
meta.span(),
|
||||||
|
&format!(
|
||||||
|
"`#![doc({} = \"...\")]` isn't allowed as a crate level attribute",
|
||||||
|
attr_name,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_doc_attrs(&self, attr: &Attribute, hir_id: HirId, target: Target) -> bool {
|
||||||
if let Some(mi) = attr.meta() {
|
if let Some(mi) = attr.meta() {
|
||||||
if let Some(list) = mi.meta_item_list() {
|
if let Some(list) = mi.meta_item_list() {
|
||||||
for meta in list {
|
for meta in list {
|
||||||
if meta.has_name(sym::alias) {
|
if meta.has_name(sym::alias) {
|
||||||
if !meta.is_value_str() {
|
if !self.check_attr_crate_level(meta, hir_id, "alias")
|
||||||
self.doc_alias_str_error(meta);
|
|| !self.check_doc_alias(meta, hir_id, target)
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let doc_alias =
|
|
||||||
meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new);
|
|
||||||
if doc_alias.is_empty() {
|
|
||||||
self.doc_alias_str_error(meta);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
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();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
if let Some(err) = match target {
|
|
||||||
Target::Impl => Some("implementation block"),
|
|
||||||
Target::ForeignMod => Some("extern block"),
|
|
||||||
Target::AssocTy => {
|
|
||||||
let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
|
|
||||||
let containing_item = self.tcx.hir().expect_item(parent_hir_id);
|
|
||||||
if Target::from_item(containing_item) == Target::Impl {
|
|
||||||
Some("type alias in implementation block")
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Target::AssocConst => {
|
|
||||||
let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
|
|
||||||
let containing_item = self.tcx.hir().expect_item(parent_hir_id);
|
|
||||||
// We can't link to trait impl's consts.
|
|
||||||
let err = "associated constant in trait implementation block";
|
|
||||||
match containing_item.kind {
|
|
||||||
ItemKind::Impl { of_trait: Some(_), .. } => Some(err),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
} {
|
|
||||||
self.tcx
|
|
||||||
.sess
|
|
||||||
.struct_span_err(
|
|
||||||
meta.span(),
|
|
||||||
&format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err),
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if CRATE_HIR_ID == hir_id {
|
|
||||||
self.tcx
|
|
||||||
.sess
|
|
||||||
.struct_span_err(
|
|
||||||
meta.span(),
|
|
||||||
"`#![doc(alias = \"...\")]` isn't allowed as a crate \
|
|
||||||
level attribute",
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue