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.rs459
1 files changed, 459 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..68f25f284
--- /dev/null
+++ b/crates/ide_diagnostics/src/handlers/incorrect_case.rs
@@ -0,0 +1,459 @@
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// ^^^ 💡 weak: 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// ^^^^^^^^^^^^^^^^ 💡 weak: 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 // ^^^^^^^^^ 💡 weak: Parameter `SomeParam` should have snake_case name, e.g. `some_param`
174
175fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
176 // ^^^^^^^^^^ 💡 weak: 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 // ^^^^^^^^^^ 💡 weak: Variable `SOME_VALUE` should have snake_case name, e.g. `some_value`
188 let AnotherValue = 20;
189 // ^^^^^^^^^^^^ 💡 weak: 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 // ^^^^^^^^^^^^^^^^^^^ 💡 weak: Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName`
201
202struct SCREAMING_CASE {}
203 // ^^^^^^^^^^^^^^ 💡 weak: 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 // ^^^^^^^^^ 💡 weak: 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 // ^^^^^^^^^ 💡 weak: Enum `some_enum` should have CamelCase name, e.g. `SomeEnum`
233
234enum SOME_ENUM {}
235 // ^^^^^^^^^ 💡 weak: 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 // ^^^^^^^^^^^^ 💡 weak: 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 // ^^^^^^^^^^^^^^^^ 💡 weak: 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 // ^^^^^^^^^^^^^^^^ 💡 weak: 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 // ^^^^^^^^^^ 💡 weak: Structure `someStruct` should have CamelCase name, e.g. `SomeStruct`
285
286impl someStruct {
287 fn SomeFunc(&self) {
288 // ^^^^^^^^ 💡 weak: Function `SomeFunc` should have snake_case name, e.g. `some_func`
289 let WHY_VAR_IS_CAPS = 10;
290 // ^^^^^^^^^^^^^^^ 💡 weak: 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 // ^^^^^^^^ 💡 weak: 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 fn complex_ignore() {
345 // FIXME: this should trigger errors for the second case.
346 check_diagnostics(
347 r#"
348trait T { fn a(); }
349struct U {}
350impl T for U {
351 fn a() {
352 #[allow(non_snake_case)]
353 trait __BitFlagsOk {
354 const HiImAlsoBad: u8 = 2;
355 fn Dirty(&self) -> bool { false }
356 }
357
358 trait __BitFlagsBad {
359 const HiImAlsoBad: u8 = 2;
360 fn Dirty(&self) -> bool { false }
361 }
362 }
363}
364"#,
365 );
366 }
367
368 #[test]
369 fn infinite_loop_inner_items() {
370 check_diagnostics(
371 r#"
372fn qualify() {
373 mod foo {
374 use super::*;
375 }
376}
377 "#,
378 )
379 }
380
381 #[test] // Issue #8809.
382 fn parenthesized_parameter() {
383 check_diagnostics(r#"fn f((O): _) {}"#)
384 }
385
386 #[test]
387 fn ignores_extern_items() {
388 cov_mark::check!(extern_func_incorrect_case_ignored);
389 cov_mark::check!(extern_static_incorrect_case_ignored);
390 check_diagnostics(
391 r#"
392extern {
393 fn NonSnakeCaseName(SOME_VAR: u8) -> u8;
394 pub static SomeStatic: u8 = 10;
395}
396 "#,
397 );
398 }
399
400 #[test]
401 fn bug_traits_arent_checked() {
402 // FIXME: Traits and functions in traits aren't currently checked by
403 // r-a, even though rustc will complain about them.
404 check_diagnostics(
405 r#"
406trait BAD_TRAIT {
407 fn BAD_FUNCTION();
408 fn BadFunction();
409}
410 "#,
411 );
412 }
413
414 #[test]
415 fn allow_attributes() {
416 check_diagnostics(
417 r#"
418#[allow(non_snake_case)]
419fn NonSnakeCaseName(SOME_VAR: u8) -> u8{
420 // cov_flags generated output from elsewhere in this file
421 extern "C" {
422 #[no_mangle]
423 static lower_case: u8;
424 }
425
426 let OtherVar = SOME_VAR + 1;
427 OtherVar
428}
429
430#[allow(nonstandard_style)]
431mod CheckNonstandardStyle {
432 fn HiImABadFnName() {}
433}
434
435#[allow(bad_style)]
436mod CheckBadStyle {
437 fn HiImABadFnName() {}
438}
439
440mod F {
441 #![allow(non_snake_case)]
442 fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {}
443}
444
445#[allow(non_snake_case, non_camel_case_types)]
446pub struct some_type {
447 SOME_FIELD: u8,
448 SomeField: u16,
449}
450
451#[allow(non_upper_case_globals)]
452pub const some_const: u8 = 10;
453
454#[allow(non_upper_case_globals)]
455pub static SomeStatic: u8 = 10;
456 "#,
457 );
458 }
459}