aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_diagnostics/src/handlers/incorrect_case.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_diagnostics/src/handlers/incorrect_case.rs')
-rw-r--r--crates/ide_diagnostics/src/handlers/incorrect_case.rs479
1 files changed, 479 insertions, 0 deletions
diff --git a/crates/ide_diagnostics/src/handlers/incorrect_case.rs b/crates/ide_diagnostics/src/handlers/incorrect_case.rs
new file mode 100644
index 000000000..3a33029cf
--- /dev/null
+++ b/crates/ide_diagnostics/src/handlers/incorrect_case.rs
@@ -0,0 +1,479 @@
1use hir::{db::AstDatabase, InFile};
2use ide_db::{assists::Assist, defs::NameClass};
3use syntax::AstNode;
4
5use crate::{
6 // references::rename::rename_with_semantics,
7 unresolved_fix,
8 Diagnostic,
9 DiagnosticsContext,
10 Severity,
11};
12
13// Diagnostic: incorrect-ident-case
14//
15// This diagnostic is triggered if an item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention].
16pub(crate) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Diagnostic {
17 Diagnostic::new(
18 "incorrect-ident-case",
19 format!(
20 "{} `{}` should have {} name, e.g. `{}`",
21 d.ident_type, d.ident_text, d.expected_case, d.suggested_text
22 ),
23 ctx.sema.diagnostics_display_range(InFile::new(d.file, d.ident.clone().into())).range,
24 )
25 .severity(Severity::WeakWarning)
26 .with_fixes(fixes(ctx, d))
27}
28
29fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Assist>> {
30 let root = ctx.sema.db.parse_or_expand(d.file)?;
31 let name_node = d.ident.to_node(&root);
32 let def = NameClass::classify(&ctx.sema, &name_node)?.defined(ctx.sema.db)?;
33
34 let name_node = InFile::new(d.file, name_node.syntax());
35 let frange = name_node.original_file_range(ctx.sema.db);
36
37 let label = format!("Rename to {}", d.suggested_text);
38 let mut res = unresolved_fix("change_case", &label, frange.range);
39 if ctx.resolve.should_resolve(&res.id) {
40 let source_change = def.rename(&ctx.sema, &d.suggested_text);
41 res.source_change = Some(source_change.ok().unwrap_or_default());
42 }
43
44 Some(vec![res])
45}
46
47#[cfg(test)]
48mod change_case {
49 use crate::tests::{check_diagnostics, check_fix};
50
51 #[test]
52 fn test_rename_incorrect_case() {
53 check_fix(
54 r#"
55pub struct test_struct$0 { one: i32 }
56
57pub fn some_fn(val: test_struct) -> test_struct {
58 test_struct { one: val.one + 1 }
59}
60"#,
61 r#"
62pub struct TestStruct { one: i32 }
63
64pub fn some_fn(val: TestStruct) -> TestStruct {
65 TestStruct { one: val.one + 1 }
66}
67"#,
68 );
69
70 check_fix(
71 r#"
72pub fn some_fn(NonSnakeCase$0: u8) -> u8 {
73 NonSnakeCase
74}
75"#,
76 r#"
77pub fn some_fn(non_snake_case: u8) -> u8 {
78 non_snake_case
79}
80"#,
81 );
82
83 check_fix(
84 r#"
85pub fn SomeFn$0(val: u8) -> u8 {
86 if val != 0 { SomeFn(val - 1) } else { val }
87}
88"#,
89 r#"
90pub fn some_fn(val: u8) -> u8 {
91 if val != 0 { some_fn(val - 1) } else { val }
92}
93"#,
94 );
95
96 check_fix(
97 r#"
98fn some_fn() {
99 let whatAWeird_Formatting$0 = 10;
100 another_func(whatAWeird_Formatting);
101}
102"#,
103 r#"
104fn some_fn() {
105 let what_a_weird_formatting = 10;
106 another_func(what_a_weird_formatting);
107}
108"#,
109 );
110 }
111
112 #[test]
113 fn test_uppercase_const_no_diagnostics() {
114 check_diagnostics(
115 r#"
116fn foo() {
117 const ANOTHER_ITEM: &str = "some_item";
118}
119"#,
120 );
121 }
122
123 #[test]
124 fn test_rename_incorrect_case_struct_method() {
125 check_fix(
126 r#"
127pub struct TestStruct;
128
129impl TestStruct {
130 pub fn SomeFn$0() -> TestStruct {
131 TestStruct
132 }
133}
134"#,
135 r#"
136pub struct TestStruct;
137
138impl TestStruct {
139 pub fn some_fn() -> TestStruct {
140 TestStruct
141 }
142}
143"#,
144 );
145 }
146
147 #[test]
148 fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() {
149 check_diagnostics(
150 r#"
151fn FOO() {}
152// ^^^ Function `FOO` should have snake_case name, e.g. `foo`
153"#,
154 );
155 check_fix(r#"fn FOO$0() {}"#, r#"fn foo() {}"#);
156 }
157
158 #[test]
159 fn incorrect_function_name() {
160 check_diagnostics(
161 r#"
162fn NonSnakeCaseName() {}
163// ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
164"#,
165 );
166 }
167
168 #[test]
169 fn incorrect_function_params() {
170 check_diagnostics(
171 r#"
172fn foo(SomeParam: u8) {}
173 // ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param`
174
175fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
176 // ^^^^^^^^^^ Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param`
177"#,
178 );
179 }
180
181 #[test]
182 fn incorrect_variable_names() {
183 check_diagnostics(
184 r#"
185fn foo() {
186 let SOME_VALUE = 10;
187 // ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value`
188 let AnotherValue = 20;
189 // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value`
190}
191"#,
192 );
193 }
194
195 #[test]
196 fn incorrect_struct_names() {
197 check_diagnostics(
198 r#"
199struct non_camel_case_name {}
200 // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName`
201
202struct SCREAMING_CASE {}
203 // ^^^^^^^^^^^^^^ Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase`
204"#,
205 );
206 }
207
208 #[test]
209 fn no_diagnostic_for_camel_cased_acronyms_in_struct_name() {
210 check_diagnostics(
211 r#"
212struct AABB {}
213"#,
214 );
215 }
216
217 #[test]
218 fn incorrect_struct_field() {
219 check_diagnostics(
220 r#"
221struct SomeStruct { SomeField: u8 }
222 // ^^^^^^^^^ Field `SomeField` should have snake_case name, e.g. `some_field`
223"#,
224 );
225 }
226
227 #[test]
228 fn incorrect_enum_names() {
229 check_diagnostics(
230 r#"
231enum some_enum { Val(u8) }
232 // ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum`
233
234enum SOME_ENUM {}
235 // ^^^^^^^^^ Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum`
236"#,
237 );
238 }
239
240 #[test]
241 fn no_diagnostic_for_camel_cased_acronyms_in_enum_name() {
242 check_diagnostics(
243 r#"
244enum AABB {}
245"#,
246 );
247 }
248
249 #[test]
250 fn incorrect_enum_variant_name() {
251 check_diagnostics(
252 r#"
253enum SomeEnum { SOME_VARIANT(u8) }
254 // ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant`
255"#,
256 );
257 }
258
259 #[test]
260 fn incorrect_const_name() {
261 check_diagnostics(
262 r#"
263const some_weird_const: u8 = 10;
264 // ^^^^^^^^^^^^^^^^ Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
265"#,
266 );
267 }
268
269 #[test]
270 fn incorrect_static_name() {
271 check_diagnostics(
272 r#"
273static some_weird_const: u8 = 10;
274 // ^^^^^^^^^^^^^^^^ Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
275"#,
276 );
277 }
278
279 #[test]
280 fn fn_inside_impl_struct() {
281 check_diagnostics(
282 r#"
283struct someStruct;
284 // ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct`
285
286impl someStruct {
287 fn SomeFunc(&self) {
288 // ^^^^^^^^ Function `SomeFunc` should have snake_case name, e.g. `some_func`
289 let WHY_VAR_IS_CAPS = 10;
290 // ^^^^^^^^^^^^^^^ Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps`
291 }
292}
293"#,
294 );
295 }
296
297 #[test]
298 fn no_diagnostic_for_enum_varinats() {
299 check_diagnostics(
300 r#"
301enum Option { Some, None }
302
303fn main() {
304 match Option::None {
305 None => (),
306 Some => (),
307 }
308}
309"#,
310 );
311 }
312
313 #[test]
314 fn non_let_bind() {
315 check_diagnostics(
316 r#"
317enum Option { Some, None }
318
319fn main() {
320 match Option::None {
321 SOME_VAR @ None => (),
322 // ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var`
323 Some => (),
324 }
325}
326"#,
327 );
328 }
329
330 #[test]
331 fn allow_attributes_crate_attr() {
332 check_diagnostics(
333 r#"
334#![allow(non_snake_case)]
335
336mod F {
337 fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {}
338}
339 "#,
340 );
341 }
342
343 #[test]
344 #[ignore]
345 fn bug_trait_inside_fn() {
346 // FIXME:
347 // This is broken, and in fact, should not even be looked at by this
348 // lint in the first place. There's weird stuff going on in the
349 // collection phase.
350 // It's currently being brought in by:
351 // * validate_func on `a` recursing into modules
352 // * then it finds the trait and then the function while iterating
353 // through modules
354 // * then validate_func is called on Dirty
355 // * ... which then proceeds to look at some unknown module taking no
356 // attrs from either the impl or the fn a, and then finally to the root
357 // module
358 //
359 // It should find the attribute on the trait, but it *doesn't even see
360 // the trait* as far as I can tell.
361
362 check_diagnostics(
363 r#"
364trait T { fn a(); }
365struct U {}
366impl T for U {
367 fn a() {
368 // this comes out of bitflags, mostly
369 #[allow(non_snake_case)]
370 trait __BitFlags {
371 const HiImAlsoBad: u8 = 2;
372 #[inline]
373 fn Dirty(&self) -> bool {
374 false
375 }
376 }
377
378 }
379}
380 "#,
381 );
382 }
383
384 #[test]
385 fn infinite_loop_inner_items() {
386 check_diagnostics(
387 r#"
388fn qualify() {
389 mod foo {
390 use super::*;
391 }
392}
393 "#,
394 )
395 }
396
397 #[test] // Issue #8809.
398 fn parenthesized_parameter() {
399 check_diagnostics(r#"fn f((O): _) {}"#)
400 }
401
402 #[test]
403 fn ignores_extern_items() {
404 cov_mark::check!(extern_func_incorrect_case_ignored);
405 cov_mark::check!(extern_static_incorrect_case_ignored);
406 check_diagnostics(
407 r#"
408extern {
409 fn NonSnakeCaseName(SOME_VAR: u8) -> u8;
410 pub static SomeStatic: u8 = 10;
411}
412 "#,
413 );
414 }
415
416 #[test]
417 #[ignore]
418 fn bug_traits_arent_checked() {
419 // FIXME: Traits and functions in traits aren't currently checked by
420 // r-a, even though rustc will complain about them.
421 check_diagnostics(
422 r#"
423trait BAD_TRAIT {
424 // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait`
425 fn BAD_FUNCTION();
426 // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
427 fn BadFunction();
428 // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function`
429}
430 "#,
431 );
432 }
433
434 #[test]
435 fn allow_attributes() {
436 check_diagnostics(
437 r#"
438#[allow(non_snake_case)]
439fn NonSnakeCaseName(SOME_VAR: u8) -> u8{
440 // cov_flags generated output from elsewhere in this file
441 extern "C" {
442 #[no_mangle]
443 static lower_case: u8;
444 }
445
446 let OtherVar = SOME_VAR + 1;
447 OtherVar
448}
449
450#[allow(nonstandard_style)]
451mod CheckNonstandardStyle {
452 fn HiImABadFnName() {}
453}
454
455#[allow(bad_style)]
456mod CheckBadStyle {
457 fn HiImABadFnName() {}
458}
459
460mod F {
461 #![allow(non_snake_case)]
462 fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {}
463}
464
465#[allow(non_snake_case, non_camel_case_types)]
466pub struct some_type {
467 SOME_FIELD: u8,
468 SomeField: u16,
469}
470
471#[allow(non_upper_case_globals)]
472pub const some_const: u8 = 10;
473
474#[allow(non_upper_case_globals)]
475pub static SomeStatic: u8 = 10;
476 "#,
477 );
478 }
479}