diff options
author | Aleksey Kladov <[email protected]> | 2021-06-14 11:15:05 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-06-14 15:45:17 +0100 |
commit | 1d2772c2c7dc0a42d8a9429d24ea41412add61b3 (patch) | |
tree | 2e727c6465f972b7f62857bc1143e08f4b4416d4 /crates/ide_diagnostics/src/incorrect_case.rs | |
parent | 3d2f0400a26ef6b07d61a06e1b543072b627570e (diff) |
internal: move diagnostics to a new crate
Diffstat (limited to 'crates/ide_diagnostics/src/incorrect_case.rs')
-rw-r--r-- | crates/ide_diagnostics/src/incorrect_case.rs | 496 |
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 @@ | |||
1 | use hir::{db::AstDatabase, InFile}; | ||
2 | use ide_assists::Assist; | ||
3 | use ide_db::base_db::FilePosition; | ||
4 | use syntax::AstNode; | ||
5 | |||
6 | use 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]. | ||
17 | pub(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 | |||
30 | fn 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)] | ||
54 | mod 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#" | ||
65 | pub struct test_struct$0 { one: i32 } | ||
66 | |||
67 | pub fn some_fn(val: test_struct) -> test_struct { | ||
68 | test_struct { one: val.one + 1 } | ||
69 | } | ||
70 | "#, | ||
71 | r#" | ||
72 | pub struct TestStruct { one: i32 } | ||
73 | |||
74 | pub fn some_fn(val: TestStruct) -> TestStruct { | ||
75 | TestStruct { one: val.one + 1 } | ||
76 | } | ||
77 | "#, | ||
78 | ); | ||
79 | |||
80 | check_fix( | ||
81 | r#" | ||
82 | pub fn some_fn(NonSnakeCase$0: u8) -> u8 { | ||
83 | NonSnakeCase | ||
84 | } | ||
85 | "#, | ||
86 | r#" | ||
87 | pub fn some_fn(non_snake_case: u8) -> u8 { | ||
88 | non_snake_case | ||
89 | } | ||
90 | "#, | ||
91 | ); | ||
92 | |||
93 | check_fix( | ||
94 | r#" | ||
95 | pub fn SomeFn$0(val: u8) -> u8 { | ||
96 | if val != 0 { SomeFn(val - 1) } else { val } | ||
97 | } | ||
98 | "#, | ||
99 | r#" | ||
100 | pub 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#" | ||
108 | fn some_fn() { | ||
109 | let whatAWeird_Formatting$0 = 10; | ||
110 | another_func(whatAWeird_Formatting); | ||
111 | } | ||
112 | "#, | ||
113 | r#" | ||
114 | fn 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#" | ||
126 | fn 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#" | ||
137 | pub struct TestStruct; | ||
138 | |||
139 | impl TestStruct { | ||
140 | pub fn SomeFn$0() -> TestStruct { | ||
141 | TestStruct | ||
142 | } | ||
143 | } | ||
144 | "#, | ||
145 | r#" | ||
146 | pub struct TestStruct; | ||
147 | |||
148 | impl 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#" | ||
179 | fn 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#" | ||
189 | fn foo(SomeParam: u8) {} | ||
190 | // ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param` | ||
191 | |||
192 | fn 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#" | ||
202 | fn 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#" | ||
216 | struct non_camel_case_name {} | ||
217 | // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName` | ||
218 | |||
219 | struct 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#" | ||
229 | struct AABB {} | ||
230 | "#, | ||
231 | ); | ||
232 | } | ||
233 | |||
234 | #[test] | ||
235 | fn incorrect_struct_field() { | ||
236 | check_diagnostics( | ||
237 | r#" | ||
238 | struct 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#" | ||
248 | enum some_enum { Val(u8) } | ||
249 | // ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum` | ||
250 | |||
251 | enum 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#" | ||
261 | enum AABB {} | ||
262 | "#, | ||
263 | ); | ||
264 | } | ||
265 | |||
266 | #[test] | ||
267 | fn incorrect_enum_variant_name() { | ||
268 | check_diagnostics( | ||
269 | r#" | ||
270 | enum 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#" | ||
280 | const 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#" | ||
290 | static 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#" | ||
300 | struct someStruct; | ||
301 | // ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct` | ||
302 | |||
303 | impl 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#" | ||
318 | enum Option { Some, None } | ||
319 | |||
320 | fn 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#" | ||
334 | enum Option { Some, None } | ||
335 | |||
336 | fn 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 | |||
353 | mod 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#" | ||
381 | trait T { fn a(); } | ||
382 | struct U {} | ||
383 | impl 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#" | ||
405 | fn 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#" | ||
425 | extern { | ||
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#" | ||
440 | trait 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)] | ||
456 | fn 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)] | ||
468 | mod CheckNonstandardStyle { | ||
469 | fn HiImABadFnName() {} | ||
470 | } | ||
471 | |||
472 | #[allow(bad_style)] | ||
473 | mod CheckBadStyle { | ||
474 | fn HiImABadFnName() {} | ||
475 | } | ||
476 | |||
477 | mod F { | ||
478 | #![allow(non_snake_case)] | ||
479 | fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {} | ||
480 | } | ||
481 | |||
482 | #[allow(non_snake_case, non_camel_case_types)] | ||
483 | pub struct some_type { | ||
484 | SOME_FIELD: u8, | ||
485 | SomeField: u16, | ||
486 | } | ||
487 | |||
488 | #[allow(non_upper_case_globals)] | ||
489 | pub const some_const: u8 = 10; | ||
490 | |||
491 | #[allow(non_upper_case_globals)] | ||
492 | pub static SomeStatic: u8 = 10; | ||
493 | "#, | ||
494 | ); | ||
495 | } | ||
496 | } | ||