macros: support doc comments in diag derives
Documentation comments shouldn't affect the diagnostic derive in any way, but explicit support has to be added for ignoring the `doc` attribute. Signed-off-by: David Wood <david.wood@huawei.com>
This commit is contained in:
parent
1536ab1b38
commit
7fbaf27696
@ -5,7 +5,7 @@
|
||||
DiagnosticDeriveError,
|
||||
};
|
||||
use crate::diagnostics::utils::{
|
||||
build_field_mapping, report_error_if_not_applied_to_span, report_type_error,
|
||||
build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error,
|
||||
should_generate_set_arg, type_is_unit, type_matches_path, FieldInfo, FieldInnerTy, FieldMap,
|
||||
HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
||||
};
|
||||
@ -152,8 +152,12 @@ pub fn body<'s>(&mut self, variant: &VariantInfo<'s>) -> TokenStream {
|
||||
fn parse_subdiag_attribute(
|
||||
&self,
|
||||
attr: &Attribute,
|
||||
) -> Result<(SubdiagnosticKind, Path), DiagnosticDeriveError> {
|
||||
let (subdiag, slug) = SubdiagnosticKind::from_attr(attr, self)?;
|
||||
) -> Result<Option<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
|
||||
let Some((subdiag, slug)) = SubdiagnosticKind::from_attr(attr, self)? else {
|
||||
// Some attributes aren't errors - like documentation comments - but also aren't
|
||||
// subdiagnostics.
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
if let SubdiagnosticKind::MultipartSuggestion { .. } = subdiag {
|
||||
let meta = attr.parse_meta()?;
|
||||
@ -170,7 +174,7 @@ fn parse_subdiag_attribute(
|
||||
SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
|
||||
});
|
||||
|
||||
Ok((subdiag, slug))
|
||||
Ok(Some((subdiag, slug)))
|
||||
}
|
||||
|
||||
/// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct
|
||||
@ -182,6 +186,11 @@ fn generate_structure_code_for_attr(
|
||||
) -> Result<TokenStream, DiagnosticDeriveError> {
|
||||
let diag = &self.parent.diag;
|
||||
|
||||
// Always allow documentation comments.
|
||||
if is_doc_comment(attr) {
|
||||
return Ok(quote! {});
|
||||
}
|
||||
|
||||
let name = attr.path.segments.last().unwrap().ident.to_string();
|
||||
let name = name.as_str();
|
||||
let meta = attr.parse_meta()?;
|
||||
@ -250,7 +259,11 @@ fn generate_structure_code_for_attr(
|
||||
return Ok(tokens);
|
||||
}
|
||||
|
||||
let (subdiag, slug) = self.parse_subdiag_attribute(attr)?;
|
||||
let Some((subdiag, slug)) = self.parse_subdiag_attribute(attr)? else {
|
||||
// Some attributes aren't errors - like documentation comments - but also aren't
|
||||
// subdiagnostics.
|
||||
return Ok(quote! {});
|
||||
};
|
||||
let fn_ident = format_ident!("{}", subdiag);
|
||||
match subdiag {
|
||||
SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
|
||||
@ -291,6 +304,11 @@ fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> Token
|
||||
.attrs
|
||||
.iter()
|
||||
.map(move |attr| {
|
||||
// Always allow documentation comments.
|
||||
if is_doc_comment(attr) {
|
||||
return quote! {};
|
||||
}
|
||||
|
||||
let name = attr.path.segments.last().unwrap().ident.to_string();
|
||||
let needs_clone =
|
||||
name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_));
|
||||
@ -397,8 +415,11 @@ fn generate_inner_field_code(
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let (subdiag, slug) = self.parse_subdiag_attribute(attr)?;
|
||||
|
||||
let Some((subdiag, slug)) = self.parse_subdiag_attribute(attr)? else {
|
||||
// Some attributes aren't errors - like documentation comments - but also aren't
|
||||
// subdiagnostics.
|
||||
return Ok(quote! {});
|
||||
};
|
||||
let fn_ident = format_ident!("{}", subdiag);
|
||||
match subdiag {
|
||||
SubdiagnosticKind::Label => {
|
||||
|
@ -5,9 +5,9 @@
|
||||
DiagnosticDeriveError,
|
||||
};
|
||||
use crate::diagnostics::utils::{
|
||||
build_field_mapping, new_code_ident, report_error_if_not_applied_to_applicability,
|
||||
report_error_if_not_applied_to_span, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce,
|
||||
SpannedOption, SubdiagnosticKind,
|
||||
build_field_mapping, is_doc_comment, new_code_ident,
|
||||
report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span, FieldInfo,
|
||||
FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
@ -43,6 +43,11 @@ pub(crate) fn into_tokens<'a>(self, mut structure: Structure<'a>) -> TokenStream
|
||||
|
||||
if matches!(ast.data, syn::Data::Enum(..)) {
|
||||
for attr in &ast.attrs {
|
||||
// Always allow documentation comments.
|
||||
if is_doc_comment(attr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
span_err(
|
||||
attr.span().unwrap(),
|
||||
"unsupported type attribute for subdiagnostic enum",
|
||||
@ -173,7 +178,11 @@ fn identify_kind(&mut self) -> Result<Vec<(SubdiagnosticKind, Path)>, Diagnostic
|
||||
let mut kind_slugs = vec![];
|
||||
|
||||
for attr in self.variant.ast().attrs {
|
||||
let (kind, slug) = SubdiagnosticKind::from_attr(attr, self)?;
|
||||
let Some((kind, slug)) = SubdiagnosticKind::from_attr(attr, self)? else {
|
||||
// Some attributes aren't errors - like documentation comments - but also aren't
|
||||
// subdiagnostics.
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some(slug) = slug else {
|
||||
let name = attr.path.segments.last().unwrap().ident.to_string();
|
||||
@ -227,6 +236,11 @@ fn generate_field_attr_code(
|
||||
ast.attrs
|
||||
.iter()
|
||||
.map(|attr| {
|
||||
// Always allow documentation comments.
|
||||
if is_doc_comment(attr) {
|
||||
return quote! {};
|
||||
}
|
||||
|
||||
let info = FieldInfo {
|
||||
binding,
|
||||
ty: inner_ty.inner_type().unwrap_or(&ast.ty),
|
||||
|
@ -477,7 +477,12 @@ impl SubdiagnosticKind {
|
||||
pub(super) fn from_attr(
|
||||
attr: &Attribute,
|
||||
fields: &impl HasFieldMap,
|
||||
) -> Result<(SubdiagnosticKind, Option<Path>), DiagnosticDeriveError> {
|
||||
) -> Result<Option<(SubdiagnosticKind, Option<Path>)>, DiagnosticDeriveError> {
|
||||
// Always allow documentation comments.
|
||||
if is_doc_comment(attr) {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let span = attr.span().unwrap();
|
||||
|
||||
let name = attr.path.segments.last().unwrap().ident.to_string();
|
||||
@ -526,7 +531,9 @@ pub(super) fn from_attr(
|
||||
| SubdiagnosticKind::Note
|
||||
| SubdiagnosticKind::Help
|
||||
| SubdiagnosticKind::Warn
|
||||
| SubdiagnosticKind::MultipartSuggestion { .. } => return Ok((kind, None)),
|
||||
| SubdiagnosticKind::MultipartSuggestion { .. } => {
|
||||
return Ok(Some((kind, None)));
|
||||
}
|
||||
SubdiagnosticKind::Suggestion { .. } => {
|
||||
throw_span_err!(span, "suggestion without `code = \"...\"`")
|
||||
}
|
||||
@ -626,7 +633,7 @@ pub(super) fn from_attr(
|
||||
| SubdiagnosticKind::MultipartSuggestion { .. } => {}
|
||||
}
|
||||
|
||||
Ok((kind, slug))
|
||||
Ok(Some((kind, slug)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -654,3 +661,7 @@ fn span(&self) -> Option<proc_macro2::Span> {
|
||||
pub(super) fn should_generate_set_arg(field: &Field) -> bool {
|
||||
field.attrs.is_empty()
|
||||
}
|
||||
|
||||
pub(super) fn is_doc_comment(attr: &Attribute) -> bool {
|
||||
attr.path.segments.last().unwrap().ident.to_string() == "doc"
|
||||
}
|
||||
|
@ -749,3 +749,12 @@ struct SubdiagnosticEagerSuggestion {
|
||||
#[subdiagnostic(eager)]
|
||||
sub: SubdiagnosticWithSuggestion,
|
||||
}
|
||||
|
||||
/// with a doc comment on the type..
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(compiletest::example, code = "E0123")]
|
||||
struct WithDocComment {
|
||||
/// ..and the field
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
}
|
||||
|
@ -641,3 +641,24 @@ struct BJ {
|
||||
span: Span,
|
||||
r#type: String,
|
||||
}
|
||||
|
||||
/// with a doc comment on the type..
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(parser::add_paren)]
|
||||
struct BK {
|
||||
/// ..and the field
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
}
|
||||
|
||||
/// with a doc comment on the type..
|
||||
#[derive(Subdiagnostic)]
|
||||
enum BL {
|
||||
/// ..and the variant..
|
||||
#[label(parser::add_paren)]
|
||||
Foo {
|
||||
/// ..and the field
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user