@@ -219,21 +219,10 @@ impl LintStore {
219219 {
220220 match self . by_name . get ( lint_name) {
221221 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) ) => {
229223 Ok ( lint_id)
230224 } ,
231225 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- }
237226 Err ( FindLintError :: Removed )
238227 } ,
239228 None => Err ( FindLintError :: NotFound )
@@ -242,8 +231,12 @@ impl LintStore {
242231
243232 pub fn process_command_line ( & mut self , sess : & Session ) {
244233 for & ( ref lint_name, level) in & sess. opts . lint_opts {
234+ check_lint_name_cmdline ( sess, self ,
235+ & lint_name[ ..] , level) ;
236+
245237 match self . find_lint ( & lint_name[ ..] , sess, None ) {
246238 Ok ( lint_id) => self . set_level ( lint_id, ( level, CommandLine ) ) ,
239+ Err ( FindLintError :: Removed ) => { }
247240 Err ( _) => {
248241 match self . lint_groups . iter ( ) . map ( |( & x, pair) | ( x, pair. 0 . clone ( ) ) )
249242 . collect :: < FnvHashMap < & ' static str ,
@@ -255,8 +248,11 @@ impl LintStore {
255248 self . set_level ( * lint_id, ( level, CommandLine ) ) )
256249 . collect :: < Vec < ( ) > > ( ) ;
257250 }
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+ }
260256 }
261257 }
262258 }
@@ -331,29 +327,39 @@ pub fn gather_attrs(attrs: &[ast::Attribute])
331327 -> Vec < Result < ( InternedString , Level , Span ) , Span > > {
332328 let mut out = vec ! ( ) ;
333329 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+ }
338335
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 ! ( ) ;
340339
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+ } ;
349344
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;
355353 }
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+ } ) ;
356361 }
362+
357363 out
358364}
359365
@@ -555,9 +561,9 @@ pub trait LintContext: Sized {
555561 ( * lint_id, level, span) )
556562 . collect ( ) ,
557563 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.
561567 continue ;
562568 }
563569 }
@@ -869,6 +875,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
869875 }
870876
871877 fn visit_attribute ( & mut self , attr : & ast:: Attribute ) {
878+ check_lint_name_attribute ( self , attr) ;
872879 run_lints ! ( self , check_attribute, late_passes, attr) ;
873880 }
874881}
@@ -1082,6 +1089,113 @@ impl LateLintPass for GatherNodeLevels {
10821089 }
10831090}
10841091
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+
10851199/// Perform lint checking on a crate.
10861200///
10871201/// Consumes the `lint_store` field of the `Session`.
0 commit comments