2022-04-27 02:57:44 +01:00
|
|
|
#![deny(unused_must_use)]
|
|
|
|
|
|
2022-06-30 08:57:45 +01:00
|
|
|
use crate::diagnostics::diagnostic_builder::{DiagnosticDeriveBuilder, DiagnosticDeriveKind};
|
|
|
|
|
use crate::diagnostics::error::{span_err, DiagnosticDeriveError};
|
|
|
|
|
use crate::diagnostics::utils::{build_field_mapping, SetOnce};
|
|
|
|
|
use proc_macro2::TokenStream;
|
|
|
|
|
use quote::quote;
|
|
|
|
|
use syn::spanned::Spanned;
|
|
|
|
|
use synstructure::Structure;
|
2022-04-27 02:57:44 +01:00
|
|
|
|
2022-04-27 05:24:31 +01:00
|
|
|
/// The central struct for constructing the `into_diagnostic` method from an annotated struct.
|
2022-04-27 02:57:44 +01:00
|
|
|
pub(crate) struct SessionDiagnosticDerive<'a> {
|
|
|
|
|
structure: Structure<'a>,
|
2022-06-29 16:22:27 +01:00
|
|
|
sess: syn::Ident,
|
2022-06-30 08:57:45 +01:00
|
|
|
builder: DiagnosticDeriveBuilder,
|
2022-04-27 02:57:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> SessionDiagnosticDerive<'a> {
|
|
|
|
|
pub(crate) fn new(diag: syn::Ident, sess: syn::Ident, structure: Structure<'a>) -> Self {
|
|
|
|
|
Self {
|
2022-06-30 08:57:45 +01:00
|
|
|
builder: DiagnosticDeriveBuilder {
|
2022-04-27 02:57:44 +01:00
|
|
|
diag,
|
2022-06-29 16:13:01 +01:00
|
|
|
fields: build_field_mapping(&structure),
|
2022-08-19 15:02:10 +02:00
|
|
|
kind: DiagnosticDeriveKind::SessionDiagnostic,
|
2022-04-27 02:57:44 +01:00
|
|
|
code: None,
|
|
|
|
|
slug: None,
|
|
|
|
|
},
|
2022-06-29 16:22:27 +01:00
|
|
|
sess,
|
2022-04-27 02:57:44 +01:00
|
|
|
structure,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn into_tokens(self) -> TokenStream {
|
2022-06-29 16:22:27 +01:00
|
|
|
let SessionDiagnosticDerive { mut structure, sess, mut builder } = self;
|
2022-04-27 02:57:44 +01:00
|
|
|
|
|
|
|
|
let ast = structure.ast();
|
2022-08-19 15:02:10 +02:00
|
|
|
let implementation = {
|
2022-04-27 02:57:44 +01:00
|
|
|
if let syn::Data::Struct(..) = ast.data {
|
2022-06-30 08:57:45 +01:00
|
|
|
let preamble = builder.preamble(&structure);
|
|
|
|
|
let (attrs, args) = builder.body(&mut structure);
|
2022-04-27 02:57:44 +01:00
|
|
|
|
|
|
|
|
let span = ast.span().unwrap();
|
2022-06-29 16:22:27 +01:00
|
|
|
let diag = &builder.diag;
|
2022-08-19 15:02:10 +02:00
|
|
|
let init = match builder.slug.value() {
|
|
|
|
|
None => {
|
2022-06-23 14:51:44 +01:00
|
|
|
span_err(span, "diagnostic slug not specified")
|
|
|
|
|
.help(&format!(
|
2022-08-19 15:02:10 +02:00
|
|
|
"specify the slug as the first argument to the `#[diag(...)]` attribute, \
|
|
|
|
|
such as `#[diag(typeck::example_error)]`",
|
2022-06-23 14:51:44 +01:00
|
|
|
))
|
2022-04-27 02:57:44 +01:00
|
|
|
.emit();
|
2022-06-30 08:57:45 +01:00
|
|
|
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
|
|
|
|
|
}
|
2022-08-19 15:02:10 +02:00
|
|
|
Some(slug) => {
|
2022-04-27 02:57:44 +01:00
|
|
|
quote! {
|
2022-08-19 15:02:10 +02:00
|
|
|
let mut #diag = #sess.struct_diagnostic(rustc_errors::fluent::#slug);
|
2022-04-27 02:57:44 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2022-08-19 15:02:10 +02:00
|
|
|
quote! {
|
2022-04-27 02:57:44 +01:00
|
|
|
#init
|
|
|
|
|
#preamble
|
|
|
|
|
match self {
|
|
|
|
|
#attrs
|
|
|
|
|
}
|
|
|
|
|
match self {
|
|
|
|
|
#args
|
|
|
|
|
}
|
|
|
|
|
#diag
|
2022-08-19 15:02:10 +02:00
|
|
|
}
|
2022-04-27 02:57:44 +01:00
|
|
|
} else {
|
|
|
|
|
span_err(
|
|
|
|
|
ast.span().unwrap(),
|
|
|
|
|
"`#[derive(SessionDiagnostic)]` can only be used on structs",
|
|
|
|
|
)
|
|
|
|
|
.emit();
|
|
|
|
|
|
2022-08-19 15:02:10 +02:00
|
|
|
DiagnosticDeriveError::ErrorHandled.to_compile_error()
|
2022-04-27 02:57:44 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
structure.gen_impl(quote! {
|
2022-08-19 15:02:10 +02:00
|
|
|
gen impl<'__session_diagnostic_sess, G>
|
|
|
|
|
rustc_session::SessionDiagnostic<'__session_diagnostic_sess, G>
|
2022-04-27 02:57:44 +01:00
|
|
|
for @Self
|
2022-08-19 15:02:10 +02:00
|
|
|
where G: rustc_errors::EmissionGuarantee
|
2022-04-27 02:57:44 +01:00
|
|
|
{
|
|
|
|
|
fn into_diagnostic(
|
|
|
|
|
self,
|
|
|
|
|
#sess: &'__session_diagnostic_sess rustc_session::parse::ParseSess
|
2022-08-19 15:02:10 +02:00
|
|
|
) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess, G> {
|
2022-04-27 02:57:44 +01:00
|
|
|
use rustc_errors::IntoDiagnosticArg;
|
|
|
|
|
#implementation
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-30 08:57:45 +01:00
|
|
|
/// The central struct for constructing the `decorate_lint` method from an annotated struct.
|
|
|
|
|
pub(crate) struct LintDiagnosticDerive<'a> {
|
|
|
|
|
structure: Structure<'a>,
|
|
|
|
|
builder: DiagnosticDeriveBuilder,
|
2022-04-27 02:57:44 +01:00
|
|
|
}
|
|
|
|
|
|
2022-06-30 08:57:45 +01:00
|
|
|
impl<'a> LintDiagnosticDerive<'a> {
|
|
|
|
|
pub(crate) fn new(diag: syn::Ident, structure: Structure<'a>) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
builder: DiagnosticDeriveBuilder {
|
|
|
|
|
diag,
|
|
|
|
|
fields: build_field_mapping(&structure),
|
2022-08-19 15:02:10 +02:00
|
|
|
kind: DiagnosticDeriveKind::LintDiagnostic,
|
2022-06-30 08:57:45 +01:00
|
|
|
code: None,
|
|
|
|
|
slug: None,
|
|
|
|
|
},
|
|
|
|
|
structure,
|
2022-04-27 02:57:44 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-30 08:57:45 +01:00
|
|
|
pub(crate) fn into_tokens(self) -> TokenStream {
|
|
|
|
|
let LintDiagnosticDerive { mut structure, mut builder } = self;
|
2022-06-23 14:51:44 +01:00
|
|
|
|
2022-06-30 08:57:45 +01:00
|
|
|
let ast = structure.ast();
|
|
|
|
|
let implementation = {
|
|
|
|
|
if let syn::Data::Struct(..) = ast.data {
|
|
|
|
|
let preamble = builder.preamble(&structure);
|
|
|
|
|
let (attrs, args) = builder.body(&mut structure);
|
2022-04-27 02:57:44 +01:00
|
|
|
|
2022-06-30 08:57:45 +01:00
|
|
|
let diag = &builder.diag;
|
|
|
|
|
let span = ast.span().unwrap();
|
2022-08-19 15:02:10 +02:00
|
|
|
let init = match builder.slug.value() {
|
|
|
|
|
None => {
|
2022-06-30 08:57:45 +01:00
|
|
|
span_err(span, "diagnostic slug not specified")
|
|
|
|
|
.help(&format!(
|
|
|
|
|
"specify the slug as the first argument to the attribute, such as \
|
2022-08-19 15:02:10 +02:00
|
|
|
`#[diag(typeck::example_error)]`",
|
2022-06-30 08:57:45 +01:00
|
|
|
))
|
|
|
|
|
.emit();
|
|
|
|
|
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
|
|
|
|
|
}
|
2022-08-19 15:02:10 +02:00
|
|
|
Some(slug) => {
|
2022-06-30 08:57:45 +01:00
|
|
|
quote! {
|
|
|
|
|
let mut #diag = #diag.build(rustc_errors::fluent::#slug);
|
2022-05-18 10:50:59 -05:00
|
|
|
}
|
|
|
|
|
}
|
2022-06-23 14:51:44 +01:00
|
|
|
};
|
2022-04-27 02:57:44 +01:00
|
|
|
|
2022-06-30 08:57:45 +01:00
|
|
|
let implementation = quote! {
|
|
|
|
|
#init
|
|
|
|
|
#preamble
|
|
|
|
|
match self {
|
|
|
|
|
#attrs
|
2022-04-27 02:57:44 +01:00
|
|
|
}
|
2022-06-30 08:57:45 +01:00
|
|
|
match self {
|
|
|
|
|
#args
|
2022-06-23 14:51:44 +01:00
|
|
|
}
|
2022-06-30 08:57:45 +01:00
|
|
|
#diag.emit();
|
|
|
|
|
};
|
2022-04-27 02:57:44 +01:00
|
|
|
|
2022-06-30 08:57:45 +01:00
|
|
|
implementation
|
|
|
|
|
} else {
|
|
|
|
|
span_err(
|
|
|
|
|
ast.span().unwrap(),
|
|
|
|
|
"`#[derive(LintDiagnostic)]` can only be used on structs",
|
|
|
|
|
)
|
|
|
|
|
.emit();
|
2022-05-07 06:02:11 +01:00
|
|
|
|
2022-06-30 08:57:45 +01:00
|
|
|
DiagnosticDeriveError::ErrorHandled.to_compile_error()
|
2022-04-27 02:57:44 +01:00
|
|
|
}
|
2022-06-30 08:57:45 +01:00
|
|
|
};
|
2022-04-27 02:57:44 +01:00
|
|
|
|
2022-06-30 08:57:45 +01:00
|
|
|
let diag = &builder.diag;
|
|
|
|
|
structure.gen_impl(quote! {
|
|
|
|
|
gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self {
|
|
|
|
|
fn decorate_lint(self, #diag: rustc_errors::LintDiagnosticBuilder<'__a, ()>) {
|
|
|
|
|
use rustc_errors::IntoDiagnosticArg;
|
|
|
|
|
#implementation
|
2022-04-27 02:57:44 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-06-30 08:57:45 +01:00
|
|
|
})
|
2022-04-27 02:57:44 +01:00
|
|
|
}
|
|
|
|
|
}
|