1use hir::{CaseType, InFile, db::ExpandDatabase};
2use ide_db::{assists::Assist, defs::NameClass, rename::RenameDefinition};
3use syntax::AstNode;
4
5use crate::{
6 Diagnostic,
7 DiagnosticCode,
8 DiagnosticsContext,
9 unresolved_fix,
11};
12
13pub(crate) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Diagnostic {
17 let code = match d.expected_case {
18 CaseType::LowerSnakeCase => DiagnosticCode::RustcLint("non_snake_case"),
19 CaseType::UpperSnakeCase => DiagnosticCode::RustcLint("non_upper_case_globals"),
20 CaseType::UpperCamelCase => DiagnosticCode::RustcLint("non_camel_case_types"),
22 };
23 Diagnostic::new_with_syntax_node_ptr(
24 ctx,
25 code,
26 format!(
27 "{} `{}` should have {} name, e.g. `{}`",
28 d.ident_type, d.ident_text, d.expected_case, d.suggested_text
29 ),
30 InFile::new(d.file, d.ident.into()),
31 )
32 .stable()
33 .with_fixes(fixes(ctx, d))
34}
35
36fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Assist>> {
37 let root = ctx.sema.db.parse_or_expand(d.file);
38 let name_node = d.ident.to_node(&root);
39 let def = NameClass::classify(&ctx.sema, &name_node)?.defined()?;
40
41 let name_node = InFile::new(d.file, name_node.syntax());
42 let frange = name_node.original_file_range_rooted(ctx.sema.db);
43
44 let label = format!("Rename to {}", d.suggested_text);
45 let mut res = unresolved_fix("change_case", &label, frange.range);
46 if ctx.resolve.should_resolve(&res.id) {
47 let source_change = def.rename(&ctx.sema, &d.suggested_text, RenameDefinition::Yes);
48 res.source_change = Some(source_change.ok().unwrap_or_default());
49 }
50
51 Some(vec![res])
52}
53
54#[cfg(test)]
55mod change_case {
56 use crate::tests::{check_diagnostics, check_diagnostics_with_disabled, check_fix};
57
58 #[test]
59 fn test_rename_incorrect_case() {
60 check_fix(
61 r#"
62pub struct test_struct$0 { one: i32 }
63
64pub fn some_fn(val: test_struct) -> test_struct {
65 test_struct { one: val.one + 1 }
66}
67"#,
68 r#"
69pub struct TestStruct { one: i32 }
70
71pub fn some_fn(val: TestStruct) -> TestStruct {
72 TestStruct { one: val.one + 1 }
73}
74"#,
75 );
76
77 check_fix(
78 r#"
79pub fn some_fn(NonSnakeCase$0: u8) -> u8 {
80 NonSnakeCase
81}
82"#,
83 r#"
84pub fn some_fn(non_snake_case: u8) -> u8 {
85 non_snake_case
86}
87"#,
88 );
89
90 check_fix(
91 r#"
92pub fn SomeFn$0(val: u8) -> u8 {
93 if val != 0 { SomeFn(val - 1) } else { val }
94}
95"#,
96 r#"
97pub fn some_fn(val: u8) -> u8 {
98 if val != 0 { some_fn(val - 1) } else { val }
99}
100"#,
101 );
102
103 check_fix(
104 r#"
105fn some_fn() {
106 let whatAWeird_Formatting$0 = 10;
107 another_func(whatAWeird_Formatting);
108}
109"#,
110 r#"
111fn some_fn() {
112 let what_aweird_formatting = 10;
113 another_func(what_aweird_formatting);
114}
115"#,
116 );
117
118 check_fix(
119 r#"
120static S: i32 = M::A;
121
122mod $0M {
123 pub const A: i32 = 10;
124}
125
126mod other {
127 use crate::M::A;
128}
129"#,
130 r#"
131static S: i32 = m::A;
132
133mod m {
134 pub const A: i32 = 10;
135}
136
137mod other {
138 use crate::m::A;
139}
140"#,
141 );
142 }
143
144 #[test]
145 fn test_uppercase_const_no_diagnostics() {
146 check_diagnostics(
147 r#"
148fn foo() {
149 const ANOTHER_ITEM: &str = "some_item";
150}
151"#,
152 );
153 }
154
155 #[test]
156 fn test_rename_incorrect_case_struct_method() {
157 check_fix(
158 r#"
159pub struct TestStruct;
160
161impl TestStruct {
162 pub fn SomeFn$0() -> TestStruct {
163 TestStruct
164 }
165}
166"#,
167 r#"
168pub struct TestStruct;
169
170impl TestStruct {
171 pub fn some_fn() -> TestStruct {
172 TestStruct
173 }
174}
175"#,
176 );
177 }
178
179 #[test]
180 fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() {
181 check_diagnostics(
182 r#"
183fn FOO() {}
184// ^^^ 💡 warn: Function `FOO` should have snake_case name, e.g. `foo`
185"#,
186 );
187 check_fix(r#"fn FOO$0() {}"#, r#"fn foo() {}"#);
188 }
189
190 #[test]
191 fn incorrect_function_name() {
192 check_diagnostics(
193 r#"
194fn NonSnakeCaseName() {}
195// ^^^^^^^^^^^^^^^^ 💡 warn: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
196"#,
197 );
198 }
199
200 #[test]
201 fn incorrect_function_params() {
202 check_diagnostics(
203 r#"
204fn foo(SomeParam: u8) { _ = SomeParam; }
205 // ^^^^^^^^^ 💡 warn: Parameter `SomeParam` should have snake_case name, e.g. `some_param`
206
207fn foo2(ok_param: &str, CAPS_PARAM: u8) { _ = (ok_param, CAPS_PARAM); }
208 // ^^^^^^^^^^ 💡 warn: Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param`
209"#,
210 );
211 }
212
213 #[test]
214 fn incorrect_variable_names() {
215 check_diagnostics(
216 r#"
217#[allow(unused)]
218fn foo() {
219 let SOME_VALUE = 10;
220 // ^^^^^^^^^^ 💡 warn: Variable `SOME_VALUE` should have snake_case name, e.g. `some_value`
221 let AnotherValue = 20;
222 // ^^^^^^^^^^^^ 💡 warn: Variable `AnotherValue` should have snake_case name, e.g. `another_value`
223}
224"#,
225 );
226 }
227
228 #[test]
229 fn incorrect_struct_names() {
230 check_diagnostics(
231 r#"
232struct non_camel_case_name {}
233 // ^^^^^^^^^^^^^^^^^^^ 💡 warn: Structure `non_camel_case_name` should have UpperCamelCase name, e.g. `NonCamelCaseName`
234
235struct SCREAMING_CASE {}
236 // ^^^^^^^^^^^^^^ 💡 warn: Structure `SCREAMING_CASE` should have UpperCamelCase name, e.g. `ScreamingCase`
237"#,
238 );
239 }
240
241 #[test]
242 fn no_diagnostic_for_camel_cased_acronyms_in_struct_name() {
243 check_diagnostics(
244 r#"
245struct AABB {}
246"#,
247 );
248 }
249
250 #[test]
251 fn incorrect_struct_field() {
252 check_diagnostics(
253 r#"
254struct SomeStruct { SomeField: u8 }
255 // ^^^^^^^^^ 💡 warn: Field `SomeField` should have snake_case name, e.g. `some_field`
256"#,
257 );
258 }
259
260 #[test]
261 fn incorrect_enum_names() {
262 check_diagnostics(
263 r#"
264enum some_enum { Val(u8) }
265 // ^^^^^^^^^ 💡 warn: Enum `some_enum` should have UpperCamelCase name, e.g. `SomeEnum`
266
267enum SOME_ENUM {}
268 // ^^^^^^^^^ 💡 warn: Enum `SOME_ENUM` should have UpperCamelCase name, e.g. `SomeEnum`
269"#,
270 );
271 }
272
273 #[test]
274 fn no_diagnostic_for_camel_cased_acronyms_in_enum_name() {
275 check_diagnostics(
276 r#"
277enum AABB {}
278"#,
279 );
280 }
281
282 #[test]
283 fn incorrect_enum_variant_name() {
284 check_diagnostics(
285 r#"
286enum SomeEnum { SOME_VARIANT(u8) }
287 // ^^^^^^^^^^^^ 💡 warn: Variant `SOME_VARIANT` should have UpperCamelCase name, e.g. `SomeVariant`
288"#,
289 );
290 }
291
292 #[test]
293 fn incorrect_const_name() {
294 check_diagnostics(
295 r#"
296const some_weird_const: u8 = 10;
297 // ^^^^^^^^^^^^^^^^ 💡 warn: Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
298"#,
299 );
300 }
301
302 #[test]
303 fn incorrect_static_name() {
304 check_diagnostics(
305 r#"
306static some_weird_const: u8 = 10;
307 // ^^^^^^^^^^^^^^^^ 💡 warn: Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
308"#,
309 );
310 }
311
312 #[test]
313 fn fn_inside_impl_struct() {
314 check_diagnostics(
315 r#"
316struct someStruct;
317 // ^^^^^^^^^^ 💡 warn: Structure `someStruct` should have UpperCamelCase name, e.g. `SomeStruct`
318
319impl someStruct {
320 fn SomeFunc(&self) {
321 // ^^^^^^^^ 💡 warn: Function `SomeFunc` should have snake_case name, e.g. `some_func`
322 let WHY_VAR_IS_CAPS = 10;
323 // ^^^^^^^^^^^^^^^ 💡 warn: Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps`
324 _ = WHY_VAR_IS_CAPS;
325 }
326}
327"#,
328 );
329 }
330
331 #[test]
332 fn no_diagnostic_for_enum_variants() {
333 check_diagnostics(
334 r#"
335enum Option { Some, None }
336use Option::{Some, None};
337
338#[allow(unused)]
339fn main() {
340 match Option::None {
341 None => (),
342 Some => (),
343 }
344}
345"#,
346 );
347 }
348
349 #[test]
350 fn allow_attributes_crate_attr() {
351 check_diagnostics(
352 r#"
353#![allow(non_snake_case)]
354#![allow(non_camel_case_types)]
355
356struct S {
357 fooBar: bool,
358}
359
360enum E {
361 fooBar,
362}
363
364mod F {
365 fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {
366 _ = BAD_NAME_HI;
367 }
368}
369 "#,
370 );
371 }
372
373 #[test]
374 fn external_macro() {
375 check_diagnostics(
376 r#"
377//- /library.rs library crate:library
378#[macro_export]
379macro_rules! trigger_lint {
380 () => { let FOO: () };
381}
382//- /user.rs crate:user deps:library
383fn foo() {
384 library::trigger_lint!();
385}
386 "#,
387 );
388 }
389
390 #[test]
391 fn complex_ignore() {
392 check_diagnostics(
393 r#"
394trait T { fn a(); }
395struct U {}
396impl T for U {
397 fn a() {
398 #[allow(non_snake_case, non_upper_case_globals)]
399 trait __BitFlagsOk {
400 const HiImAlsoBad: u8 = 2;
401 fn Dirty(&self) -> bool { false }
402 }
403
404 trait __BitFlagsBad {
405 const HiImAlsoBad: u8 = 2;
406 // ^^^^^^^^^^^ 💡 warn: Constant `HiImAlsoBad` should have UPPER_SNAKE_CASE name, e.g. `HI_IM_ALSO_BAD`
407 fn Dirty(&self) -> bool { false }
408 // ^^^^^💡 warn: Function `Dirty` should have snake_case name, e.g. `dirty`
409 }
410 }
411}
412"#,
413 );
414 }
415
416 #[test]
417 fn infinite_loop_inner_items() {
418 check_diagnostics(
419 r#"
420fn qualify() {
421 mod foo {
422 use super::*;
423 }
424}
425 "#,
426 )
427 }
428
429 #[test] fn parenthesized_parameter() {
431 check_diagnostics(
432 r#"
433fn f((_O): u8) {}
434 // ^^ 💡 warn: Variable `_O` should have snake_case name, e.g. `_o`
435"#,
436 )
437 }
438
439 #[test]
440 fn ignores_no_mangle_items() {
441 cov_mark::check!(extern_func_no_mangle_ignored);
442 cov_mark::check!(no_mangle_static_incorrect_case_ignored);
443 check_diagnostics(
444 r#"
445#[no_mangle]
446extern "C" fn NonSnakeCaseName(some_var: u8) -> u8;
447#[no_mangle]
448static lower_case: () = ();
449 "#,
450 );
451 }
452
453 #[test]
454 fn ignores_unsafe_no_mangle_items() {
455 cov_mark::check!(extern_func_no_mangle_ignored);
456 cov_mark::check!(no_mangle_static_incorrect_case_ignored);
457 check_diagnostics(
458 r#"
459#[unsafe(no_mangle)]
460extern "C" fn NonSnakeCaseName(some_var: u8) -> u8;
461#[unsafe(no_mangle)]
462static lower_case: () = ();
463 "#,
464 );
465 }
466
467 #[test]
468 fn ignores_no_mangle_items_with_no_abi() {
469 cov_mark::check!(extern_func_no_mangle_ignored);
470 check_diagnostics(
471 r#"
472#[no_mangle]
473extern fn NonSnakeCaseName(some_var: u8) -> u8;
474 "#,
475 );
476 }
477
478 #[test]
479 fn no_mangle_items_with_rust_abi() {
480 check_diagnostics(
481 r#"
482#[no_mangle]
483extern "Rust" fn NonSnakeCaseName(some_var: u8) -> u8;
484 // ^^^^^^^^^^^^^^^^ 💡 warn: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
485 "#,
486 );
487 }
488
489 #[test]
490 fn no_mangle_items_non_extern() {
491 check_diagnostics(
492 r#"
493#[no_mangle]
494fn NonSnakeCaseName(some_var: u8) -> u8;
495// ^^^^^^^^^^^^^^^^ 💡 warn: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
496 "#,
497 );
498 }
499
500 #[test]
501 fn extern_fn_name() {
502 check_diagnostics(
503 r#"
504extern "C" fn NonSnakeCaseName(some_var: u8) -> u8;
505 // ^^^^^^^^^^^^^^^^ 💡 warn: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
506extern "Rust" fn NonSnakeCaseName(some_var: u8) -> u8;
507 // ^^^^^^^^^^^^^^^^ 💡 warn: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
508extern fn NonSnakeCaseName(some_var: u8) -> u8;
509 // ^^^^^^^^^^^^^^^^ 💡 warn: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
510 "#,
511 );
512 }
513
514 #[test]
515 fn ignores_extern_items() {
516 cov_mark::check!(extern_func_incorrect_case_ignored);
517 cov_mark::check!(extern_static_incorrect_case_ignored);
518 check_diagnostics(
519 r#"
520extern {
521 fn NonSnakeCaseName(SOME_VAR: u8) -> u8;
522 pub static SomeStatic: u8 = 10;
523}
524 "#,
525 );
526 }
527
528 #[test]
529 fn ignores_extern_items_from_macro() {
530 check_diagnostics(
531 r#"
532macro_rules! m {
533 () => {
534 fn NonSnakeCaseName(SOME_VAR: u8) -> u8;
535 pub static SomeStatic: u8 = 10;
536 }
537}
538
539extern {
540 m!();
541}
542 "#,
543 );
544 }
545
546 #[test]
547 fn incorrect_trait_and_assoc_item_names() {
548 check_diagnostics(
549 r#"
550trait BAD_TRAIT {
551 // ^^^^^^^^^ 💡 warn: Trait `BAD_TRAIT` should have UpperCamelCase name, e.g. `BadTrait`
552 const bad_const: u8;
553 // ^^^^^^^^^ 💡 warn: Constant `bad_const` should have UPPER_SNAKE_CASE name, e.g. `BAD_CONST`
554 type BAD_TYPE;
555 // ^^^^^^^^ 💡 warn: Type alias `BAD_TYPE` should have UpperCamelCase name, e.g. `BadType`
556 fn BAD_FUNCTION();
557 // ^^^^^^^^^^^^ 💡 warn: Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
558 fn BadFunction();
559 // ^^^^^^^^^^^ 💡 warn: Function `BadFunction` should have snake_case name, e.g. `bad_function`
560}
561 "#,
562 );
563 }
564
565 #[test]
566 fn no_diagnostics_for_trait_impl_assoc_items_except_pats_in_body() {
567 cov_mark::check!(trait_impl_assoc_const_incorrect_case_ignored);
568 cov_mark::check!(trait_impl_assoc_type_incorrect_case_ignored);
569 cov_mark::check_count!(trait_impl_assoc_func_name_incorrect_case_ignored, 2);
570 check_diagnostics_with_disabled(
571 r#"
572trait BAD_TRAIT {
573 // ^^^^^^^^^ 💡 warn: Trait `BAD_TRAIT` should have UpperCamelCase name, e.g. `BadTrait`
574 const bad_const: u8;
575 // ^^^^^^^^^ 💡 warn: Constant `bad_const` should have UPPER_SNAKE_CASE name, e.g. `BAD_CONST`
576 type BAD_TYPE;
577 // ^^^^^^^^ 💡 warn: Type alias `BAD_TYPE` should have UpperCamelCase name, e.g. `BadType`
578 fn BAD_FUNCTION(BAD_PARAM: u8);
579 // ^^^^^^^^^^^^ 💡 warn: Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
580 // ^^^^^^^^^ 💡 warn: Parameter `BAD_PARAM` should have snake_case name, e.g. `bad_param`
581 fn BadFunction();
582 // ^^^^^^^^^^^ 💡 warn: Function `BadFunction` should have snake_case name, e.g. `bad_function`
583}
584
585impl BAD_TRAIT for () {
586 const bad_const: u8 = 0;
587 type BAD_TYPE = ();
588 fn BAD_FUNCTION(BAD_PARAM: u8) {
589 // ^^^^^^^^^ 💡 warn: Parameter `BAD_PARAM` should have snake_case name, e.g. `bad_param`
590 let BAD_VAR = 0;
591 // ^^^^^^^ 💡 warn: Variable `BAD_VAR` should have snake_case name, e.g. `bad_var`
592 }
593 fn BadFunction() {}
594}
595 "#,
596 &["unused_variables"],
597 );
598 }
599
600 #[test]
601 fn allow_attributes() {
602 check_diagnostics(
603 r#"
604#[allow(non_snake_case)]
605fn NonSnakeCaseName(SOME_VAR: u8) -> u8{
606 // cov_flags generated output from elsewhere in this file
607 extern "C" {
608 #[no_mangle]
609 static lower_case: u8;
610 }
611
612 let OtherVar = SOME_VAR + 1;
613 OtherVar
614}
615
616#[allow(nonstandard_style)]
617mod CheckNonstandardStyle {
618 fn HiImABadFnName() {}
619}
620
621#[allow(bad_style)]
622mod CheckBadStyle {
623 struct fooo;
624}
625
626mod F {
627 #![allow(non_snake_case)]
628 fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {
629 _ = BAD_NAME_HI;
630 }
631}
632
633#[allow(non_snake_case, non_camel_case_types)]
634pub struct some_type {
635 SOME_FIELD: u8,
636 SomeField: u16,
637}
638
639#[allow(non_upper_case_globals)]
640pub const some_const: u8 = 10;
641
642#[allow(non_upper_case_globals)]
643pub static SomeStatic: u8 = 10;
644
645#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
646trait BAD_TRAIT {
647 const bad_const: u8;
648 type BAD_TYPE;
649 fn BAD_FUNCTION(BAD_PARAM: u8);
650 fn BadFunction();
651}
652 "#,
653 );
654 }
655
656 #[test]
657 fn deny_attributes() {
658 check_diagnostics(
659 r#"
660#[deny(non_snake_case)]
661fn NonSnakeCaseName(some_var: u8) -> u8 {
662 //^^^^^^^^^^^^^^^^ 💡 error: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
663 // cov_flags generated output from elsewhere in this file
664 extern "C" {
665 #[no_mangle]
666 static lower_case: u8;
667 }
668
669 let OtherVar = some_var + 1;
670 //^^^^^^^^ 💡 error: Variable `OtherVar` should have snake_case name, e.g. `other_var`
671 OtherVar
672}
673
674#[deny(nonstandard_style)]
675mod CheckNonstandardStyle {
676 //^^^^^^^^^^^^^^^^^^^^^ 💡 error: Module `CheckNonstandardStyle` should have snake_case name, e.g. `check_nonstandard_style`
677 fn HiImABadFnName() {}
678 //^^^^^^^^^^^^^^ 💡 error: Function `HiImABadFnName` should have snake_case name, e.g. `hi_im_abad_fn_name`
679}
680
681#[deny(warnings)]
682mod CheckBadStyle {
683 //^^^^^^^^^^^^^ 💡 error: Module `CheckBadStyle` should have snake_case name, e.g. `check_bad_style`
684 struct fooo;
685 //^^^^ 💡 error: Structure `fooo` should have UpperCamelCase name, e.g. `Fooo`
686}
687
688mod F {
689 //^ 💡 error: Module `F` should have snake_case name, e.g. `f`
690 #![deny(non_snake_case)]
691 fn CheckItWorksWithModAttr() {}
692 //^^^^^^^^^^^^^^^^^^^^^^^ 💡 error: Function `CheckItWorksWithModAttr` should have snake_case name, e.g. `check_it_works_with_mod_attr`
693}
694
695#[deny(non_snake_case, non_camel_case_types)]
696pub struct some_type {
697 //^^^^^^^^^ 💡 error: Structure `some_type` should have UpperCamelCase name, e.g. `SomeType`
698 SOME_FIELD: u8,
699 //^^^^^^^^^^ 💡 error: Field `SOME_FIELD` should have snake_case name, e.g. `some_field`
700 SomeField: u16,
701 //^^^^^^^^^ 💡 error: Field `SomeField` should have snake_case name, e.g. `some_field`
702}
703
704#[deny(non_upper_case_globals)]
705pub const some_const: u8 = 10;
706 //^^^^^^^^^^ 💡 error: Constant `some_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_CONST`
707
708#[deny(non_upper_case_globals)]
709pub static SomeStatic: u8 = 10;
710 //^^^^^^^^^^ 💡 error: Static variable `SomeStatic` should have UPPER_SNAKE_CASE name, e.g. `SOME_STATIC`
711
712#[deny(non_snake_case, non_camel_case_types, non_upper_case_globals)]
713trait BAD_TRAIT {
714 // ^^^^^^^^^ 💡 error: Trait `BAD_TRAIT` should have UpperCamelCase name, e.g. `BadTrait`
715 const bad_const: u8;
716 // ^^^^^^^^^ 💡 error: Constant `bad_const` should have UPPER_SNAKE_CASE name, e.g. `BAD_CONST`
717 type BAD_TYPE;
718 // ^^^^^^^^ 💡 error: Type alias `BAD_TYPE` should have UpperCamelCase name, e.g. `BadType`
719 fn BAD_FUNCTION(BAD_PARAM: u8);
720 // ^^^^^^^^^^^^ 💡 error: Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
721 // ^^^^^^^^^ 💡 error: Parameter `BAD_PARAM` should have snake_case name, e.g. `bad_param`
722 fn BadFunction();
723 // ^^^^^^^^^^^ 💡 error: Function `BadFunction` should have snake_case name, e.g. `bad_function`
724}
725 "#,
726 );
727 }
728
729 #[test]
730 fn fn_inner_items() {
731 check_diagnostics(
732 r#"
733fn main() {
734 const foo: bool = true;
735 //^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
736 static bar: bool = true;
737 //^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
738 fn BAZ() {
739 //^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
740 const foo: bool = true;
741 //^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
742 static bar: bool = true;
743 //^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
744 fn BAZ() {
745 //^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
746 let _INNER_INNER = 42;
747 //^^^^^^^^^^^^ 💡 warn: Variable `_INNER_INNER` should have snake_case name, e.g. `_inner_inner`
748 }
749
750 let _INNER_LOCAL = 42;
751 //^^^^^^^^^^^^ 💡 warn: Variable `_INNER_LOCAL` should have snake_case name, e.g. `_inner_local`
752 }
753}
754"#,
755 );
756 }
757
758 #[test]
759 fn const_body_inner_items() {
760 check_diagnostics(
761 r#"
762const _: () = {
763 static bar: bool = true;
764 //^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
765 fn BAZ() {}
766 //^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
767
768 const foo: () = {
769 //^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
770 const foo: bool = true;
771 //^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
772 static bar: bool = true;
773 //^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
774 fn BAZ() {}
775 //^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
776 };
777};
778"#,
779 );
780 }
781
782 #[test]
783 fn static_body_inner_items() {
784 check_diagnostics(
785 r#"
786static FOO: () = {
787 const foo: bool = true;
788 //^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
789 fn BAZ() {}
790 //^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
791
792 static bar: () = {
793 //^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
794 const foo: bool = true;
795 //^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
796 static bar: bool = true;
797 //^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
798 fn BAZ() {}
799 //^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
800 };
801};
802"#,
803 );
804 }
805
806 #[test]
807 #[should_panic]
809 fn enum_variant_body_inner_item() {
810 check_diagnostics(
811 r#"
812enum E {
813 A = {
814 const foo: bool = true;
815 //^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
816 static bar: bool = true;
817 //^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
818 fn BAZ() {}
819 //^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
820 42
821 },
822}
823"#,
824 );
825 }
826
827 #[test]
828 fn module_name_inline() {
829 check_diagnostics(
830 r#"
831mod M {
832 //^ 💡 warn: Module `M` should have snake_case name, e.g. `m`
833 mod IncorrectCase {}
834 //^^^^^^^^^^^^^ 💡 warn: Module `IncorrectCase` should have snake_case name, e.g. `incorrect_case`
835}
836"#,
837 );
838 }
839
840 #[test]
841 fn module_name_decl() {
842 check_diagnostics(
843 r#"
844//- /Foo.rs
845
846//- /main.rs
847mod Foo;
848 //^^^ 💡 warn: Module `Foo` should have snake_case name, e.g. `foo`
849"#,
850 )
851 }
852
853 #[test]
854 fn test_field_shorthand() {
855 check_diagnostics(
856 r#"
857struct Foo { _nonSnake: u8 }
858 // ^^^^^^^^^ 💡 warn: Field `_nonSnake` should have snake_case name, e.g. `_non_snake`
859fn func(Foo { _nonSnake }: Foo) {}
860"#,
861 );
862 }
863
864 #[test]
865 fn test_match() {
866 check_diagnostics(
867 r#"
868enum Foo { Variant { nonSnake1: u8 } }
869 // ^^^^^^^^^ 💡 warn: Field `nonSnake1` should have snake_case name, e.g. `non_snake1`
870fn func() {
871 match (Foo::Variant { nonSnake1: 1 }) {
872 Foo::Variant { nonSnake1: _nonSnake2 } => {},
873 // ^^^^^^^^^^ 💡 warn: Variable `_nonSnake2` should have snake_case name, e.g. `_non_snake2`
874 }
875}
876"#,
877 );
878
879 check_diagnostics(
880 r#"
881struct Foo(u8);
882
883fn func() {
884 match Foo(1) {
885 Foo(_nonSnake) => {},
886 // ^^^^^^^^^ 💡 warn: Variable `_nonSnake` should have snake_case name, e.g. `_non_snake`
887 }
888}
889"#,
890 );
891
892 check_diagnostics(
893 r#"
894fn main() {
895 match 1 {
896 _Bad1 @ _Bad2 => {}
897 // ^^^^^ 💡 warn: Variable `_Bad1` should have snake_case name, e.g. `_bad1`
898 // ^^^^^ 💡 warn: Variable `_Bad2` should have snake_case name, e.g. `_bad2`
899 }
900}
901"#,
902 );
903 check_diagnostics(
904 r#"
905fn main() {
906 match 1 { _Bad1 => () }
907 // ^^^^^ 💡 warn: Variable `_Bad1` should have snake_case name, e.g. `_bad1`
908}
909"#,
910 );
911
912 check_diagnostics(
913 r#"
914enum Foo { V1, V2 }
915use Foo::V1;
916
917fn main() {
918 match V1 {
919 _Bad1 @ V1 => {},
920 // ^^^^^ 💡 warn: Variable `_Bad1` should have snake_case name, e.g. `_bad1`
921 Foo::V2 => {}
922 }
923}
924"#,
925 );
926 }
927
928 #[test]
929 fn test_for_loop() {
930 check_diagnostics(
931 r#"
932//- minicore: iterators
933fn func() {
934 for _nonSnake in [] {}
935 // ^^^^^^^^^ 💡 warn: Variable `_nonSnake` should have snake_case name, e.g. `_non_snake`
936}
937"#,
938 );
939
940 check_fix(
941 r#"
942//- minicore: iterators
943fn func() {
944 for nonSnake$0 in [] { nonSnake; }
945}
946"#,
947 r#"
948fn func() {
949 for non_snake in [] { non_snake; }
950}
951"#,
952 );
953 }
954
955 #[test]
956 fn override_lint_level() {
957 check_diagnostics(
958 r#"
959#![allow(unused_variables)]
960#[warn(nonstandard_style)]
961fn foo() {
962 let BAR;
963 // ^^^ 💡 warn: Variable `BAR` should have snake_case name, e.g. `bar`
964 #[allow(non_snake_case)]
965 let FOO;
966}
967
968#[warn(nonstandard_style)]
969fn foo() {
970 let BAR;
971 // ^^^ 💡 warn: Variable `BAR` should have snake_case name, e.g. `bar`
972 #[expect(non_snake_case)]
973 let FOO;
974 #[allow(non_snake_case)]
975 struct qux;
976 // ^^^ 💡 warn: Structure `qux` should have UpperCamelCase name, e.g. `Qux`
977
978 fn BAZ() {
979 // ^^^ 💡 error: Function `BAZ` should have snake_case name, e.g. `baz`
980 #![forbid(bad_style)]
981 }
982}
983 "#,
984 );
985 }
986
987 #[test]
988 fn different_files() {
989 check_diagnostics(
990 r#"
991//- /lib.rs
992#![expect(nonstandard_style)]
993
994mod BAD_CASE;
995
996fn BAD_CASE() {}
997
998//- /BAD_CASE.rs
999mod OtherBadCase;
1000 // ^^^^^^^^^^^^ 💡 error: Module `OtherBadCase` should have snake_case name, e.g. `other_bad_case`
1001
1002//- /BAD_CASE/OtherBadCase.rs
1003#![allow(non_snake_case)]
1004#![deny(non_snake_case)] // The lint level has been overridden.
1005
1006fn FOO() {}
1007// ^^^ 💡 error: Function `FOO` should have snake_case name, e.g. `foo`
1008
1009#[allow(bad_style)]
1010mod FINE_WITH_BAD_CASE;
1011
1012//- /BAD_CASE/OtherBadCase/FINE_WITH_BAD_CASE.rs
1013struct QUX;
1014const foo: i32 = 0;
1015fn BAR() {
1016 let BAZ;
1017 _ = BAZ;
1018}
1019 "#,
1020 );
1021 }
1022
1023 #[test]
1024 fn cfged_lint_attrs() {
1025 check_diagnostics(
1026 r#"
1027//- /lib.rs cfg:feature=cool_feature
1028#[cfg_attr(any(), allow(non_snake_case))]
1029fn FOO() {}
1030// ^^^ 💡 warn: Function `FOO` should have snake_case name, e.g. `foo`
1031
1032#[cfg_attr(non_existent, allow(non_snake_case))]
1033fn BAR() {}
1034// ^^^ 💡 warn: Function `BAR` should have snake_case name, e.g. `bar`
1035
1036#[cfg_attr(feature = "cool_feature", allow(non_snake_case))]
1037fn BAZ() {}
1038
1039#[cfg_attr(feature = "cool_feature", cfg_attr ( all ( ) , allow ( non_snake_case ) ) ) ]
1040fn QUX() {}
1041 "#,
1042 );
1043 }
1044
1045 #[test]
1046 fn allow_with_comment() {
1047 check_diagnostics(
1048 r#"
1049#[allow(
1050 // Yo, sup
1051 non_snake_case
1052)]
1053fn foo(_HelloWorld: ()) {}
1054 "#,
1055 );
1056 }
1057}