mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
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 @@ use crate::diagnostics::error::{
|
|||||||
DiagnosticDeriveError,
|
DiagnosticDeriveError,
|
||||||
};
|
};
|
||||||
use crate::diagnostics::utils::{
|
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,
|
should_generate_set_arg, type_is_unit, type_matches_path, FieldInfo, FieldInnerTy, FieldMap,
|
||||||
HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
||||||
};
|
};
|
||||||
@ -152,8 +152,12 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
|||||||
fn parse_subdiag_attribute(
|
fn parse_subdiag_attribute(
|
||||||
&self,
|
&self,
|
||||||
attr: &Attribute,
|
attr: &Attribute,
|
||||||
) -> Result<(SubdiagnosticKind, Path), DiagnosticDeriveError> {
|
) -> Result<Option<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
|
||||||
let (subdiag, slug) = SubdiagnosticKind::from_attr(attr, self)?;
|
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 {
|
if let SubdiagnosticKind::MultipartSuggestion { .. } = subdiag {
|
||||||
let meta = attr.parse_meta()?;
|
let meta = attr.parse_meta()?;
|
||||||
@ -170,7 +174,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
|||||||
SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
|
SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok((subdiag, slug))
|
Ok(Some((subdiag, slug)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct
|
/// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct
|
||||||
@ -182,6 +186,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
|||||||
) -> Result<TokenStream, DiagnosticDeriveError> {
|
) -> Result<TokenStream, DiagnosticDeriveError> {
|
||||||
let diag = &self.parent.diag;
|
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 = attr.path.segments.last().unwrap().ident.to_string();
|
||||||
let name = name.as_str();
|
let name = name.as_str();
|
||||||
let meta = attr.parse_meta()?;
|
let meta = attr.parse_meta()?;
|
||||||
@ -250,7 +259,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
|||||||
return Ok(tokens);
|
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);
|
let fn_ident = format_ident!("{}", subdiag);
|
||||||
match subdiag {
|
match subdiag {
|
||||||
SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
|
SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
|
||||||
@ -291,6 +304,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
|||||||
.attrs
|
.attrs
|
||||||
.iter()
|
.iter()
|
||||||
.map(move |attr| {
|
.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 name = attr.path.segments.last().unwrap().ident.to_string();
|
||||||
let needs_clone =
|
let needs_clone =
|
||||||
name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_));
|
name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_));
|
||||||
@ -397,8 +415,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
let fn_ident = format_ident!("{}", subdiag);
|
||||||
match subdiag {
|
match subdiag {
|
||||||
SubdiagnosticKind::Label => {
|
SubdiagnosticKind::Label => {
|
||||||
|
@ -5,9 +5,9 @@ use crate::diagnostics::error::{
|
|||||||
DiagnosticDeriveError,
|
DiagnosticDeriveError,
|
||||||
};
|
};
|
||||||
use crate::diagnostics::utils::{
|
use crate::diagnostics::utils::{
|
||||||
build_field_mapping, new_code_ident, report_error_if_not_applied_to_applicability,
|
build_field_mapping, is_doc_comment, new_code_ident,
|
||||||
report_error_if_not_applied_to_span, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce,
|
report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span, FieldInfo,
|
||||||
SpannedOption, SubdiagnosticKind,
|
FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
||||||
};
|
};
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
@ -43,6 +43,11 @@ impl SubdiagnosticDeriveBuilder {
|
|||||||
|
|
||||||
if matches!(ast.data, syn::Data::Enum(..)) {
|
if matches!(ast.data, syn::Data::Enum(..)) {
|
||||||
for attr in &ast.attrs {
|
for attr in &ast.attrs {
|
||||||
|
// Always allow documentation comments.
|
||||||
|
if is_doc_comment(attr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
span_err(
|
span_err(
|
||||||
attr.span().unwrap(),
|
attr.span().unwrap(),
|
||||||
"unsupported type attribute for subdiagnostic enum",
|
"unsupported type attribute for subdiagnostic enum",
|
||||||
@ -173,7 +178,11 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||||||
let mut kind_slugs = vec![];
|
let mut kind_slugs = vec![];
|
||||||
|
|
||||||
for attr in self.variant.ast().attrs {
|
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 Some(slug) = slug else {
|
||||||
let name = attr.path.segments.last().unwrap().ident.to_string();
|
let name = attr.path.segments.last().unwrap().ident.to_string();
|
||||||
@ -227,6 +236,11 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||||||
ast.attrs
|
ast.attrs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|attr| {
|
.map(|attr| {
|
||||||
|
// Always allow documentation comments.
|
||||||
|
if is_doc_comment(attr) {
|
||||||
|
return quote! {};
|
||||||
|
}
|
||||||
|
|
||||||
let info = FieldInfo {
|
let info = FieldInfo {
|
||||||
binding,
|
binding,
|
||||||
ty: inner_ty.inner_type().unwrap_or(&ast.ty),
|
ty: inner_ty.inner_type().unwrap_or(&ast.ty),
|
||||||
|
@ -477,7 +477,12 @@ impl SubdiagnosticKind {
|
|||||||
pub(super) fn from_attr(
|
pub(super) fn from_attr(
|
||||||
attr: &Attribute,
|
attr: &Attribute,
|
||||||
fields: &impl HasFieldMap,
|
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 span = attr.span().unwrap();
|
||||||
|
|
||||||
let name = attr.path.segments.last().unwrap().ident.to_string();
|
let name = attr.path.segments.last().unwrap().ident.to_string();
|
||||||
@ -526,7 +531,9 @@ impl SubdiagnosticKind {
|
|||||||
| SubdiagnosticKind::Note
|
| SubdiagnosticKind::Note
|
||||||
| SubdiagnosticKind::Help
|
| SubdiagnosticKind::Help
|
||||||
| SubdiagnosticKind::Warn
|
| SubdiagnosticKind::Warn
|
||||||
| SubdiagnosticKind::MultipartSuggestion { .. } => return Ok((kind, None)),
|
| SubdiagnosticKind::MultipartSuggestion { .. } => {
|
||||||
|
return Ok(Some((kind, None)));
|
||||||
|
}
|
||||||
SubdiagnosticKind::Suggestion { .. } => {
|
SubdiagnosticKind::Suggestion { .. } => {
|
||||||
throw_span_err!(span, "suggestion without `code = \"...\"`")
|
throw_span_err!(span, "suggestion without `code = \"...\"`")
|
||||||
}
|
}
|
||||||
@ -626,7 +633,7 @@ impl SubdiagnosticKind {
|
|||||||
| SubdiagnosticKind::MultipartSuggestion { .. } => {}
|
| SubdiagnosticKind::MultipartSuggestion { .. } => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((kind, slug))
|
Ok(Some((kind, slug)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -654,3 +661,7 @@ impl quote::IdentFragment for SubdiagnosticKind {
|
|||||||
pub(super) fn should_generate_set_arg(field: &Field) -> bool {
|
pub(super) fn should_generate_set_arg(field: &Field) -> bool {
|
||||||
field.attrs.is_empty()
|
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)]
|
#[subdiagnostic(eager)]
|
||||||
sub: SubdiagnosticWithSuggestion,
|
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,
|
span: Span,
|
||||||
r#type: String,
|
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