@@ -3,28 +3,38 @@ use rustc_session::{config::ExpectedValues, Session};
3
3
use rustc_span:: edit_distance:: find_best_match_for_name;
4
4
use rustc_span:: { sym, Span , Symbol } ;
5
5
6
+ use crate :: lints;
7
+
6
8
const MAX_CHECK_CFG_NAMES_OR_VALUES : usize = 35 ;
7
9
8
- fn check_cfg_expected_note (
10
+ fn sort_and_truncate_possibilities (
9
11
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 ) {
17
14
let n_possibilities = if sess. opts . unstable_opts . check_cfg_all_expected {
18
15
possibilities. len ( )
19
16
} else {
20
17
std:: cmp:: min ( possibilities. len ( ) , MAX_CHECK_CFG_NAMES_OR_VALUES )
21
18
} ;
22
19
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 ( ) ) ) ;
25
21
26
22
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 ( "`, `" ) ;
28
38
29
39
let mut note = String :: with_capacity ( 50 + possibilities. len ( ) ) ;
30
40
@@ -68,91 +78,95 @@ pub(super) fn unexpected_cfg_name(
68
78
let is_from_cargo = rustc_session:: utils:: was_invoked_from_cargo ( ) ;
69
79
let mut is_feature_cfg = name == sym:: feature;
70
80
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
73
83
// Suggest the most probable if we found one
74
84
} else if let Some ( best_match) = find_best_match_for_name ( & possibilities, name, None ) {
85
+ is_feature_cfg |= best_match == sym:: feature;
86
+
75
87
if let Some ( ExpectedValues :: Some ( best_match_values) ) =
76
88
sess. psess . check_config . expecteds . get ( & best_match)
77
89
{
78
90
// We will soon sort, so the initial order does not matter.
79
91
#[ 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
+ } ;
83
104
84
- let mut should_print_possibilities = true ;
85
105
if let Some ( ( value, value_span) ) = value {
86
106
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
+ }
94
111
} 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
+ }
102
116
} 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
+ }
109
122
} 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
+ }
117
129
} 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
+ }
129
135
}
130
136
} 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
+ }
137
142
}
138
-
139
- is_feature_cfg |= best_match == sym:: feature;
140
143
} else {
141
- if !names_possibilities. is_empty ( ) && names_possibilities. len ( ) <= 3 {
144
+ let similar_values = if !names_possibilities. is_empty ( ) && names_possibilities. len ( ) <= 3 {
142
145
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,
154
168
}
155
- }
169
+ } ;
156
170
157
171
let inst = if let Some ( ( value, _value_span) ) = value {
158
172
let pre = if is_from_cargo { "\\ " } else { "" } ;
@@ -161,15 +175,20 @@ pub(super) fn unexpected_cfg_name(
161
175
format ! ( "cfg({name})" )
162
176
} ;
163
177
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 }
169
187
} 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 } ) ;
173
192
}
174
193
175
194
pub ( super ) fn unexpected_cfg_value (
@@ -200,7 +219,7 @@ pub(super) fn unexpected_cfg_value(
200
219
if !possibilities. is_empty ( ) {
201
220
diag. note ( check_cfg_expected_note (
202
221
sess,
203
- & possibilities,
222
+ possibilities. clone ( ) ,
204
223
"values" ,
205
224
Some ( name) ,
206
225
if have_none_possibility { "(none), " } else { "" } ,
0 commit comments