@@ -5,6 +5,7 @@ use crate::diagnostics::error::{span_err, DiagnosticDeriveError};
55use crate :: diagnostics:: utils:: SetOnce ;
66use proc_macro2:: TokenStream ;
77use quote:: quote;
8+ use syn:: spanned:: Spanned ;
89use synstructure:: Structure ;
910
1011/// The central struct for constructing the `into_diagnostic` method from an annotated struct.
@@ -45,10 +46,19 @@ impl<'a> DiagnosticDerive<'a> {
4546 . emit ( ) ;
4647 return DiagnosticDeriveError :: ErrorHandled . to_compile_error ( ) ;
4748 }
49+ Some ( slug) if let Some ( Mismatch { slug_name, crate_name, slug_prefix } ) = Mismatch :: check ( slug) => {
50+ span_err ( slug. span ( ) . unwrap ( ) , "diagnostic slug and crate name do not match" )
51+ . note ( & format ! (
52+ "slug is `{slug_name}` but the crate name is `{crate_name}`"
53+ ) )
54+ . help ( & format ! (
55+ "expected a slug starting with `{slug_prefix}_...`"
56+ ) )
57+ . emit ( ) ;
58+ return DiagnosticDeriveError :: ErrorHandled . to_compile_error ( ) ;
59+ }
4860 Some ( slug) => {
49- let check = make_check ( slug) ;
5061 quote ! {
51- #check
5262 let mut #diag = #handler. struct_diagnostic( rustc_errors:: fluent:: #slug) ;
5363 }
5464 }
@@ -130,11 +140,19 @@ impl<'a> LintDiagnosticDerive<'a> {
130140 . emit ( ) ;
131141 return DiagnosticDeriveError :: ErrorHandled . to_compile_error ( ) ;
132142 }
143+ Some ( slug) if let Some ( Mismatch { slug_name, crate_name, slug_prefix } ) = Mismatch :: check ( slug) => {
144+ span_err ( slug. span ( ) . unwrap ( ) , "diagnostic slug and crate name do not match" )
145+ . note ( & format ! (
146+ "slug is `{slug_name}` but the crate name is `{crate_name}`"
147+ ) )
148+ . help ( & format ! (
149+ "expected a slug starting with `{slug_prefix}_...`"
150+ ) )
151+ . emit ( ) ;
152+ return DiagnosticDeriveError :: ErrorHandled . to_compile_error ( ) ;
153+ }
133154 Some ( slug) => {
134- let check = make_check ( slug) ;
135-
136155 quote ! {
137- #check
138156 rustc_errors:: fluent:: #slug. into( )
139157 }
140158 }
@@ -161,53 +179,26 @@ impl<'a> LintDiagnosticDerive<'a> {
161179 }
162180}
163181
164- /// Checks whether the slug starts with the crate name it's in.
165- fn make_check ( slug : & syn:: Path ) -> TokenStream {
166- quote ! {
167- const _: ( ) = {
168- const krate_str: & str = match option_env!( "CARGO_CRATE_NAME" ) {
169- Some ( c) => c,
170- None => "" ,
171- } ;
172- const krate: & [ u8 ] = krate_str. as_bytes( ) ;
173-
174- if krate. len( ) > 6
175- && krate[ 0 ] == b'r'
176- && krate[ 1 ] == b'u'
177- && krate[ 2 ] == b's'
178- && krate[ 3 ] == b't'
179- && krate[ 4 ] == b'c'
180- && krate[ 5 ] == b'_'
181- {
182- let slug = stringify!( #slug) . as_bytes( ) ;
183-
184- let mut pos = 0 ;
185- loop {
186- let b = slug[ pos] ;
187- if krate. len( ) == pos + 6 {
188- if b != b'_' {
189- panic!( concat!(
190- "slug \" " ,
191- stringify!( #slug) ,
192- "\" does not match the crate it is in"
193- ) ) ;
194- }
195- break ;
196- }
197- let a = krate[ pos + 6 ] ;
198-
199- if a != b {
200- panic!( concat!(
201- "slug \" " ,
202- stringify!( #slug) ,
203- "\" does not match the crate it is in"
204- ) ) ;
205- }
206- pos += 1 ;
207- }
208- } else {
209- // Crate does not start with "rustc_"
210- }
211- } ;
182+ struct Mismatch {
183+ slug_name : String ,
184+ crate_name : String ,
185+ slug_prefix : String ,
186+ }
187+
188+ impl Mismatch {
189+ /// Checks whether the slug starts with the crate name it's in.
190+ fn check ( slug : & syn:: Path ) -> Option < Mismatch > {
191+ // If this is missing we're probably in a test, so bail.
192+ let crate_name = std:: env:: var ( "CARGO_CRATE_NAME" ) . ok ( ) ?;
193+
194+ // If we're not in a "rustc_" crate, bail.
195+ let Some ( ( "rustc" , slug_prefix) ) = crate_name. split_once ( "_" ) else { return None } ;
196+
197+ let slug_name = slug. segments . first ( ) ?. ident . to_string ( ) ;
198+ if !slug_name. starts_with ( slug_prefix) {
199+ Some ( Mismatch { slug_name, slug_prefix : slug_prefix. to_string ( ) , crate_name } )
200+ } else {
201+ None
202+ }
212203 }
213204}
0 commit comments