Skip to content

Commit b1ae167

Browse files
committed
Convert unexpected_cfg_name to struct diagnostics
1 parent 55c8590 commit b1ae167

File tree

3 files changed

+230
-86
lines changed

3 files changed

+230
-86
lines changed

compiler/rustc_lint/messages.ftl

+16
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,22 @@ lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::Manual
699699
.label = argument has type `{$arg_ty}`
700700
.suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value
701701
702+
lint_unexpected_cfg_name_add_cargo_feature = consider using a Cargo feature instead or adding `{$build_rs_println}` to the top of a `build.rs`
703+
lint_unexpected_cfg_name_add_cmdline_arg = to expect this configuration use `{$cmdline_arg}`
704+
lint_unexpected_cfg_name_define_features = consider defining some features in `Cargo.toml`
705+
lint_unexpected_cfg_name_doc_cargo = see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration
706+
lint_unexpected_cfg_name_doc_rustc = see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
707+
lint_unexpected_cfg_name_expected_names = expected names are: `{$possibilities}`{$and_more ->
708+
[0] {""}
709+
*[others] and {$and_more} more
710+
}
711+
lint_unexpected_cfg_name_expected_values = expected values for `{$best_match}` are: `{$possibilities}`
712+
lint_unexpected_cfg_name_similar_name = there is a config with a similar name
713+
lint_unexpected_cfg_name_similar_name_different_values = there is a config with a similar name and different values
714+
lint_unexpected_cfg_name_similar_name_no_value = there is a config with a similar name and no value
715+
lint_unexpected_cfg_name_similar_name_value = there is a config with a similar name and value
716+
lint_unexpected_cfg_name_with_similar_value = found config with similar value
717+
702718
lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op
703719
.label = this function will not propagate the caller location
704720

compiler/rustc_lint/src/context/diagnostics/check_cfg.rs

+104-85
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,38 @@ use rustc_session::{config::ExpectedValues, Session};
33
use rustc_span::edit_distance::find_best_match_for_name;
44
use rustc_span::{sym, Span, Symbol};
55

6+
use crate::lints;
7+
68
const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35;
79

8-
fn check_cfg_expected_note(
10+
fn sort_and_truncate_possibilities(
911
sess: &Session,
10-
possibilities: &[Symbol],
11-
type_: &str,
12-
name: Option<Symbol>,
13-
suffix: &str,
14-
) -> String {
15-
use std::fmt::Write;
16-
12+
mut possibilities: Vec<Symbol>,
13+
) -> (Vec<Symbol>, usize) {
1714
let n_possibilities = if sess.opts.unstable_opts.check_cfg_all_expected {
1815
possibilities.len()
1916
} else {
2017
std::cmp::min(possibilities.len(), MAX_CHECK_CFG_NAMES_OR_VALUES)
2118
};
2219

23-
let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>();
24-
possibilities.sort();
20+
possibilities.sort_by(|s1, s2| s1.as_str().cmp(s2.as_str()));
2521

2622
let and_more = possibilities.len().saturating_sub(n_possibilities);
27-
let possibilities = possibilities[..n_possibilities].join("`, `");
23+
possibilities.truncate(n_possibilities);
24+
(possibilities, and_more)
25+
}
26+
27+
fn check_cfg_expected_note(
28+
sess: &Session,
29+
possibilities: Vec<Symbol>,
30+
type_: &str,
31+
name: Option<Symbol>,
32+
suffix: &str,
33+
) -> String {
34+
use std::fmt::Write;
35+
36+
let (possibilities, and_more) = sort_and_truncate_possibilities(sess, possibilities);
37+
let possibilities = possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>().join("`, `");
2838

2939
let mut note = String::with_capacity(50 + possibilities.len());
3040

@@ -68,91 +78,95 @@ pub(super) fn unexpected_cfg_name(
6878
let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
6979
let mut is_feature_cfg = name == sym::feature;
7080

71-
if is_feature_cfg && is_from_cargo {
72-
diag.help("consider defining some features in `Cargo.toml`");
81+
let code_sugg = if is_feature_cfg && is_from_cargo {
82+
lints::UnexpectedCfgNameCodeSugg::ConsiderDefiningFeatures
7383
// Suggest the most probable if we found one
7484
} else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
85+
is_feature_cfg |= best_match == sym::feature;
86+
7587
if let Some(ExpectedValues::Some(best_match_values)) =
7688
sess.psess.check_config.expecteds.get(&best_match)
7789
{
7890
// We will soon sort, so the initial order does not matter.
7991
#[allow(rustc::potential_query_instability)]
80-
let mut possibilities =
81-
best_match_values.iter().flatten().map(Symbol::as_str).collect::<Vec<_>>();
82-
possibilities.sort();
92+
let mut possibilities = best_match_values.iter().flatten().collect::<Vec<_>>();
93+
possibilities.sort_by_key(|s| s.as_str());
94+
95+
let get_possibilities_sub = || {
96+
if !possibilities.is_empty() {
97+
let possibilities =
98+
possibilities.iter().copied().cloned().collect::<Vec<_>>().into();
99+
Some(lints::UnexpectedCfgNameExpectedValues { best_match, possibilities })
100+
} else {
101+
None
102+
}
103+
};
83104

84-
let mut should_print_possibilities = true;
85105
if let Some((value, value_span)) = value {
86106
if best_match_values.contains(&Some(value)) {
87-
diag.span_suggestion(
88-
name_span,
89-
"there is a config with a similar name and value",
90-
best_match,
91-
Applicability::MaybeIncorrect,
92-
);
93-
should_print_possibilities = false;
107+
lints::UnexpectedCfgNameCodeSugg::SimilarNameAndValue {
108+
span: name_span,
109+
code: best_match.to_string(),
110+
}
94111
} else if best_match_values.contains(&None) {
95-
diag.span_suggestion(
96-
name_span.to(value_span),
97-
"there is a config with a similar name and no value",
98-
best_match,
99-
Applicability::MaybeIncorrect,
100-
);
101-
should_print_possibilities = false;
112+
lints::UnexpectedCfgNameCodeSugg::SimilarNameNoValue {
113+
span: name_span.to(value_span),
114+
code: best_match.to_string(),
115+
}
102116
} else if let Some(first_value) = possibilities.first() {
103-
diag.span_suggestion(
104-
name_span.to(value_span),
105-
"there is a config with a similar name and different values",
106-
format!("{best_match} = \"{first_value}\""),
107-
Applicability::MaybeIncorrect,
108-
);
117+
lints::UnexpectedCfgNameCodeSugg::SimilarNameDifferentValues {
118+
span: name_span.to(value_span),
119+
code: format!("{best_match} = \"{first_value}\""),
120+
expected: get_possibilities_sub(),
121+
}
109122
} else {
110-
diag.span_suggestion(
111-
name_span.to(value_span),
112-
"there is a config with a similar name and different values",
113-
best_match,
114-
Applicability::MaybeIncorrect,
115-
);
116-
};
123+
lints::UnexpectedCfgNameCodeSugg::SimilarNameDifferentValues {
124+
span: name_span.to(value_span),
125+
code: best_match.to_string(),
126+
expected: get_possibilities_sub(),
127+
}
128+
}
117129
} else {
118-
diag.span_suggestion(
119-
name_span,
120-
"there is a config with a similar name",
121-
best_match,
122-
Applicability::MaybeIncorrect,
123-
);
124-
}
125-
126-
if !possibilities.is_empty() && should_print_possibilities {
127-
let possibilities = possibilities.join("`, `");
128-
diag.help(format!("expected values for `{best_match}` are: `{possibilities}`"));
130+
lints::UnexpectedCfgNameCodeSugg::SimilarName {
131+
span: name_span,
132+
code: best_match.to_string(),
133+
expected: get_possibilities_sub(),
134+
}
129135
}
130136
} else {
131-
diag.span_suggestion(
132-
name_span,
133-
"there is a config with a similar name",
134-
best_match,
135-
Applicability::MaybeIncorrect,
136-
);
137+
lints::UnexpectedCfgNameCodeSugg::SimilarName {
138+
span: name_span,
139+
code: best_match.to_string(),
140+
expected: None,
141+
}
137142
}
138-
139-
is_feature_cfg |= best_match == sym::feature;
140143
} else {
141-
if !names_possibilities.is_empty() && names_possibilities.len() <= 3 {
144+
let similar_values = if !names_possibilities.is_empty() && names_possibilities.len() <= 3 {
142145
names_possibilities.sort();
143-
for cfg_name in names_possibilities.iter() {
144-
diag.span_suggestion(
145-
name_span,
146-
"found config with similar value",
147-
format!("{cfg_name} = \"{name}\""),
148-
Applicability::MaybeIncorrect,
149-
);
150-
}
151-
}
152-
if !possibilities.is_empty() {
153-
diag.help_once(check_cfg_expected_note(sess, &possibilities, "names", None, ""));
146+
names_possibilities
147+
.iter()
148+
.map(|cfg_name| lints::UnexpectedCfgNameWithSimilarValue {
149+
span: name_span,
150+
code: format!("{cfg_name} = \"{name}\""),
151+
})
152+
.collect()
153+
} else {
154+
vec![]
155+
};
156+
let expected_names = if !possibilities.is_empty() {
157+
let (possibilities, and_more) = sort_and_truncate_possibilities(sess, possibilities);
158+
Some(lints::UnexpectedCfgNameExpectedNames {
159+
possibilities: possibilities.into(),
160+
and_more,
161+
})
162+
} else {
163+
None
164+
};
165+
lints::UnexpectedCfgNameCodeSugg::SimilarValues {
166+
with_similar_values: similar_values,
167+
expected_names,
154168
}
155-
}
169+
};
156170

157171
let inst = if let Some((value, _value_span)) = value {
158172
let pre = if is_from_cargo { "\\" } else { "" };
@@ -161,15 +175,20 @@ pub(super) fn unexpected_cfg_name(
161175
format!("cfg({name})")
162176
};
163177

164-
if is_from_cargo {
165-
if !is_feature_cfg {
166-
diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`"));
167-
}
168-
diag.note("see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration");
178+
let meta_sugg = if is_from_cargo {
179+
let sub = if !is_feature_cfg {
180+
Some(lints::UnexpectedCfgNameCargoSugg {
181+
build_rs_println: format!("println!(\"cargo:rustc-check-cfg={inst}\");"),
182+
})
183+
} else {
184+
None
185+
};
186+
lints::UnexpectedCfgNameMetaSugg::FromCargo { sub }
169187
} else {
170-
diag.help(format!("to expect this configuration use `--check-cfg={inst}`"));
171-
diag.note("see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration");
172-
}
188+
lints::UnexpectedCfgNameMetaSugg::Standalone { cmdline_arg: format!("--check-cfg={inst}") }
189+
};
190+
191+
diag.subdiagnostic(diag.dcx, lints::UnexpectedCfgNameSub { code_sugg, meta_sugg });
173192
}
174193

175194
pub(super) fn unexpected_cfg_value(
@@ -200,7 +219,7 @@ pub(super) fn unexpected_cfg_value(
200219
if !possibilities.is_empty() {
201220
diag.note(check_cfg_expected_note(
202221
sess,
203-
&possibilities,
222+
possibilities.clone(),
204223
"values",
205224
Some(name),
206225
if have_none_possibility { "(none), " } else { "" },

compiler/rustc_lint/src/lints.rs

+110-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::num::NonZero;
55
use crate::errors::RequestedLevel;
66
use crate::fluent_generated as fluent;
77
use rustc_errors::{
8-
codes::*, Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString,
8+
codes::*, Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, DiagSymbolList,
99
ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, SubdiagMessageOp,
1010
Subdiagnostic, SuggestionStyle,
1111
};
@@ -2340,3 +2340,112 @@ pub struct BreakWithLabelAndLoopSub {
23402340
#[suggestion_part(code = ")")]
23412341
pub right: Span,
23422342
}
2343+
2344+
#[derive(Subdiagnostic)]
2345+
pub struct UnexpectedCfgNameSub {
2346+
#[subdiagnostic]
2347+
pub code_sugg: UnexpectedCfgNameCodeSugg,
2348+
#[subdiagnostic]
2349+
pub meta_sugg: UnexpectedCfgNameMetaSugg,
2350+
}
2351+
2352+
#[derive(Subdiagnostic)]
2353+
pub enum UnexpectedCfgNameMetaSugg {
2354+
#[note(lint_unexpected_cfg_name_doc_cargo)]
2355+
FromCargo {
2356+
#[subdiagnostic]
2357+
sub: Option<UnexpectedCfgNameCargoSugg>,
2358+
},
2359+
#[help(lint_unexpected_cfg_name_add_cmdline_arg)]
2360+
#[note(lint_unexpected_cfg_name_doc_rustc)]
2361+
Standalone { cmdline_arg: String },
2362+
}
2363+
2364+
#[derive(Subdiagnostic)]
2365+
#[help(lint_unexpected_cfg_name_add_cargo_feature)]
2366+
pub struct UnexpectedCfgNameCargoSugg {
2367+
pub build_rs_println: String,
2368+
}
2369+
2370+
#[derive(Subdiagnostic)]
2371+
pub enum UnexpectedCfgNameCodeSugg {
2372+
#[help(lint_unexpected_cfg_name_define_features)]
2373+
ConsiderDefiningFeatures,
2374+
#[suggestion(
2375+
lint_unexpected_cfg_name_similar_name_value,
2376+
applicability = "maybe-incorrect",
2377+
code = "{code}"
2378+
)]
2379+
SimilarNameAndValue {
2380+
#[primary_span]
2381+
span: Span,
2382+
code: String,
2383+
},
2384+
#[suggestion(
2385+
lint_unexpected_cfg_name_similar_name_no_value,
2386+
applicability = "maybe-incorrect",
2387+
code = "{code}"
2388+
)]
2389+
SimilarNameNoValue {
2390+
#[primary_span]
2391+
span: Span,
2392+
code: String,
2393+
},
2394+
#[suggestion(
2395+
lint_unexpected_cfg_name_similar_name_different_values,
2396+
applicability = "maybe-incorrect",
2397+
code = "{code}"
2398+
)]
2399+
SimilarNameDifferentValues {
2400+
#[primary_span]
2401+
span: Span,
2402+
code: String,
2403+
#[subdiagnostic]
2404+
expected: Option<UnexpectedCfgNameExpectedValues>,
2405+
},
2406+
#[suggestion(
2407+
lint_unexpected_cfg_name_similar_name,
2408+
applicability = "maybe-incorrect",
2409+
code = "{code}"
2410+
)]
2411+
SimilarName {
2412+
#[primary_span]
2413+
span: Span,
2414+
code: String,
2415+
#[subdiagnostic]
2416+
expected: Option<UnexpectedCfgNameExpectedValues>,
2417+
},
2418+
SimilarValues {
2419+
#[subdiagnostic]
2420+
with_similar_values: Vec<UnexpectedCfgNameWithSimilarValue>,
2421+
#[subdiagnostic]
2422+
expected_names: Option<UnexpectedCfgNameExpectedNames>,
2423+
},
2424+
}
2425+
2426+
#[derive(Subdiagnostic)]
2427+
#[help(lint_unexpected_cfg_name_expected_values)]
2428+
pub struct UnexpectedCfgNameExpectedValues {
2429+
pub best_match: Symbol,
2430+
pub possibilities: DiagSymbolList,
2431+
}
2432+
2433+
#[derive(Subdiagnostic)]
2434+
#[suggestion(
2435+
lint_unexpected_cfg_name_with_similar_value,
2436+
applicability = "maybe-incorrect",
2437+
code = "{code}"
2438+
)]
2439+
pub struct UnexpectedCfgNameWithSimilarValue {
2440+
#[primary_span]
2441+
pub span: Span,
2442+
pub code: String,
2443+
}
2444+
2445+
#[derive(Subdiagnostic)]
2446+
// FIXME: help_once
2447+
#[help(lint_unexpected_cfg_name_expected_names)]
2448+
pub struct UnexpectedCfgNameExpectedNames {
2449+
pub possibilities: DiagSymbolList,
2450+
pub and_more: usize,
2451+
}

0 commit comments

Comments
 (0)