Skip to content

Commit e8e47e0

Browse files
author
mejrs
committed
Improve slug name error
1 parent d494502 commit e8e47e0

File tree

4 files changed

+80
-53
lines changed

4 files changed

+80
-53
lines changed

compiler/rustc_macros/src/diagnostics/diagnostic.rs

+44-53
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::diagnostics::error::{span_err, DiagnosticDeriveError};
55
use crate::diagnostics::utils::SetOnce;
66
use proc_macro2::TokenStream;
77
use quote::quote;
8+
use syn::spanned::Spanned;
89
use 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
}

compiler/rustc_macros/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![feature(allow_internal_unstable)]
2+
#![feature(if_let_guard)]
23
#![feature(never_type)]
34
#![feature(proc_macro_diagnostic)]
45
#![feature(proc_macro_span)]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// rustc-env:CARGO_CRATE_NAME=rustc_dummy
2+
3+
#![feature(rustc_private)]
4+
#![crate_type = "lib"]
5+
6+
extern crate rustc_span;
7+
use rustc_span::symbol::Ident;
8+
use rustc_span::Span;
9+
10+
extern crate rustc_macros;
11+
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
12+
13+
extern crate rustc_middle;
14+
use rustc_middle::ty::Ty;
15+
16+
extern crate rustc_errors;
17+
use rustc_errors::{Applicability, MultiSpan};
18+
19+
extern crate rustc_session;
20+
21+
#[derive(Diagnostic)]
22+
#[diag(compiletest_example, code = "E0123")]
23+
//~^ ERROR diagnostic slug and crate name do not match
24+
struct Hello {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: diagnostic slug and crate name do not match
2+
--> $DIR/enforce_slug_naming.rs:22:8
3+
|
4+
LL | #[diag(compiletest_example, code = "E0123")]
5+
| ^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: slug is `compiletest_example` but the crate name is `rustc_dummy`
8+
= help: expected a slug starting with `dummy_...`
9+
10+
error: aborting due to previous error
11+

0 commit comments

Comments
 (0)