@@ -3,28 +3,38 @@ use rustc_session::{config::ExpectedValues, Session};
33use rustc_span:: edit_distance:: find_best_match_for_name;
44use rustc_span:: { sym, Span , Symbol } ;
55
6+ use crate :: lints;
7+
68const 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
175194pub ( 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 { "" } ,
0 commit comments