mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-21 22:34:05 +00:00
Improve slug name error
This commit is contained in:
parent
d494502f64
commit
e8e47e0873
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![feature(allow_internal_unstable)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(never_type)]
|
||||
#![feature(proc_macro_diagnostic)]
|
||||
#![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…
Reference in New Issue
Block a user