@@ -218,21 +218,10 @@ impl LintStore {
218218 {
219219 match self . by_name . get ( lint_name) {
220220 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) ) => {
228222 Ok ( lint_id)
229223 } ,
230224 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- }
236225 Err ( FindLintError :: Removed )
237226 } ,
238227 None => Err ( FindLintError :: NotFound )
@@ -241,8 +230,12 @@ impl LintStore {
241230
242231 pub fn process_command_line ( & mut self , sess : & Session ) {
243232 for & ( ref lint_name, level) in & sess. opts . lint_opts {
233+ check_lint_name_cmdline ( sess, self ,
234+ & lint_name[ ..] , level) ;
235+
244236 match self . find_lint ( & lint_name[ ..] , sess, None ) {
245237 Ok ( lint_id) => self . set_level ( lint_id, ( level, CommandLine ) ) ,
238+ Err ( FindLintError :: Removed ) => { }
246239 Err ( _) => {
247240 match self . lint_groups . iter ( ) . map ( |( & x, pair) | ( x, pair. 0 . clone ( ) ) )
248241 . collect :: < FnvHashMap < & ' static str ,
@@ -254,8 +247,11 @@ impl LintStore {
254247 self . set_level ( * lint_id, ( level, CommandLine ) ) )
255248 . collect :: < Vec < ( ) > > ( ) ;
256249 }
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+ }
259255 }
260256 }
261257 }
@@ -330,29 +326,39 @@ pub fn gather_attrs(attrs: &[ast::Attribute])
330326 -> Vec < Result < ( InternedString , Level , Span ) , Span > > {
331327 let mut out = vec ! ( ) ;
332328 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+ }
337334
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 ! ( ) ;
339338
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+ } ;
348343
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;
354352 }
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+ } ) ;
355360 }
361+
356362 out
357363}
358364
@@ -510,9 +516,9 @@ pub trait LintContext: Sized {
510516 ( * lint_id, level, span) )
511517 . collect ( ) ,
512518 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.
516522 continue ;
517523 }
518524 }
@@ -824,6 +830,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
824830 }
825831
826832 fn visit_attribute ( & mut self , attr : & ast:: Attribute ) {
833+ check_lint_name_attribute ( self , attr) ;
827834 run_lints ! ( self , check_attribute, late_passes, attr) ;
828835 }
829836}
@@ -1037,6 +1044,110 @@ impl LateLintPass for GatherNodeLevels {
10371044 }
10381045}
10391046
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+
10401151/// Perform lint checking on a crate.
10411152///
10421153/// Consumes the `lint_store` field of the `Session`.
0 commit comments