Improve slug name error
This commit is contained in:
parent
d494502f64
commit
e8e47e0873
4 changed files with 77 additions and 50 deletions
|
@ -5,6 +5,7 @@ use crate::diagnostics::error::{span_err, DiagnosticDeriveError};
|
||||||
use crate::diagnostics::utils::SetOnce;
|
use crate::diagnostics::utils::SetOnce;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
use syn::spanned::Spanned;
|
||||||
use synstructure::Structure;
|
use synstructure::Structure;
|
||||||
|
|
||||||
/// The central struct for constructing the `into_diagnostic` method from an annotated struct.
|
/// The central struct for constructing the `into_diagnostic` method from an annotated struct.
|
||||||
|
@ -45,10 +46,19 @@ impl<'a> DiagnosticDerive<'a> {
|
||||||
.emit();
|
.emit();
|
||||||
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
|
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) => {
|
Some(slug) => {
|
||||||
let check = make_check(slug);
|
|
||||||
quote! {
|
quote! {
|
||||||
#check
|
|
||||||
let mut #diag = #handler.struct_diagnostic(rustc_errors::fluent::#slug);
|
let mut #diag = #handler.struct_diagnostic(rustc_errors::fluent::#slug);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,11 +140,19 @@ impl<'a> LintDiagnosticDerive<'a> {
|
||||||
.emit();
|
.emit();
|
||||||
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
|
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) => {
|
Some(slug) => {
|
||||||
let check = make_check(slug);
|
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#check
|
|
||||||
rustc_errors::fluent::#slug.into()
|
rustc_errors::fluent::#slug.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,53 +179,26 @@ impl<'a> LintDiagnosticDerive<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Mismatch {
|
||||||
|
slug_name: String,
|
||||||
|
crate_name: String,
|
||||||
|
slug_prefix: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mismatch {
|
||||||
/// Checks whether the slug starts with the crate name it's in.
|
/// Checks whether the slug starts with the crate name it's in.
|
||||||
fn make_check(slug: &syn::Path) -> TokenStream {
|
fn check(slug: &syn::Path) -> Option<Mismatch> {
|
||||||
quote! {
|
// If this is missing we're probably in a test, so bail.
|
||||||
const _: () = {
|
let crate_name = std::env::var("CARGO_CRATE_NAME").ok()?;
|
||||||
const krate_str: &str = match option_env!("CARGO_CRATE_NAME") {
|
|
||||||
Some(c) => c,
|
|
||||||
None => "",
|
|
||||||
};
|
|
||||||
const krate: &[u8] = krate_str.as_bytes();
|
|
||||||
|
|
||||||
if krate.len() > 6
|
// If we're not in a "rustc_" crate, bail.
|
||||||
&& krate[0] == b'r'
|
let Some(("rustc", slug_prefix)) = crate_name.split_once("_") else { return None };
|
||||||
&& 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();
|
|
||||||
|
|
||||||
let mut pos = 0;
|
let slug_name = slug.segments.first()?.ident.to_string();
|
||||||
loop {
|
if !slug_name.starts_with(slug_prefix) {
|
||||||
let b = slug[pos];
|
Some(Mismatch { slug_name, slug_prefix: slug_prefix.to_string(), crate_name })
|
||||||
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 a != b {
|
|
||||||
panic!(concat!(
|
|
||||||
"slug \"",
|
|
||||||
stringify!(#slug),
|
|
||||||
"\" does not match the crate it is in"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
pos += 1;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Crate does not start with "rustc_"
|
None
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#![feature(allow_internal_unstable)]
|
#![feature(allow_internal_unstable)]
|
||||||
|
#![feature(if_let_guard)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(proc_macro_diagnostic)]
|
#![feature(proc_macro_diagnostic)]
|
||||||
#![feature(proc_macro_span)]
|
#![feature(proc_macro_span)]
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
// rustc-env:CARGO_CRATE_NAME=rustc_dummy
|
||||||
|
|
||||||
|
#![feature(rustc_private)]
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
extern crate rustc_span;
|
||||||
|
use rustc_span::symbol::Ident;
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
extern crate rustc_macros;
|
||||||
|
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||||
|
|
||||||
|
extern crate rustc_middle;
|
||||||
|
use rustc_middle::ty::Ty;
|
||||||
|
|
||||||
|
extern crate rustc_errors;
|
||||||
|
use rustc_errors::{Applicability, MultiSpan};
|
||||||
|
|
||||||
|
extern crate rustc_session;
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(compiletest_example, code = "E0123")]
|
||||||
|
//~^ ERROR diagnostic slug and crate name do not match
|
||||||
|
struct Hello {}
|
|
@ -0,0 +1,11 @@
|
||||||
|
error: diagnostic slug and crate name do not match
|
||||||
|
--> $DIR/enforce_slug_naming.rs:22:8
|
||||||
|
|
|
||||||
|
LL | #[diag(compiletest_example, code = "E0123")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: slug is `compiletest_example` but the crate name is `rustc_dummy`
|
||||||
|
= help: expected a slug starting with `dummy_...`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue