@@ -247,21 +247,10 @@ impl LintStore {
247247 {
248248 match self . by_name . get ( lint_name) {
249249 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) ) => {
257251 Ok ( lint_id)
258252 } ,
259253 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- }
265254 Err ( FindLintError :: Removed )
266255 } ,
267256 None => Err ( FindLintError :: NotFound )
@@ -270,8 +259,12 @@ impl LintStore {
270259
271260 pub fn process_command_line ( & mut self , sess : & Session ) {
272261 for & ( ref lint_name, level) in & sess. opts . lint_opts {
262+ check_lint_name_cmdline ( sess, self ,
263+ & lint_name[ ..] , level) ;
264+
273265 match self . find_lint ( & lint_name[ ..] , sess, None ) {
274266 Ok ( lint_id) => self . set_level ( lint_id, ( level, CommandLine ) ) ,
267+ Err ( FindLintError :: Removed ) => { }
275268 Err ( _) => {
276269 match self . lint_groups . iter ( ) . map ( |( & x, pair) | ( x, pair. 0 . clone ( ) ) )
277270 . collect :: < FnvHashMap < & ' static str ,
@@ -283,8 +276,11 @@ impl LintStore {
283276 self . set_level ( * lint_id, ( level, CommandLine ) ) )
284277 . collect :: < Vec < ( ) > > ( ) ;
285278 }
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+ }
288284 }
289285 }
290286 }
@@ -359,29 +355,39 @@ pub fn gather_attrs(attrs: &[ast::Attribute])
359355 -> Vec < Result < ( InternedString , Level , Span ) , Span > > {
360356 let mut out = vec ! ( ) ;
361357 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+ }
366363
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 ! ( ) ;
368367
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+ } ;
377372
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;
383381 }
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+ } ) ;
384389 }
390+
385391 out
386392}
387393
@@ -587,9 +593,9 @@ pub trait LintContext: Sized {
587593 ( * lint_id, level, span) )
588594 . collect ( ) ,
589595 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.
593599 continue ;
594600 }
595601 }
@@ -901,6 +907,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
901907 }
902908
903909 fn visit_attribute ( & mut self , attr : & ast:: Attribute ) {
910+ check_lint_name_attribute ( self , attr) ;
904911 run_lints ! ( self , check_attribute, late_passes, attr) ;
905912 }
906913}
@@ -1114,6 +1121,113 @@ impl LateLintPass for GatherNodeLevels {
11141121 }
11151122}
11161123
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+
11171231/// Perform lint checking on a crate.
11181232///
11191233/// Consumes the `lint_store` field of the `Session`.
0 commit comments