@@ -16,7 +16,7 @@ use hir_def::{
16
16
adt:: VariantData ,
17
17
expr:: { Pat , PatId } ,
18
18
src:: HasSource ,
19
- AdtId , ConstId , EnumId , FunctionId , Lookup , ModuleDefId , StaticId , StructId ,
19
+ AdtId , AttrDefId , ConstId , EnumId , FunctionId , Lookup , ModuleDefId , StaticId , StructId ,
20
20
} ;
21
21
use hir_expand:: {
22
22
diagnostics:: DiagnosticSink ,
@@ -32,6 +32,12 @@ use crate::{
32
32
diagnostics:: { decl_check:: case_conv:: * , CaseType , IncorrectCase } ,
33
33
} ;
34
34
35
+ mod allow {
36
+ pub const NON_SNAKE_CASE : & str = "non_snake_case" ;
37
+ pub const NON_UPPER_CASE_GLOBAL : & str = "non_upper_case_globals" ;
38
+ pub const NON_CAMEL_CASE_TYPES : & str = "non_camel_case_types" ;
39
+ }
40
+
35
41
pub ( super ) struct DeclValidator < ' a , ' b : ' a > {
36
42
owner : ModuleDefId ,
37
43
sink : & ' a mut DiagnosticSink < ' b > ,
@@ -72,11 +78,29 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
72
78
}
73
79
}
74
80
81
+ /// Checks whether not following the convention is allowed for this item.
82
+ ///
83
+ /// Currently this method doesn't check parent attributes.
84
+ fn allowed ( & self , db : & dyn HirDatabase , id : AttrDefId , allow_name : & str ) -> bool {
85
+ db. attrs ( id) . by_key ( "allow" ) . tt_values ( ) . any ( |tt| tt. to_string ( ) . contains ( allow_name) )
86
+ }
87
+
75
88
fn validate_func ( & mut self , db : & dyn HirDatabase , func : FunctionId ) {
76
89
let data = db. function_data ( func) ;
77
90
let body = db. body ( func. into ( ) ) ;
78
91
79
- // 1. Check the function name.
92
+ // 1. Recursively validate inner scope items, such as static variables and constants.
93
+ for ( item_id, _) in body. item_scope . values ( ) {
94
+ let mut validator = DeclValidator :: new ( item_id, self . sink ) ;
95
+ validator. validate_item ( db) ;
96
+ }
97
+
98
+ // 2. Check whether non-snake case identifiers are allowed for this function.
99
+ if self . allowed ( db, func. into ( ) , allow:: NON_SNAKE_CASE ) {
100
+ return ;
101
+ }
102
+
103
+ // 2. Check the function name.
80
104
let function_name = data. name . to_string ( ) ;
81
105
let fn_name_replacement = if let Some ( new_name) = to_lower_snake_case ( & function_name) {
82
106
let replacement = Replacement {
@@ -89,7 +113,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
89
113
None
90
114
} ;
91
115
92
- // 2 . Check the param names.
116
+ // 3 . Check the param names.
93
117
let mut fn_param_replacements = Vec :: new ( ) ;
94
118
95
119
for pat_id in body. params . iter ( ) . cloned ( ) {
@@ -111,7 +135,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
111
135
}
112
136
}
113
137
114
- // 3 . Check the patterns inside the function body.
138
+ // 4 . Check the patterns inside the function body.
115
139
let mut pats_replacements = Vec :: new ( ) ;
116
140
117
141
for ( pat_idx, pat) in body. pats . iter ( ) {
@@ -136,20 +160,14 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
136
160
}
137
161
}
138
162
139
- // 4 . If there is at least one element to spawn a warning on, go to the source map and generate a warning.
163
+ // 5 . If there is at least one element to spawn a warning on, go to the source map and generate a warning.
140
164
self . create_incorrect_case_diagnostic_for_func (
141
165
func,
142
166
db,
143
167
fn_name_replacement,
144
168
fn_param_replacements,
145
169
) ;
146
170
self . create_incorrect_case_diagnostic_for_variables ( func, db, pats_replacements) ;
147
-
148
- // 5. Recursively validate inner scope items, such as static variables and constants.
149
- for ( item_id, _) in body. item_scope . values ( ) {
150
- let mut validator = DeclValidator :: new ( item_id, self . sink ) ;
151
- validator. validate_item ( db) ;
152
- }
153
171
}
154
172
155
173
/// Given the information about incorrect names in the function declaration, looks up into the source code
@@ -312,6 +330,10 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
312
330
fn validate_struct ( & mut self , db : & dyn HirDatabase , struct_id : StructId ) {
313
331
let data = db. struct_data ( struct_id) ;
314
332
333
+ let non_camel_case_allowed =
334
+ self . allowed ( db, struct_id. into ( ) , allow:: NON_CAMEL_CASE_TYPES ) ;
335
+ let non_snake_case_allowed = self . allowed ( db, struct_id. into ( ) , allow:: NON_SNAKE_CASE ) ;
336
+
315
337
// 1. Check the structure name.
316
338
let struct_name = data. name . to_string ( ) ;
317
339
let struct_name_replacement = if let Some ( new_name) = to_camel_case ( & struct_name) {
@@ -320,24 +342,30 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
320
342
suggested_text : new_name,
321
343
expected_case : CaseType :: UpperCamelCase ,
322
344
} ;
323
- Some ( replacement)
345
+ if !non_camel_case_allowed {
346
+ Some ( replacement)
347
+ } else {
348
+ None
349
+ }
324
350
} else {
325
351
None
326
352
} ;
327
353
328
354
// 2. Check the field names.
329
355
let mut struct_fields_replacements = Vec :: new ( ) ;
330
356
331
- if let VariantData :: Record ( fields) = data. variant_data . as_ref ( ) {
332
- for ( _, field) in fields. iter ( ) {
333
- let field_name = field. name . to_string ( ) ;
334
- if let Some ( new_name) = to_lower_snake_case ( & field_name) {
335
- let replacement = Replacement {
336
- current_name : field. name . clone ( ) ,
337
- suggested_text : new_name,
338
- expected_case : CaseType :: LowerSnakeCase ,
339
- } ;
340
- struct_fields_replacements. push ( replacement) ;
357
+ if !non_snake_case_allowed {
358
+ if let VariantData :: Record ( fields) = data. variant_data . as_ref ( ) {
359
+ for ( _, field) in fields. iter ( ) {
360
+ let field_name = field. name . to_string ( ) ;
361
+ if let Some ( new_name) = to_lower_snake_case ( & field_name) {
362
+ let replacement = Replacement {
363
+ current_name : field. name . clone ( ) ,
364
+ suggested_text : new_name,
365
+ expected_case : CaseType :: LowerSnakeCase ,
366
+ } ;
367
+ struct_fields_replacements. push ( replacement) ;
368
+ }
341
369
}
342
370
}
343
371
}
@@ -442,7 +470,12 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
442
470
fn validate_enum ( & mut self , db : & dyn HirDatabase , enum_id : EnumId ) {
443
471
let data = db. enum_data ( enum_id) ;
444
472
445
- // 1. Check the enum name.
473
+ // 1. Check whether non-camel case names are allowed for this enum.
474
+ if self . allowed ( db, enum_id. into ( ) , allow:: NON_CAMEL_CASE_TYPES ) {
475
+ return ;
476
+ }
477
+
478
+ // 2. Check the enum name.
446
479
let enum_name = data. name . to_string ( ) ;
447
480
let enum_name_replacement = if let Some ( new_name) = to_camel_case ( & enum_name) {
448
481
let replacement = Replacement {
@@ -455,7 +488,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
455
488
None
456
489
} ;
457
490
458
- // 2 . Check the field names.
491
+ // 3 . Check the field names.
459
492
let mut enum_fields_replacements = Vec :: new ( ) ;
460
493
461
494
for ( _, variant) in data. variants . iter ( ) {
@@ -470,7 +503,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
470
503
}
471
504
}
472
505
473
- // 3 . If there is at least one element to spawn a warning on, go to the source map and generate a warning.
506
+ // 4 . If there is at least one element to spawn a warning on, go to the source map and generate a warning.
474
507
self . create_incorrect_case_diagnostic_for_enum (
475
508
enum_id,
476
509
db,
@@ -572,6 +605,10 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
572
605
fn validate_const ( & mut self , db : & dyn HirDatabase , const_id : ConstId ) {
573
606
let data = db. const_data ( const_id) ;
574
607
608
+ if self . allowed ( db, const_id. into ( ) , allow:: NON_UPPER_CASE_GLOBAL ) {
609
+ return ;
610
+ }
611
+
575
612
let name = match & data. name {
576
613
Some ( name) => name,
577
614
None => return ,
@@ -612,6 +649,10 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
612
649
fn validate_static ( & mut self , db : & dyn HirDatabase , static_id : StaticId ) {
613
650
let data = db. static_data ( static_id) ;
614
651
652
+ if self . allowed ( db, static_id. into ( ) , allow:: NON_UPPER_CASE_GLOBAL ) {
653
+ return ;
654
+ }
655
+
615
656
let name = match & data. name {
616
657
Some ( name) => name,
617
658
None => return ,
@@ -854,4 +895,29 @@ fn main() {
854
895
"# ,
855
896
) ;
856
897
}
898
+
899
+ #[ test]
900
+ fn allow_attributes ( ) {
901
+ check_diagnostics (
902
+ r#"
903
+ #[allow(non_snake_case)]
904
+ fn NonSnakeCaseName(SOME_VAR: u8) -> u8{
905
+ let OtherVar = SOME_VAR + 1;
906
+ OtherVar
907
+ }
908
+
909
+ #[allow(non_snake_case, non_camel_case_types)]
910
+ pub struct some_type {
911
+ SOME_FIELD: u8,
912
+ SomeField: u16,
913
+ }
914
+
915
+ #[allow(non_upper_case_globals)]
916
+ pub const some_const: u8 = 10;
917
+
918
+ #[allow(non_upper_case_globals)]
919
+ pub static SomeStatic: u8 = 10;
920
+ "# ,
921
+ ) ;
922
+ }
857
923
}
0 commit comments