ide_diagnostics/handlers/
incorrect_case.rs

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    // references::rename::rename_with_semantics,
10    unresolved_fix,
11};
12
13// Diagnostic: incorrect-ident-case
14//
15// This diagnostic is triggered if an item name doesn't follow [Rust naming convention](https://doc.rust-lang.org/1.0.0/style/style/naming/README.html).
16pub(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        // The name is lying. It also covers variants, traits, ...
21        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] // Issue #8809.
430    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    // FIXME
808    #[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}