Add typo suggestion for a misspelt Cargo environment variable

This commit is contained in:
yukang 2025-11-06 10:47:47 +08:00
parent 401ae55427
commit 3edd25f049
5 changed files with 170 additions and 0 deletions

View file

@ -156,6 +156,7 @@ builtin_macros_duplicate_macro_attribute = duplicated attribute
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
.cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
.cargo_typo = there is a similar Cargo environment variable: `{$suggested_var}`
.custom = use `std::env::var({$var_expr})` to read the variable at run time
builtin_macros_env_not_unicode = environment variable `{$var}` is not a valid Unicode string

View file

@ -10,6 +10,7 @@ use rustc_ast::token::{self, LitKind};
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{ExprKind, GenericArg, Mutability};
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_span::edit_distance::edit_distance;
use rustc_span::{Ident, Span, Symbol, kw, sym};
use thin_vec::thin_vec;
@ -144,6 +145,12 @@ pub(crate) fn expand_env<'cx>(
if let Some(msg_from_user) = custom_msg {
cx.dcx()
.emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user })
} else if let Some(suggested_var) = find_similar_cargo_var(var.as_str()) {
cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVarTypo {
span,
var: *symbol,
suggested_var: Symbol::intern(suggested_var),
})
} else if is_cargo_env_var(var.as_str()) {
cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar {
span,
@ -176,3 +183,49 @@ fn is_cargo_env_var(var: &str) -> bool {
|| var.starts_with("DEP_")
|| matches!(var, "OUT_DIR" | "OPT_LEVEL" | "PROFILE" | "HOST" | "TARGET")
}
const KNOWN_CARGO_VARS: &[&str] = &[
// List of known Cargo environment variables that are set for crates (not build scripts, OUT_DIR etc).
// See: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates
"CARGO_PKG_VERSION",
"CARGO_PKG_VERSION_MAJOR",
"CARGO_PKG_VERSION_MINOR",
"CARGO_PKG_VERSION_PATCH",
"CARGO_PKG_VERSION_PRE",
"CARGO_PKG_AUTHORS",
"CARGO_PKG_NAME",
"CARGO_PKG_DESCRIPTION",
"CARGO_PKG_HOMEPAGE",
"CARGO_PKG_REPOSITORY",
"CARGO_PKG_LICENSE",
"CARGO_PKG_LICENSE_FILE",
"CARGO_PKG_RUST_VERSION",
"CARGO_PKG_README",
"CARGO_MANIFEST_DIR",
"CARGO_MANIFEST_PATH",
"CARGO_CRATE_NAME",
"CARGO_BIN_NAME",
"CARGO_PRIMARY_PACKAGE",
];
fn find_similar_cargo_var(var: &str) -> Option<&'static str> {
if !var.starts_with("CARGO_") {
return None;
}
let lookup_len = var.chars().count();
let max_dist = std::cmp::max(lookup_len, 3) / 3;
let mut best_match = None;
let mut best_distance = usize::MAX;
for &known_var in KNOWN_CARGO_VARS {
if let Some(distance) = edit_distance(var, known_var, max_dist) {
if distance < best_distance {
best_distance = distance;
best_match = Some(known_var);
}
}
}
best_match
}

View file

@ -535,6 +535,14 @@ pub(crate) enum EnvNotDefined<'a> {
var_expr: &'a rustc_ast::Expr,
},
#[diag(builtin_macros_env_not_defined)]
#[help(builtin_macros_cargo_typo)]
CargoEnvVarTypo {
#[primary_span]
span: Span,
var: Symbol,
suggested_var: Symbol,
},
#[diag(builtin_macros_env_not_defined)]
#[help(builtin_macros_custom)]
CustomEnvVar {
#[primary_span]

View file

@ -0,0 +1,50 @@
//@ edition: 2021
// Regression test for issue #148439
// Ensure that when using misspelled Cargo environment variables in env!(),
fn test_cargo_package_version() {
let _ = env!("CARGO_PACKAGE_VERSION");
//~^ ERROR environment variable `CARGO_PACKAGE_VERSION` not defined at compile time
//~| HELP there is a similar Cargo environment variable: `CARGO_PKG_VERSION`
}
fn test_cargo_package_name() {
let _ = env!("CARGO_PACKAGE_NAME");
//~^ ERROR environment variable `CARGO_PACKAGE_NAME` not defined at compile time
//~| HELP there is a similar Cargo environment variable: `CARGO_PKG_NAME`
}
fn test_cargo_package_authors() {
let _ = env!("CARGO_PACKAGE_AUTHORS");
//~^ ERROR environment variable `CARGO_PACKAGE_AUTHORS` not defined at compile time
//~| HELP there is a similar Cargo environment variable: `CARGO_PKG_AUTHORS`
}
fn test_cargo_manifest_directory() {
let _ = env!("CARGO_MANIFEST_DIRECTORY");
//~^ ERROR environment variable `CARGO_MANIFEST_DIRECTORY` not defined at compile time
//~| HELP there is a similar Cargo environment variable: `CARGO_MANIFEST_DIR`
}
fn test_cargo_pkg_version_typo() {
let _ = env!("CARGO_PKG_VERSIO");
//~^ ERROR environment variable `CARGO_PKG_VERSIO` not defined at compile time
//~| HELP there is a similar Cargo environment variable: `CARGO_PKG_VERSION`
}
fn test_non_cargo_var() {
// Non-Cargo variable should get different help message
let _ = env!("MY_CUSTOM_VAR");
//~^ ERROR environment variable `MY_CUSTOM_VAR` not defined at compile time
//~| HELP use `std::env::var("MY_CUSTOM_VAR")` to read the variable at run time
}
fn test_cargo_unknown_var() {
// Cargo-prefixed but not similar to any known variable
let _ = env!("CARGO_SOMETHING_TOTALLY_UNKNOWN");
//~^ ERROR environment variable `CARGO_SOMETHING_TOTALLY_UNKNOWN` not defined at compile time
//~| HELP Cargo sets build script variables at run time. Use `std::env::var("CARGO_SOMETHING_TOTALLY_UNKNOWN")` instead
}
fn main() {}

View file

@ -0,0 +1,58 @@
error: environment variable `CARGO_PACKAGE_VERSION` not defined at compile time
--> $DIR/env-cargo-var-typo-issue-148439.rs:7:13
|
LL | let _ = env!("CARGO_PACKAGE_VERSION");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: there is a similar Cargo environment variable: `CARGO_PKG_VERSION`
error: environment variable `CARGO_PACKAGE_NAME` not defined at compile time
--> $DIR/env-cargo-var-typo-issue-148439.rs:13:13
|
LL | let _ = env!("CARGO_PACKAGE_NAME");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: there is a similar Cargo environment variable: `CARGO_PKG_NAME`
error: environment variable `CARGO_PACKAGE_AUTHORS` not defined at compile time
--> $DIR/env-cargo-var-typo-issue-148439.rs:19:13
|
LL | let _ = env!("CARGO_PACKAGE_AUTHORS");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: there is a similar Cargo environment variable: `CARGO_PKG_AUTHORS`
error: environment variable `CARGO_MANIFEST_DIRECTORY` not defined at compile time
--> $DIR/env-cargo-var-typo-issue-148439.rs:25:13
|
LL | let _ = env!("CARGO_MANIFEST_DIRECTORY");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: there is a similar Cargo environment variable: `CARGO_MANIFEST_DIR`
error: environment variable `CARGO_PKG_VERSIO` not defined at compile time
--> $DIR/env-cargo-var-typo-issue-148439.rs:31:13
|
LL | let _ = env!("CARGO_PKG_VERSIO");
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: there is a similar Cargo environment variable: `CARGO_PKG_VERSION`
error: environment variable `MY_CUSTOM_VAR` not defined at compile time
--> $DIR/env-cargo-var-typo-issue-148439.rs:38:13
|
LL | let _ = env!("MY_CUSTOM_VAR");
| ^^^^^^^^^^^^^^^^^^^^^
|
= help: use `std::env::var("MY_CUSTOM_VAR")` to read the variable at run time
error: environment variable `CARGO_SOMETHING_TOTALLY_UNKNOWN` not defined at compile time
--> $DIR/env-cargo-var-typo-issue-148439.rs:45:13
|
LL | let _ = env!("CARGO_SOMETHING_TOTALLY_UNKNOWN");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: Cargo sets build script variables at run time. Use `std::env::var("CARGO_SOMETHING_TOTALLY_UNKNOWN")` instead
error: aborting due to 7 previous errors