@@ -219,21 +219,10 @@ impl LintStore {
219
219
{
220
220
match self . by_name . get ( lint_name) {
221
221
Some ( & Id ( lint_id) ) => Ok ( lint_id) ,
222
- Some ( & Renamed ( ref new_name, lint_id) ) => {
223
- let warning = format ! ( "lint {} has been renamed to {}" ,
224
- lint_name, new_name) ;
225
- match span {
226
- Some ( span) => sess. span_warn ( span, & warning[ ..] ) ,
227
- None => sess. warn ( & warning[ ..] ) ,
228
- } ;
222
+ Some ( & Renamed ( _, lint_id) ) => {
229
223
Ok ( lint_id)
230
224
} ,
231
225
Some ( & Removed ( ref reason) ) => {
232
- let warning = format ! ( "lint {} has been removed: {}" , lint_name, reason) ;
233
- match span {
234
- Some ( span) => sess. span_warn ( span, & warning[ ..] ) ,
235
- None => sess. warn ( & warning[ ..] )
236
- }
237
226
Err ( FindLintError :: Removed )
238
227
} ,
239
228
None => Err ( FindLintError :: NotFound )
@@ -242,8 +231,12 @@ impl LintStore {
242
231
243
232
pub fn process_command_line ( & mut self , sess : & Session ) {
244
233
for & ( ref lint_name, level) in & sess. opts . lint_opts {
234
+ check_lint_name_cmdline ( sess, self ,
235
+ & lint_name[ ..] , level) ;
236
+
245
237
match self . find_lint ( & lint_name[ ..] , sess, None ) {
246
238
Ok ( lint_id) => self . set_level ( lint_id, ( level, CommandLine ) ) ,
239
+ Err ( FindLintError :: Removed ) => { }
247
240
Err ( _) => {
248
241
match self . lint_groups . iter ( ) . map ( |( & x, pair) | ( x, pair. 0 . clone ( ) ) )
249
242
. collect :: < FnvHashMap < & ' static str ,
@@ -255,8 +248,11 @@ impl LintStore {
255
248
self . set_level ( * lint_id, ( level, CommandLine ) ) )
256
249
. collect :: < Vec < ( ) > > ( ) ;
257
250
}
258
- None => sess. err ( & format ! ( "unknown {} flag: {}" ,
259
- level. as_str( ) , lint_name) ) ,
251
+ None => {
252
+ // The lint or lint group doesn't exist.
253
+ // This is an error, but it was handled
254
+ // by check_lint_name_cmdline.
255
+ }
260
256
}
261
257
}
262
258
}
@@ -331,29 +327,39 @@ pub fn gather_attrs(attrs: &[ast::Attribute])
331
327
-> Vec < Result < ( InternedString , Level , Span ) , Span > > {
332
328
let mut out = vec ! ( ) ;
333
329
for attr in attrs {
334
- let level = match Level :: from_str ( & attr. name ( ) ) {
335
- None => continue ,
336
- Some ( lvl) => lvl,
337
- } ;
330
+ let r = gather_attr ( attr) ;
331
+ out. extend ( r. into_iter ( ) ) ;
332
+ }
333
+ out
334
+ }
338
335
339
- attr:: mark_used ( attr) ;
336
+ pub fn gather_attr ( attr : & ast:: Attribute )
337
+ -> Vec < Result < ( InternedString , Level , Span ) , Span > > {
338
+ let mut out = vec ! ( ) ;
340
339
341
- let meta = & attr. node . value ;
342
- let metas = match meta. node {
343
- ast:: MetaList ( _, ref metas) => metas,
344
- _ => {
345
- out. push ( Err ( meta. span ) ) ;
346
- continue ;
347
- }
348
- } ;
340
+ let level = match Level :: from_str ( & attr. name ( ) ) {
341
+ None => return out,
342
+ Some ( lvl) => lvl,
343
+ } ;
349
344
350
- for meta in metas {
351
- out. push ( match meta. node {
352
- ast:: MetaWord ( ref lint_name) => Ok ( ( lint_name. clone ( ) , level, meta. span ) ) ,
353
- _ => Err ( meta. span ) ,
354
- } ) ;
345
+ attr:: mark_used ( attr) ;
346
+
347
+ let meta = & attr. node . value ;
348
+ let metas = match meta. node {
349
+ ast:: MetaList ( _, ref metas) => metas,
350
+ _ => {
351
+ out. push ( Err ( meta. span ) ) ;
352
+ return out;
355
353
}
354
+ } ;
355
+
356
+ for meta in metas {
357
+ out. push ( match meta. node {
358
+ ast:: MetaWord ( ref lint_name) => Ok ( ( lint_name. clone ( ) , level, meta. span ) ) ,
359
+ _ => Err ( meta. span ) ,
360
+ } ) ;
356
361
}
362
+
357
363
out
358
364
}
359
365
@@ -555,9 +561,9 @@ pub trait LintContext: Sized {
555
561
( * lint_id, level, span) )
556
562
. collect ( ) ,
557
563
None => {
558
- self . span_lint ( builtin :: UNKNOWN_LINTS , span ,
559
- & format ! ( "unknown `{}` attribute: `{}`" ,
560
- level . as_str ( ) , lint_name ) ) ;
564
+ // The lint or lint group doesn't exist.
565
+ // This is an error, but it was handled
566
+ // by check_lint_name_attribute.
561
567
continue ;
562
568
}
563
569
}
@@ -869,6 +875,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
869
875
}
870
876
871
877
fn visit_attribute ( & mut self , attr : & ast:: Attribute ) {
878
+ check_lint_name_attribute ( self , attr) ;
872
879
run_lints ! ( self , check_attribute, late_passes, attr) ;
873
880
}
874
881
}
@@ -1082,6 +1089,113 @@ impl LateLintPass for GatherNodeLevels {
1082
1089
}
1083
1090
}
1084
1091
1092
+ enum CheckLintNameResult < ' a > {
1093
+ Ok ,
1094
+ // Lint doesn't exist
1095
+ NoLint ,
1096
+ // The lint is either renamed or removed and a warning was
1097
+ // generated in the DiagnosticBuilder
1098
+ Mentioned ( DiagnosticBuilder < ' a > )
1099
+ }
1100
+
1101
+ /// Checks the name of a lint for its existence, and whether it was
1102
+ /// renamed or removed. Generates a DiagnosticBuilder containing a
1103
+ /// warning for renamed and removed lints. This is over both lint
1104
+ /// names from attributes and those passed on the command line. Since
1105
+ /// it emits non-fatal warnings and there are *two* lint passes that
1106
+ /// inspect attributes, this is only run from the late pass to avoid
1107
+ /// printing duplicate warnings.
1108
+ fn check_lint_name < ' a > ( sess : & ' a Session ,
1109
+ lint_cx : & LintStore ,
1110
+ lint_name : & str ,
1111
+ span : Option < Span > ) -> CheckLintNameResult < ' a > {
1112
+ match lint_cx. by_name . get ( lint_name) {
1113
+ Some ( & Renamed ( ref new_name, _) ) => {
1114
+ let warning = format ! ( "lint {} has been renamed to {}" ,
1115
+ lint_name, new_name) ;
1116
+ let db = match span {
1117
+ Some ( span) => sess. struct_span_warn ( span, & warning[ ..] ) ,
1118
+ None => sess. struct_warn ( & warning[ ..] ) ,
1119
+ } ;
1120
+ CheckLintNameResult :: Mentioned ( db)
1121
+ } ,
1122
+ Some ( & Removed ( ref reason) ) => {
1123
+ let warning = format ! ( "lint {} has been removed: {}" , lint_name, reason) ;
1124
+ let db = match span {
1125
+ Some ( span) => sess. struct_span_warn ( span, & warning[ ..] ) ,
1126
+ None => sess. struct_warn ( & warning[ ..] )
1127
+ } ;
1128
+ CheckLintNameResult :: Mentioned ( db)
1129
+ } ,
1130
+ None => {
1131
+ match lint_cx. lint_groups . get ( lint_name) {
1132
+ None => {
1133
+ CheckLintNameResult :: NoLint
1134
+ }
1135
+ Some ( _) => {
1136
+ /* lint group exists */
1137
+ CheckLintNameResult :: Ok
1138
+ }
1139
+ }
1140
+ }
1141
+ Some ( _) => {
1142
+ /* lint exists */
1143
+ CheckLintNameResult :: Ok
1144
+ }
1145
+ }
1146
+ }
1147
+
1148
+ // Checks the validity of lint names derived from attributes
1149
+ fn check_lint_name_attribute ( cx : & LateContext , attr : & ast:: Attribute ) {
1150
+ for result in gather_attr ( attr) {
1151
+ match result {
1152
+ Err ( _) => {
1153
+ // Malformed lint attr. Reported by with_lint_attrs
1154
+ continue ;
1155
+ }
1156
+ Ok ( ( lint_name, _, span) ) => {
1157
+ match check_lint_name ( & cx. tcx . sess , & cx. lints , & lint_name[ ..] , Some ( span) ) {
1158
+ CheckLintNameResult :: Ok => ( ) ,
1159
+ CheckLintNameResult :: Mentioned ( mut db) => {
1160
+ db. emit ( ) ;
1161
+ }
1162
+ CheckLintNameResult :: NoLint => {
1163
+ cx. span_lint ( builtin:: UNKNOWN_LINTS , span,
1164
+ & format ! ( "unknown lint: `{}`" ,
1165
+ lint_name) ) ;
1166
+ }
1167
+ }
1168
+ }
1169
+ }
1170
+ }
1171
+ }
1172
+
1173
+ // Checks the validity of lint names derived from the command line
1174
+ fn check_lint_name_cmdline ( sess : & Session , lint_cx : & LintStore ,
1175
+ lint_name : & str , level : Level ) {
1176
+ let db = match check_lint_name ( sess, lint_cx, lint_name, None ) {
1177
+ CheckLintNameResult :: Ok => None ,
1178
+ CheckLintNameResult :: Mentioned ( db) => Some ( db) ,
1179
+ CheckLintNameResult :: NoLint => {
1180
+ Some ( sess. struct_err ( & format ! ( "unknown lint: `{}`" , lint_name) ) )
1181
+ }
1182
+ } ;
1183
+
1184
+ if let Some ( mut db) = db {
1185
+ let msg = format ! ( "requested on the command line with `{} {}`" ,
1186
+ match level {
1187
+ Level :: Allow => "-A" ,
1188
+ Level :: Warn => "-W" ,
1189
+ Level :: Deny => "-D" ,
1190
+ Level :: Forbid => "-F" ,
1191
+ } ,
1192
+ lint_name) ;
1193
+ db. note ( & msg) ;
1194
+ db. emit ( ) ;
1195
+ }
1196
+ }
1197
+
1198
+
1085
1199
/// Perform lint checking on a crate.
1086
1200
///
1087
1201
/// Consumes the `lint_store` field of the `Session`.
0 commit comments