@@ -7,7 +7,8 @@ use lint::{EarlyContext, LateContext, LintContext, LintArray};
77use lint:: { EarlyLintPass , LintPass , LateLintPass } ;
88use syntax:: ast;
99use syntax:: attr;
10- use syntax_pos:: Span ;
10+ use syntax:: errors:: Applicability ;
11+ use syntax_pos:: { BytePos , symbol:: Ident , Span } ;
1112
1213#[ derive( PartialEq ) ]
1314pub enum MethodLateContext {
@@ -179,7 +180,8 @@ impl NonSnakeCase {
179180 words. join ( "_" )
180181 }
181182
182- fn check_snake_case ( & self , cx : & LateContext , sort : & str , name : & str , span : Option < Span > ) {
183+ /// Checks if a given identifier is snake case, and reports a diagnostic if not.
184+ fn check_snake_case ( & self , cx : & LateContext , sort : & str , ident : & Ident ) {
183185 fn is_snake_case ( ident : & str ) -> bool {
184186 if ident. is_empty ( ) {
185187 return true ;
@@ -201,20 +203,28 @@ impl NonSnakeCase {
201203 } )
202204 }
203205
206+ let name = & ident. name . as_str ( ) ;
207+
204208 if !is_snake_case ( name) {
205209 let sc = NonSnakeCase :: to_snake_case ( name) ;
206- let msg = if sc != name {
207- format ! ( "{} `{}` should have a snake case name such as `{}`" ,
208- sort,
209- name,
210- sc)
210+
211+ let msg = format ! ( "{} `{}` should have a snake case name" , sort, name) ;
212+ let mut err = cx. struct_span_lint ( NON_SNAKE_CASE , ident. span , & msg) ;
213+
214+ // We have a valid span in almost all cases, but we don't have one when linting a crate
215+ // name provided via the command line.
216+ if !ident. span . is_dummy ( ) {
217+ err. span_suggestion_with_applicability (
218+ ident. span ,
219+ "convert the identifier to snake case" ,
220+ sc,
221+ Applicability :: MaybeIncorrect ,
222+ ) ;
211223 } else {
212- format ! ( "{} `{}` should have a snake case name" , sort, name)
213- } ;
214- match span {
215- Some ( span) => cx. span_lint ( NON_SNAKE_CASE , span, & msg) ,
216- None => cx. lint ( NON_SNAKE_CASE , & msg) ,
224+ err. help ( & format ! ( "convert the identifier to snake case: `{}`" , sc) ) ;
217225 }
226+
227+ err. emit ( ) ;
218228 }
219229 }
220230}
@@ -227,87 +237,111 @@ impl LintPass for NonSnakeCase {
227237
228238impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for NonSnakeCase {
229239 fn check_crate ( & mut self , cx : & LateContext , cr : & hir:: Crate ) {
230- let attr_crate_name = attr:: find_by_name ( & cr. attrs , "crate_name" )
231- . and_then ( |at| at. value_str ( ) . map ( |s| ( at, s) ) ) ;
232- if let Some ( ref name) = cx. tcx . sess . opts . crate_name {
233- self . check_snake_case ( cx, "crate" , name, None ) ;
234- } else if let Some ( ( attr, name) ) = attr_crate_name {
235- self . check_snake_case ( cx, "crate" , & name. as_str ( ) , Some ( attr. span ) ) ;
240+ let crate_ident = if let Some ( name) = & cx. tcx . sess . opts . crate_name {
241+ Some ( Ident :: from_str ( name) )
242+ } else {
243+ attr:: find_by_name ( & cr. attrs , "crate_name" )
244+ . and_then ( |attr| attr. meta ( ) )
245+ . and_then ( |meta| {
246+ meta. name_value_literal ( ) . and_then ( |lit| {
247+ if let ast:: LitKind :: Str ( name, ..) = lit. node {
248+ // Discard the double quotes surrounding the literal.
249+ let sp = cx. sess ( ) . source_map ( ) . span_to_snippet ( lit. span )
250+ . ok ( )
251+ . and_then ( |snippet| {
252+ let left = snippet. find ( '"' ) ?;
253+ let right = snippet. rfind ( '"' ) . map ( |pos| snippet. len ( ) - pos) ?;
254+
255+ Some (
256+ lit. span
257+ . with_lo ( lit. span . lo ( ) + BytePos ( left as u32 + 1 ) )
258+ . with_hi ( lit. span . hi ( ) - BytePos ( right as u32 ) ) ,
259+ )
260+ } )
261+ . unwrap_or_else ( || lit. span ) ;
262+
263+ Some ( Ident :: new ( name, sp) )
264+ } else {
265+ None
266+ }
267+ } )
268+ } )
269+ } ;
270+
271+ if let Some ( ident) = & crate_ident {
272+ self . check_snake_case ( cx, "crate" , ident) ;
236273 }
237274 }
238275
239276 fn check_generic_param ( & mut self , cx : & LateContext , param : & hir:: GenericParam ) {
240- match param. kind {
241- GenericParamKind :: Lifetime { .. } => {
242- let name = param. name . ident ( ) . as_str ( ) ;
243- self . check_snake_case ( cx, "lifetime" , & name, Some ( param. span ) ) ;
244- }
245- GenericParamKind :: Type { .. } => { }
277+ if let GenericParamKind :: Lifetime { .. } = param. kind {
278+ self . check_snake_case ( cx, "lifetime" , & param. name . ident ( ) ) ;
246279 }
247280 }
248281
249- fn check_fn ( & mut self ,
250- cx : & LateContext ,
251- fk : FnKind ,
252- _: & hir:: FnDecl ,
253- _: & hir:: Body ,
254- span : Span ,
255- id : ast:: NodeId ) {
256- match fk {
257- FnKind :: Method ( name, ..) => {
282+ fn check_fn (
283+ & mut self ,
284+ cx : & LateContext ,
285+ fk : FnKind ,
286+ _: & hir:: FnDecl ,
287+ _: & hir:: Body ,
288+ _: Span ,
289+ id : ast:: NodeId ,
290+ ) {
291+ match & fk {
292+ FnKind :: Method ( ident, ..) => {
258293 match method_context ( cx, id) {
259294 MethodLateContext :: PlainImpl => {
260- self . check_snake_case ( cx, "method" , & name . as_str ( ) , Some ( span ) )
295+ self . check_snake_case ( cx, "method" , ident ) ;
261296 }
262297 MethodLateContext :: TraitAutoImpl => {
263- self . check_snake_case ( cx, "trait method" , & name . as_str ( ) , Some ( span ) )
298+ self . check_snake_case ( cx, "trait method" , ident ) ;
264299 }
265300 _ => ( ) ,
266301 }
267302 }
268- FnKind :: ItemFn ( name , _, header, _, attrs) => {
303+ FnKind :: ItemFn ( ident , _, header, _, attrs) => {
269304 // Skip foreign-ABI #[no_mangle] functions (Issue #31924)
270- if header. abi != Abi :: Rust && attr:: find_by_name ( attrs, "no_mangle" ) . is_some ( ) {
305+ if header. abi != Abi :: Rust && attr:: contains_name ( attrs, "no_mangle" ) {
271306 return ;
272307 }
273- self . check_snake_case ( cx, "function" , & name . as_str ( ) , Some ( span ) )
308+ self . check_snake_case ( cx, "function" , ident ) ;
274309 }
275310 FnKind :: Closure ( _) => ( ) ,
276311 }
277312 }
278313
279314 fn check_item ( & mut self , cx : & LateContext , it : & hir:: Item ) {
280315 if let hir:: ItemKind :: Mod ( _) = it. node {
281- self . check_snake_case ( cx, "module" , & it. ident . as_str ( ) , Some ( it . span ) ) ;
316+ self . check_snake_case ( cx, "module" , & it. ident ) ;
282317 }
283318 }
284319
285320 fn check_trait_item ( & mut self , cx : & LateContext , item : & hir:: TraitItem ) {
286- if let hir:: TraitItemKind :: Method ( _, hir:: TraitMethod :: Required ( ref pnames) ) = item. node {
287- self . check_snake_case ( cx,
288- "trait method" ,
289- & item. ident . as_str ( ) ,
290- Some ( item. span ) ) ;
321+ if let hir:: TraitItemKind :: Method ( _, hir:: TraitMethod :: Required ( pnames) ) = & item. node {
322+ self . check_snake_case ( cx, "trait method" , & item. ident ) ;
291323 for param_name in pnames {
292- self . check_snake_case ( cx, "variable" , & param_name. as_str ( ) , Some ( param_name . span ) ) ;
324+ self . check_snake_case ( cx, "variable" , param_name) ;
293325 }
294326 }
295327 }
296328
297329 fn check_pat ( & mut self , cx : & LateContext , p : & hir:: Pat ) {
298- if let & PatKind :: Binding ( _, _, ref ident, _) = & p. node {
299- self . check_snake_case ( cx, "variable" , & ident. as_str ( ) , Some ( p . span ) ) ;
330+ if let & PatKind :: Binding ( _, _, ident, _) = & p. node {
331+ self . check_snake_case ( cx, "variable" , & ident) ;
300332 }
301333 }
302334
303- fn check_struct_def ( & mut self ,
304- cx : & LateContext ,
305- s : & hir:: VariantData ,
306- _: ast:: Name ,
307- _: & hir:: Generics ,
308- _: ast:: NodeId ) {
335+ fn check_struct_def (
336+ & mut self ,
337+ cx : & LateContext ,
338+ s : & hir:: VariantData ,
339+ _: ast:: Name ,
340+ _: & hir:: Generics ,
341+ _: ast:: NodeId ,
342+ ) {
309343 for sf in s. fields ( ) {
310- self . check_snake_case ( cx, "structure field" , & sf. ident . as_str ( ) , Some ( sf . span ) ) ;
344+ self . check_snake_case ( cx, "structure field" , & sf. ident ) ;
311345 }
312346 }
313347}
0 commit comments