rustc_macros/diagnostics/
diagnostic.rs1#![deny(unused_must_use)]
2
3use proc_macro2::TokenStream;
4use quote::quote;
5use synstructure::Structure;
6
7use crate::diagnostics::diagnostic_builder::DiagnosticDeriveKind;
8use crate::diagnostics::error::DiagnosticDeriveError;
9
10pub(crate) struct DiagnosticDerive<'a> {
12 structure: Structure<'a>,
13}
14
15impl<'a> DiagnosticDerive<'a> {
16 pub(crate) fn new(structure: Structure<'a>) -> Self {
17 Self { structure }
18 }
19
20 pub(crate) fn into_tokens(self) -> TokenStream {
21 let DiagnosticDerive { mut structure } = self;
22 let kind = DiagnosticDeriveKind::Diagnostic;
23 let implementation = kind.each_variant(&mut structure, |mut builder, variant| {
24 let preamble = builder.preamble(variant);
25 let body = builder.body(variant);
26
27 let Some(message) = builder.primary_message() else {
28 return DiagnosticDeriveError::ErrorHandled.to_compile_error();
29 };
30 let message = message.diag_message(Some(variant));
31
32 let init = quote! {
33 let mut diag = rustc_errors::Diag::new(
34 dcx,
35 level,
36 #message
37 );
38 };
39
40 let formatting_init = &builder.formatting_init;
41 quote! {
42 #init
43 #formatting_init
44 #preamble
45 #body
46 diag
47 }
48 });
49
50 structure.gen_impl(quote! {
52 gen impl<'_sess, G> rustc_errors::Diagnostic<'_sess, G> for @Self
53 where G: rustc_errors::EmissionGuarantee
54 {
55 #[track_caller]
56 fn into_diag(
57 self,
58 dcx: rustc_errors::DiagCtxtHandle<'_sess>,
59 level: rustc_errors::Level
60 ) -> rustc_errors::Diag<'_sess, G> {
61 #implementation
62 }
63 }
64 })
65 }
66}
67
68pub(crate) struct LintDiagnosticDerive<'a> {
70 structure: Structure<'a>,
71}
72
73impl<'a> LintDiagnosticDerive<'a> {
74 pub(crate) fn new(structure: Structure<'a>) -> Self {
75 Self { structure }
76 }
77
78 pub(crate) fn into_tokens(self) -> TokenStream {
79 let LintDiagnosticDerive { mut structure } = self;
80 let kind = DiagnosticDeriveKind::LintDiagnostic;
81 let implementation = kind.each_variant(&mut structure, |mut builder, variant| {
82 let preamble = builder.preamble(variant);
83 let body = builder.body(variant);
84
85 let Some(message) = builder.primary_message() else {
86 return DiagnosticDeriveError::ErrorHandled.to_compile_error();
87 };
88 let message = message.diag_message(Some(variant));
89 let primary_message = quote! {
90 diag.primary_message(#message);
91 };
92
93 let formatting_init = &builder.formatting_init;
94 quote! {
95 #primary_message
96 #preamble
97 #formatting_init
98 #body
99 diag
100 }
101 });
102
103 structure.gen_impl(quote! {
104 gen impl<'__a> rustc_errors::LintDiagnostic<'__a, ()> for @Self {
105 #[track_caller]
106 fn decorate_lint<'__b>(
107 self,
108 diag: &'__b mut rustc_errors::Diag<'__a, ()>
109 ) {
110 #implementation;
111 }
112 }
113 })
114 }
115}