From 3d234770b1c83840d18305e8625da38e97da3174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20BRANSTETT?= Date: Sun, 20 Feb 2022 00:48:10 +0100 Subject: [PATCH] Improve diagnostic of the unexpected_cfgs lint --- compiler/rustc_attr/src/builtin.rs | 15 ++++++-- compiler/rustc_lint/src/context.rs | 34 ++++++++++++++++++- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint_defs/src/lib.rs | 1 + src/test/ui/check-cfg/invalid-cfg-name.stderr | 2 +- .../ui/check-cfg/invalid-cfg-value.stderr | 1 + src/test/ui/check-cfg/well-known-names.stderr | 10 ++++-- 7 files changed, 57 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index cd2e150a190..503e172b687 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -8,6 +8,7 @@ use rustc_errors::{struct_span_err, Applicability}; use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; use rustc_macros::HashStable_Generic; use rustc_session::lint::builtin::UNEXPECTED_CFGS; +use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::{feature_err, ParseSess}; use rustc_session::Session; use rustc_span::hygiene::Transparency; @@ -465,11 +466,16 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat let value = cfg.value_str(); if let Some(names_valid) = &sess.check_config.names_valid { if !names_valid.contains(&name) { - sess.buffer_lint( + sess.buffer_lint_with_diagnostic( UNEXPECTED_CFGS, cfg.span, CRATE_NODE_ID, "unexpected `cfg` condition name", + BuiltinLintDiagnostics::UnexpectedCfg( + cfg.ident().unwrap().span, + name, + None, + ), ); } } @@ -477,11 +483,16 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat if let Some(values_valid) = &sess.check_config.values_valid { if let Some(values) = values_valid.get(&name) { if !values.contains(&val) { - sess.buffer_lint( + sess.buffer_lint_with_diagnostic( UNEXPECTED_CFGS, cfg.span, CRATE_NODE_ID, "unexpected `cfg` condition value", + BuiltinLintDiagnostics::UnexpectedCfg( + cfg.name_value_literal_span().unwrap(), + name, + Some(val), + ), ); } } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index d2d853efda2..72a3f5d5fc9 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -766,7 +766,39 @@ pub trait LintContext: Sized { BuiltinLintDiagnostics::NamedAsmLabel(help) => { db.help(&help); db.note("see the asm section of Rust By Example for more information"); - } + }, + BuiltinLintDiagnostics::UnexpectedCfg(span, name, value) => { + let mut possibilities: Vec = if value.is_some() { + let Some(values_valid) = &sess.parse_sess.check_config.values_valid else { + bug!("it shouldn't be possible to have a diagnostic on a value if values checking is not enable"); + }; + let Some(values) = values_valid.get(&name) else { + bug!("it shouldn't be possible to have a diagnostic on a value whose name is not in values"); + }; + values.iter().map(|&s| s).collect() + } else { + let Some(names_valid) = &sess.parse_sess.check_config.names_valid else { + bug!("it shouldn't be possible to have a diagnostic on a value if values checking is not enable"); + }; + names_valid.iter().map(|s| *s).collect() + }; + + // Show the full list if all possible values for a given name, but don't do it + // for names as the possibilities could be very long + if value.is_some() { + // Sorting can take some time, so we only do it if required + possibilities.sort(); + + let possibilities = possibilities.iter().map(Symbol::as_str).intersperse(", ").collect::(); + db.note(&format!("possible values for `{name}` are: {possibilities}")); + } + + // Suggest the most probable if we found one + if let Some(best_match) = find_best_match_for_name(&possibilities, value.unwrap_or(name), None) { + let ponctuation = if value.is_some() { "\"" } else { "" }; + db.span_suggestion(span, "did you mean", format!("{ponctuation}{best_match}{ponctuation}"), Applicability::MaybeIncorrect); + } + }, } // Rewrap `db`, and pass control to the user. decorate(LintDiagnosticBuilder::new(db)); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 69863b5ff82..7182022d252 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -31,6 +31,7 @@ #![feature(box_patterns)] #![feature(crate_visibility_modifier)] #![feature(if_let_guard)] +#![feature(iter_intersperse)] #![feature(iter_order_by)] #![feature(let_else)] #![feature(never_type)] diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 1f834b7212f..e9c62fc4006 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -310,6 +310,7 @@ pub enum BuiltinLintDiagnostics { BreakWithLabelAndLoop(Span), NamedAsmLabel(String), UnicodeTextFlow(Span, String), + UnexpectedCfg(Span, Symbol, Option), } /// Lints that are buffered up early on in the `Session` before the diff --git a/src/test/ui/check-cfg/invalid-cfg-name.stderr b/src/test/ui/check-cfg/invalid-cfg-name.stderr index 2587685afa0..2bd1821c942 100644 --- a/src/test/ui/check-cfg/invalid-cfg-name.stderr +++ b/src/test/ui/check-cfg/invalid-cfg-name.stderr @@ -2,7 +2,7 @@ warning: unexpected `cfg` condition name --> $DIR/invalid-cfg-name.rs:7:7 | LL | #[cfg(widnows)] - | ^^^^^^^ + | ^^^^^^^ help: did you mean: `windows` | = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/src/test/ui/check-cfg/invalid-cfg-value.stderr b/src/test/ui/check-cfg/invalid-cfg-value.stderr index c591d8474a2..23fd5c8c759 100644 --- a/src/test/ui/check-cfg/invalid-cfg-value.stderr +++ b/src/test/ui/check-cfg/invalid-cfg-value.stderr @@ -5,6 +5,7 @@ LL | #[cfg(feature = "sedre")] | ^^^^^^^^^^^^^^^^^ | = note: `#[warn(unexpected_cfgs)]` on by default + = note: possible values for `feature` are: rand, serde, full warning: 1 warning emitted diff --git a/src/test/ui/check-cfg/well-known-names.stderr b/src/test/ui/check-cfg/well-known-names.stderr index a6b9a77dc8d..bdbe4d29d30 100644 --- a/src/test/ui/check-cfg/well-known-names.stderr +++ b/src/test/ui/check-cfg/well-known-names.stderr @@ -2,7 +2,9 @@ warning: unexpected `cfg` condition name --> $DIR/well-known-names.rs:6:7 | LL | #[cfg(target_oz = "linux")] - | ^^^^^^^^^^^^^^^^^^^ + | ---------^^^^^^^^^^ + | | + | help: did you mean: `target_os` | = note: `#[warn(unexpected_cfgs)]` on by default @@ -10,13 +12,15 @@ warning: unexpected `cfg` condition name --> $DIR/well-known-names.rs:13:7 | LL | #[cfg(features = "foo")] - | ^^^^^^^^^^^^^^^^ + | --------^^^^^^^^ + | | + | help: did you mean: `feature` warning: unexpected `cfg` condition name --> $DIR/well-known-names.rs:20:7 | LL | #[cfg(uniw)] - | ^^^^ + | ^^^^ help: did you mean: `unix` warning: 3 warnings emitted