@@ -218,21 +218,10 @@ impl LintStore {
218
218
{
219
219
match self . by_name . get ( lint_name) {
220
220
Some ( & Id ( lint_id) ) => Ok ( lint_id) ,
221
- Some ( & Renamed ( ref new_name, lint_id) ) => {
222
- let warning = format ! ( "lint {} has been renamed to {}" ,
223
- lint_name, new_name) ;
224
- match span {
225
- Some ( span) => sess. span_warn ( span, & warning[ ..] ) ,
226
- None => sess. warn ( & warning[ ..] ) ,
227
- } ;
221
+ Some ( & Renamed ( _, lint_id) ) => {
228
222
Ok ( lint_id)
229
223
} ,
230
224
Some ( & Removed ( ref reason) ) => {
231
- let warning = format ! ( "lint {} has been removed: {}" , lint_name, reason) ;
232
- match span {
233
- Some ( span) => sess. span_warn ( span, & warning[ ..] ) ,
234
- None => sess. warn ( & warning[ ..] )
235
- }
236
225
Err ( FindLintError :: Removed )
237
226
} ,
238
227
None => Err ( FindLintError :: NotFound )
@@ -241,8 +230,12 @@ impl LintStore {
241
230
242
231
pub fn process_command_line ( & mut self , sess : & Session ) {
243
232
for & ( ref lint_name, level) in & sess. opts . lint_opts {
233
+ check_lint_name_cmdline ( sess, self ,
234
+ & lint_name[ ..] , level) ;
235
+
244
236
match self . find_lint ( & lint_name[ ..] , sess, None ) {
245
237
Ok ( lint_id) => self . set_level ( lint_id, ( level, CommandLine ) ) ,
238
+ Err ( FindLintError :: Removed ) => { }
246
239
Err ( _) => {
247
240
match self . lint_groups . iter ( ) . map ( |( & x, pair) | ( x, pair. 0 . clone ( ) ) )
248
241
. collect :: < FnvHashMap < & ' static str ,
@@ -254,8 +247,11 @@ impl LintStore {
254
247
self . set_level ( * lint_id, ( level, CommandLine ) ) )
255
248
. collect :: < Vec < ( ) > > ( ) ;
256
249
}
257
- None => sess. err ( & format ! ( "unknown {} flag: {}" ,
258
- level. as_str( ) , lint_name) ) ,
250
+ None => {
251
+ // The lint or lint group doesn't exist.
252
+ // This is an error, but it was handled
253
+ // by check_lint_name_cmdline.
254
+ }
259
255
}
260
256
}
261
257
}
@@ -330,29 +326,39 @@ pub fn gather_attrs(attrs: &[ast::Attribute])
330
326
-> Vec < Result < ( InternedString , Level , Span ) , Span > > {
331
327
let mut out = vec ! ( ) ;
332
328
for attr in attrs {
333
- let level = match Level :: from_str ( & attr. name ( ) ) {
334
- None => continue ,
335
- Some ( lvl) => lvl,
336
- } ;
329
+ let r = gather_attr ( attr) ;
330
+ out. extend ( r. into_iter ( ) ) ;
331
+ }
332
+ out
333
+ }
337
334
338
- attr:: mark_used ( attr) ;
335
+ pub fn gather_attr ( attr : & ast:: Attribute )
336
+ -> Vec < Result < ( InternedString , Level , Span ) , Span > > {
337
+ let mut out = vec ! ( ) ;
339
338
340
- let meta = & attr. node . value ;
341
- let metas = match meta. node {
342
- ast:: MetaList ( _, ref metas) => metas,
343
- _ => {
344
- out. push ( Err ( meta. span ) ) ;
345
- continue ;
346
- }
347
- } ;
339
+ let level = match Level :: from_str ( & attr. name ( ) ) {
340
+ None => return out,
341
+ Some ( lvl) => lvl,
342
+ } ;
348
343
349
- for meta in metas {
350
- out. push ( match meta. node {
351
- ast:: MetaWord ( ref lint_name) => Ok ( ( lint_name. clone ( ) , level, meta. span ) ) ,
352
- _ => Err ( meta. span ) ,
353
- } ) ;
344
+ attr:: mark_used ( attr) ;
345
+
346
+ let meta = & attr. node . value ;
347
+ let metas = match meta. node {
348
+ ast:: MetaList ( _, ref metas) => metas,
349
+ _ => {
350
+ out. push ( Err ( meta. span ) ) ;
351
+ return out;
354
352
}
353
+ } ;
354
+
355
+ for meta in metas {
356
+ out. push ( match meta. node {
357
+ ast:: MetaWord ( ref lint_name) => Ok ( ( lint_name. clone ( ) , level, meta. span ) ) ,
358
+ _ => Err ( meta. span ) ,
359
+ } ) ;
355
360
}
361
+
356
362
out
357
363
}
358
364
@@ -510,9 +516,9 @@ pub trait LintContext: Sized {
510
516
( * lint_id, level, span) )
511
517
. collect ( ) ,
512
518
None => {
513
- self . span_lint ( builtin :: UNKNOWN_LINTS , span ,
514
- & format ! ( "unknown `{}` attribute: `{}`" ,
515
- level . as_str ( ) , lint_name ) ) ;
519
+ // The lint or lint group doesn't exist.
520
+ // This is an error, but it was handled
521
+ // by check_lint_name_attribute.
516
522
continue ;
517
523
}
518
524
}
@@ -824,6 +830,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
824
830
}
825
831
826
832
fn visit_attribute ( & mut self , attr : & ast:: Attribute ) {
833
+ check_lint_name_attribute ( self , attr) ;
827
834
run_lints ! ( self , check_attribute, late_passes, attr) ;
828
835
}
829
836
}
@@ -1037,6 +1044,110 @@ impl LateLintPass for GatherNodeLevels {
1037
1044
}
1038
1045
}
1039
1046
1047
+ enum CheckLintNameResult {
1048
+ Ok ,
1049
+ // Lint doesn't exist
1050
+ NoLint ,
1051
+ // The lint is either renamed or removed and a warning was generated
1052
+ Mentioned
1053
+ }
1054
+
1055
+ /// Checks the name of a lint for its existence, and whether it was
1056
+ /// renamed or removed. Generates a DiagnosticBuilder containing a
1057
+ /// warning for renamed and removed lints. This is over both lint
1058
+ /// names from attributes and those passed on the command line. Since
1059
+ /// it emits non-fatal warnings and there are *two* lint passes that
1060
+ /// inspect attributes, this is only run from the late pass to avoid
1061
+ /// printing duplicate warnings.
1062
+ fn check_lint_name ( sess : & Session ,
1063
+ lint_cx : & LintStore ,
1064
+ lint_name : & str ,
1065
+ span : Option < Span > ) -> CheckLintNameResult {
1066
+ match lint_cx. by_name . get ( lint_name) {
1067
+ Some ( & Renamed ( ref new_name, _) ) => {
1068
+ let warning = format ! ( "lint {} has been renamed to {}" ,
1069
+ lint_name, new_name) ;
1070
+ match span {
1071
+ Some ( span) => sess. span_warn ( span, & warning[ ..] ) ,
1072
+ None => sess. warn ( & warning[ ..] ) ,
1073
+ } ;
1074
+ CheckLintNameResult :: Mentioned
1075
+ } ,
1076
+ Some ( & Removed ( ref reason) ) => {
1077
+ let warning = format ! ( "lint {} has been removed: {}" , lint_name, reason) ;
1078
+ match span {
1079
+ Some ( span) => sess. span_warn ( span, & warning[ ..] ) ,
1080
+ None => sess. warn ( & warning[ ..] )
1081
+ } ;
1082
+ CheckLintNameResult :: Mentioned
1083
+ } ,
1084
+ None => {
1085
+ match lint_cx. lint_groups . get ( lint_name) {
1086
+ None => {
1087
+ CheckLintNameResult :: NoLint
1088
+ }
1089
+ Some ( _) => {
1090
+ /* lint group exists */
1091
+ CheckLintNameResult :: Ok
1092
+ }
1093
+ }
1094
+ }
1095
+ Some ( _) => {
1096
+ /* lint exists */
1097
+ CheckLintNameResult :: Ok
1098
+ }
1099
+ }
1100
+ }
1101
+
1102
+ // Checks the validity of lint names derived from attributes
1103
+ fn check_lint_name_attribute ( cx : & LateContext , attr : & ast:: Attribute ) {
1104
+ for result in gather_attr ( attr) {
1105
+ match result {
1106
+ Err ( _) => {
1107
+ // Malformed lint attr. Reported by with_lint_attrs
1108
+ continue ;
1109
+ }
1110
+ Ok ( ( lint_name, _, span) ) => {
1111
+ match check_lint_name ( & cx. tcx . sess , & cx. lints , & lint_name[ ..] , Some ( span) ) {
1112
+ CheckLintNameResult :: Ok => ( ) ,
1113
+ CheckLintNameResult :: Mentioned => ( ) ,
1114
+ CheckLintNameResult :: NoLint => {
1115
+ cx. span_lint ( builtin:: UNKNOWN_LINTS , span,
1116
+ & format ! ( "unknown lint: `{}`" ,
1117
+ lint_name) ) ;
1118
+ }
1119
+ }
1120
+ }
1121
+ }
1122
+ }
1123
+ }
1124
+
1125
+ // Checks the validity of lint names derived from the command line
1126
+ fn check_lint_name_cmdline ( sess : & Session , lint_cx : & LintStore ,
1127
+ lint_name : & str , level : Level ) {
1128
+ let explain = match check_lint_name ( sess, lint_cx, lint_name, None ) {
1129
+ CheckLintNameResult :: Ok => false ,
1130
+ CheckLintNameResult :: Mentioned => true ,
1131
+ CheckLintNameResult :: NoLint => {
1132
+ sess. err ( & format ! ( "unknown lint: `{}`" , lint_name) ) ;
1133
+ true
1134
+ }
1135
+ } ;
1136
+
1137
+ if explain {
1138
+ let msg = format ! ( "requested on the command line with `{} {}`" ,
1139
+ match level {
1140
+ Level :: Allow => "-A" ,
1141
+ Level :: Warn => "-W" ,
1142
+ Level :: Deny => "-D" ,
1143
+ Level :: Forbid => "-F" ,
1144
+ } ,
1145
+ lint_name) ;
1146
+ sess. note ( & msg) ;
1147
+ }
1148
+ }
1149
+
1150
+
1040
1151
/// Perform lint checking on a crate.
1041
1152
///
1042
1153
/// Consumes the `lint_store` field of the `Session`.
0 commit comments