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