Improve slug name error

This commit is contained in:
mejrs 2022-11-13 13:10:36 +01:00
parent d494502f64
commit e8e47e0873
4 changed files with 77 additions and 50 deletions

View file

@ -5,6 +5,7 @@ use crate::diagnostics::error::{span_err, DiagnosticDeriveError};
use crate::diagnostics::utils::SetOnce;
use proc_macro2::TokenStream;
use quote::quote;
use syn::spanned::Spanned;
use synstructure::Structure;
/// The central struct for constructing the `into_diagnostic` method from an annotated struct.
@ -45,10 +46,19 @@ impl<'a> DiagnosticDerive<'a> {
.emit();
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
}
Some(slug) if let Some( Mismatch { slug_name, crate_name, slug_prefix }) = Mismatch::check(slug) => {
span_err(slug.span().unwrap(), "diagnostic slug and crate name do not match")
.note(&format!(
"slug is `{slug_name}` but the crate name is `{crate_name}`"
))
.help(&format!(
"expected a slug starting with `{slug_prefix}_...`"
))
.emit();
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
}
Some(slug) => {
let check = make_check(slug);
quote! {
#check
let mut #diag = #handler.struct_diagnostic(rustc_errors::fluent::#slug);
}
}
@ -130,11 +140,19 @@ impl<'a> LintDiagnosticDerive<'a> {
.emit();
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
}
Some(slug) if let Some( Mismatch { slug_name, crate_name, slug_prefix }) = Mismatch::check(slug) => {
span_err(slug.span().unwrap(), "diagnostic slug and crate name do not match")
.note(&format!(
"slug is `{slug_name}` but the crate name is `{crate_name}`"
))
.help(&format!(
"expected a slug starting with `{slug_prefix}_...`"
))
.emit();
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
}
Some(slug) => {
let check = make_check(slug);
quote! {
#check
rustc_errors::fluent::#slug.into()
}
}
@ -161,53 +179,26 @@ impl<'a> LintDiagnosticDerive<'a> {
}
}
/// Checks whether the slug starts with the crate name it's in.
fn make_check(slug: &syn::Path) -> TokenStream {
quote! {
const _: () = {
const krate_str: &str = match option_env!("CARGO_CRATE_NAME") {
Some(c) => c,
None => "",
};
const krate: &[u8] = krate_str.as_bytes();
struct Mismatch {
slug_name: String,
crate_name: String,
slug_prefix: String,
}
if krate.len() > 6
&& krate[0] == b'r'
&& krate[1] == b'u'
&& krate[2] == b's'
&& krate[3] == b't'
&& krate[4] == b'c'
&& krate[5] == b'_'
{
let slug = stringify!(#slug).as_bytes();
impl Mismatch {
/// Checks whether the slug starts with the crate name it's in.
fn check(slug: &syn::Path) -> Option<Mismatch> {
// If this is missing we're probably in a test, so bail.
let crate_name = std::env::var("CARGO_CRATE_NAME").ok()?;
let mut pos = 0;
loop {
let b = slug[pos];
if krate.len() == pos + 6 {
if b != b'_' {
panic!(concat!(
"slug \"",
stringify!(#slug),
"\" does not match the crate it is in"
));
}
break;
}
let a = krate[pos + 6];
// If we're not in a "rustc_" crate, bail.
let Some(("rustc", slug_prefix)) = crate_name.split_once("_") else { return None };
if a != b {
panic!(concat!(
"slug \"",
stringify!(#slug),
"\" does not match the crate it is in"
));
}
pos += 1;
}
} else {
// Crate does not start with "rustc_"
}
};
let slug_name = slug.segments.first()?.ident.to_string();
if !slug_name.starts_with(slug_prefix) {
Some(Mismatch { slug_name, slug_prefix: slug_prefix.to_string(), crate_name })
} else {
None
}
}
}

View file

@ -1,4 +1,5 @@
#![feature(allow_internal_unstable)]
#![feature(if_let_guard)]
#![feature(never_type)]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_span)]