@@ -247,21 +247,10 @@ impl LintStore {
247
247
{
248
248
match self . by_name . get ( lint_name) {
249
249
Some ( & Id ( lint_id) ) => Ok ( lint_id) ,
250
- Some ( & Renamed ( ref new_name, lint_id) ) => {
251
- let warning = format ! ( "lint {} has been renamed to {}" ,
252
- lint_name, new_name) ;
253
- match span {
254
- Some ( span) => sess. span_warn ( span, & warning[ ..] ) ,
255
- None => sess. warn ( & warning[ ..] ) ,
256
- } ;
250
+ Some ( & Renamed ( _, lint_id) ) => {
257
251
Ok ( lint_id)
258
252
} ,
259
253
Some ( & Removed ( ref reason) ) => {
260
- let warning = format ! ( "lint {} has been removed: {}" , lint_name, reason) ;
261
- match span {
262
- Some ( span) => sess. span_warn ( span, & warning[ ..] ) ,
263
- None => sess. warn ( & warning[ ..] )
264
- }
265
254
Err ( FindLintError :: Removed )
266
255
} ,
267
256
None => Err ( FindLintError :: NotFound )
@@ -270,8 +259,12 @@ impl LintStore {
270
259
271
260
pub fn process_command_line ( & mut self , sess : & Session ) {
272
261
for & ( ref lint_name, level) in & sess. opts . lint_opts {
262
+ check_lint_name_cmdline ( sess, self ,
263
+ & lint_name[ ..] , level) ;
264
+
273
265
match self . find_lint ( & lint_name[ ..] , sess, None ) {
274
266
Ok ( lint_id) => self . set_level ( lint_id, ( level, CommandLine ) ) ,
267
+ Err ( FindLintError :: Removed ) => { }
275
268
Err ( _) => {
276
269
match self . lint_groups . iter ( ) . map ( |( & x, pair) | ( x, pair. 0 . clone ( ) ) )
277
270
. collect :: < FnvHashMap < & ' static str ,
@@ -283,8 +276,11 @@ impl LintStore {
283
276
self . set_level ( * lint_id, ( level, CommandLine ) ) )
284
277
. collect :: < Vec < ( ) > > ( ) ;
285
278
}
286
- None => sess. err ( & format ! ( "unknown {} flag: {}" ,
287
- level. as_str( ) , lint_name) ) ,
279
+ None => {
280
+ // The lint or lint group doesn't exist.
281
+ // This is an error, but it was handled
282
+ // by check_lint_name_cmdline.
283
+ }
288
284
}
289
285
}
290
286
}
@@ -359,29 +355,39 @@ pub fn gather_attrs(attrs: &[ast::Attribute])
359
355
-> Vec < Result < ( InternedString , Level , Span ) , Span > > {
360
356
let mut out = vec ! ( ) ;
361
357
for attr in attrs {
362
- let level = match Level :: from_str ( & attr. name ( ) ) {
363
- None => continue ,
364
- Some ( lvl) => lvl,
365
- } ;
358
+ let r = gather_attr ( attr) ;
359
+ out. extend ( r. into_iter ( ) ) ;
360
+ }
361
+ out
362
+ }
366
363
367
- attr:: mark_used ( attr) ;
364
+ pub fn gather_attr ( attr : & ast:: Attribute )
365
+ -> Vec < Result < ( InternedString , Level , Span ) , Span > > {
366
+ let mut out = vec ! ( ) ;
368
367
369
- let meta = & attr. node . value ;
370
- let metas = match meta. node {
371
- ast:: MetaList ( _, ref metas) => metas,
372
- _ => {
373
- out. push ( Err ( meta. span ) ) ;
374
- continue ;
375
- }
376
- } ;
368
+ let level = match Level :: from_str ( & attr. name ( ) ) {
369
+ None => return out,
370
+ Some ( lvl) => lvl,
371
+ } ;
377
372
378
- for meta in metas {
379
- out. push ( match meta. node {
380
- ast:: MetaWord ( ref lint_name) => Ok ( ( lint_name. clone ( ) , level, meta. span ) ) ,
381
- _ => Err ( meta. span ) ,
382
- } ) ;
373
+ attr:: mark_used ( attr) ;
374
+
375
+ let meta = & attr. node . value ;
376
+ let metas = match meta. node {
377
+ ast:: MetaList ( _, ref metas) => metas,
378
+ _ => {
379
+ out. push ( Err ( meta. span ) ) ;
380
+ return out;
383
381
}
382
+ } ;
383
+
384
+ for meta in metas {
385
+ out. push ( match meta. node {
386
+ ast:: MetaWord ( ref lint_name) => Ok ( ( lint_name. clone ( ) , level, meta. span ) ) ,
387
+ _ => Err ( meta. span ) ,
388
+ } ) ;
384
389
}
390
+
385
391
out
386
392
}
387
393
@@ -587,9 +593,9 @@ pub trait LintContext: Sized {
587
593
( * lint_id, level, span) )
588
594
. collect ( ) ,
589
595
None => {
590
- self . span_lint ( builtin :: UNKNOWN_LINTS , span ,
591
- & format ! ( "unknown `{}` attribute: `{}`" ,
592
- level . as_str ( ) , lint_name ) ) ;
596
+ // The lint or lint group doesn't exist.
597
+ // This is an error, but it was handled
598
+ // by check_lint_name_attribute.
593
599
continue ;
594
600
}
595
601
}
@@ -901,6 +907,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
901
907
}
902
908
903
909
fn visit_attribute ( & mut self , attr : & ast:: Attribute ) {
910
+ check_lint_name_attribute ( self , attr) ;
904
911
run_lints ! ( self , check_attribute, late_passes, attr) ;
905
912
}
906
913
}
@@ -1114,6 +1121,113 @@ impl LateLintPass for GatherNodeLevels {
1114
1121
}
1115
1122
}
1116
1123
1124
+ enum CheckLintNameResult < ' a > {
1125
+ Ok ,
1126
+ // Lint doesn't exist
1127
+ NoLint ,
1128
+ // The lint is either renamed or removed and a warning was
1129
+ // generated in the DiagnosticBuilder
1130
+ Mentioned ( DiagnosticBuilder < ' a > )
1131
+ }
1132
+
1133
+ /// Checks the name of a lint for its existence, and whether it was
1134
+ /// renamed or removed. Generates a DiagnosticBuilder containing a
1135
+ /// warning for renamed and removed lints. This is over both lint
1136
+ /// names from attributes and those passed on the command line. Since
1137
+ /// it emits non-fatal warnings and there are *two* lint passes that
1138
+ /// inspect attributes, this is only run from the late pass to avoid
1139
+ /// printing duplicate warnings.
1140
+ fn check_lint_name < ' a > ( sess : & ' a Session ,
1141
+ lint_cx : & LintStore ,
1142
+ lint_name : & str ,
1143
+ span : Option < Span > ) -> CheckLintNameResult < ' a > {
1144
+ match lint_cx. by_name . get ( lint_name) {
1145
+ Some ( & Renamed ( ref new_name, _) ) => {
1146
+ let warning = format ! ( "lint {} has been renamed to {}" ,
1147
+ lint_name, new_name) ;
1148
+ let db = match span {
1149
+ Some ( span) => sess. struct_span_warn ( span, & warning[ ..] ) ,
1150
+ None => sess. struct_warn ( & warning[ ..] ) ,
1151
+ } ;
1152
+ CheckLintNameResult :: Mentioned ( db)
1153
+ } ,
1154
+ Some ( & Removed ( ref reason) ) => {
1155
+ let warning = format ! ( "lint {} has been removed: {}" , lint_name, reason) ;
1156
+ let db = match span {
1157
+ Some ( span) => sess. struct_span_warn ( span, & warning[ ..] ) ,
1158
+ None => sess. struct_warn ( & warning[ ..] )
1159
+ } ;
1160
+ CheckLintNameResult :: Mentioned ( db)
1161
+ } ,
1162
+ None => {
1163
+ match lint_cx. lint_groups . get ( lint_name) {
1164
+ None => {
1165
+ CheckLintNameResult :: NoLint
1166
+ }
1167
+ Some ( _) => {
1168
+ /* lint group exists */
1169
+ CheckLintNameResult :: Ok
1170
+ }
1171
+ }
1172
+ }
1173
+ Some ( _) => {
1174
+ /* lint exists */
1175
+ CheckLintNameResult :: Ok
1176
+ }
1177
+ }
1178
+ }
1179
+
1180
+ // Checks the validity of lint names derived from attributes
1181
+ fn check_lint_name_attribute ( cx : & LateContext , attr : & ast:: Attribute ) {
1182
+ for result in gather_attr ( attr) {
1183
+ match result {
1184
+ Err ( _) => {
1185
+ // Malformed lint attr. Reported by with_lint_attrs
1186
+ continue ;
1187
+ }
1188
+ Ok ( ( lint_name, _, span) ) => {
1189
+ match check_lint_name ( & cx. tcx . sess , & cx. lints , & lint_name[ ..] , Some ( span) ) {
1190
+ CheckLintNameResult :: Ok => ( ) ,
1191
+ CheckLintNameResult :: Mentioned ( mut db) => {
1192
+ db. emit ( ) ;
1193
+ }
1194
+ CheckLintNameResult :: NoLint => {
1195
+ cx. span_lint ( builtin:: UNKNOWN_LINTS , span,
1196
+ & format ! ( "unknown lint: `{}`" ,
1197
+ lint_name) ) ;
1198
+ }
1199
+ }
1200
+ }
1201
+ }
1202
+ }
1203
+ }
1204
+
1205
+ // Checks the validity of lint names derived from the command line
1206
+ fn check_lint_name_cmdline ( sess : & Session , lint_cx : & LintStore ,
1207
+ lint_name : & str , level : Level ) {
1208
+ let db = match check_lint_name ( sess, lint_cx, lint_name, None ) {
1209
+ CheckLintNameResult :: Ok => None ,
1210
+ CheckLintNameResult :: Mentioned ( db) => Some ( db) ,
1211
+ CheckLintNameResult :: NoLint => {
1212
+ Some ( sess. struct_err ( & format ! ( "unknown lint: `{}`" , lint_name) ) )
1213
+ }
1214
+ } ;
1215
+
1216
+ if let Some ( mut db) = db {
1217
+ let msg = format ! ( "requested on the command line with `{} {}`" ,
1218
+ match level {
1219
+ Level :: Allow => "-A" ,
1220
+ Level :: Warn => "-W" ,
1221
+ Level :: Deny => "-D" ,
1222
+ Level :: Forbid => "-F" ,
1223
+ } ,
1224
+ lint_name) ;
1225
+ db. note ( & msg) ;
1226
+ db. emit ( ) ;
1227
+ }
1228
+ }
1229
+
1230
+
1117
1231
/// Perform lint checking on a crate.
1118
1232
///
1119
1233
/// Consumes the `lint_store` field of the `Session`.
0 commit comments