diff options
author | Aleksey Kladov <[email protected]> | 2021-06-13 19:09:03 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-06-13 19:09:03 +0100 |
commit | fc30c5ccbeba2a102922da497809dd3f812544c4 (patch) | |
tree | ed3067580e998f04e94bfb93508fe3f12c851c3b /crates/ide/src/diagnostics/incorrect_case.rs | |
parent | 2ad78924621420cb323efdeb3d875ca3f47d940f (diff) |
internal: refactor incorrect case diagnostics
Diffstat (limited to 'crates/ide/src/diagnostics/incorrect_case.rs')
-rw-r--r-- | crates/ide/src/diagnostics/incorrect_case.rs | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/crates/ide/src/diagnostics/incorrect_case.rs b/crates/ide/src/diagnostics/incorrect_case.rs new file mode 100644 index 000000000..56283b58b --- /dev/null +++ b/crates/ide/src/diagnostics/incorrect_case.rs | |||
@@ -0,0 +1,166 @@ | |||
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 | diagnostics::{unresolved_fix, Diagnostic, DiagnosticsContext}, | ||
8 | references::rename::rename_with_semantics, | ||
9 | Severity, | ||
10 | }; | ||
11 | |||
12 | // Diagnostic: incorrect-ident-case | ||
13 | // | ||
14 | // 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]. | ||
15 | pub(super) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Diagnostic { | ||
16 | Diagnostic::new( | ||
17 | "incorrect-ident-case", | ||
18 | format!( | ||
19 | "{} `{}` should have {} name, e.g. `{}`", | ||
20 | d.ident_type, d.ident_text, d.expected_case, d.suggested_text | ||
21 | ), | ||
22 | ctx.sema.diagnostics_display_range(InFile::new(d.file, d.ident.clone().into())).range, | ||
23 | ) | ||
24 | .severity(Severity::WeakWarning) | ||
25 | .with_fixes(fixes(ctx, d)) | ||
26 | } | ||
27 | |||
28 | fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Assist>> { | ||
29 | let root = ctx.sema.db.parse_or_expand(d.file)?; | ||
30 | let name_node = d.ident.to_node(&root); | ||
31 | |||
32 | let name_node = InFile::new(d.file, name_node.syntax()); | ||
33 | let frange = name_node.original_file_range(ctx.sema.db); | ||
34 | let file_position = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; | ||
35 | |||
36 | let label = format!("Rename to {}", d.suggested_text); | ||
37 | let mut res = unresolved_fix("change_case", &label, frange.range); | ||
38 | if ctx.resolve.should_resolve(&res.id) { | ||
39 | let source_change = rename_with_semantics(&ctx.sema, file_position, &d.suggested_text); | ||
40 | res.source_change = Some(source_change.ok().unwrap_or_default()); | ||
41 | } | ||
42 | |||
43 | Some(vec![res]) | ||
44 | } | ||
45 | |||
46 | #[cfg(test)] | ||
47 | mod change_case { | ||
48 | use crate::{ | ||
49 | diagnostics::tests::{check_diagnostics, check_fix}, | ||
50 | fixture, AssistResolveStrategy, DiagnosticsConfig, | ||
51 | }; | ||
52 | |||
53 | #[test] | ||
54 | fn test_rename_incorrect_case() { | ||
55 | check_fix( | ||
56 | r#" | ||
57 | pub struct test_struct$0 { one: i32 } | ||
58 | |||
59 | pub fn some_fn(val: test_struct) -> test_struct { | ||
60 | test_struct { one: val.one + 1 } | ||
61 | } | ||
62 | "#, | ||
63 | r#" | ||
64 | pub struct TestStruct { one: i32 } | ||
65 | |||
66 | pub fn some_fn(val: TestStruct) -> TestStruct { | ||
67 | TestStruct { one: val.one + 1 } | ||
68 | } | ||
69 | "#, | ||
70 | ); | ||
71 | |||
72 | check_fix( | ||
73 | r#" | ||
74 | pub fn some_fn(NonSnakeCase$0: u8) -> u8 { | ||
75 | NonSnakeCase | ||
76 | } | ||
77 | "#, | ||
78 | r#" | ||
79 | pub fn some_fn(non_snake_case: u8) -> u8 { | ||
80 | non_snake_case | ||
81 | } | ||
82 | "#, | ||
83 | ); | ||
84 | |||
85 | check_fix( | ||
86 | r#" | ||
87 | pub fn SomeFn$0(val: u8) -> u8 { | ||
88 | if val != 0 { SomeFn(val - 1) } else { val } | ||
89 | } | ||
90 | "#, | ||
91 | r#" | ||
92 | pub fn some_fn(val: u8) -> u8 { | ||
93 | if val != 0 { some_fn(val - 1) } else { val } | ||
94 | } | ||
95 | "#, | ||
96 | ); | ||
97 | |||
98 | check_fix( | ||
99 | r#" | ||
100 | fn some_fn() { | ||
101 | let whatAWeird_Formatting$0 = 10; | ||
102 | another_func(whatAWeird_Formatting); | ||
103 | } | ||
104 | "#, | ||
105 | r#" | ||
106 | fn some_fn() { | ||
107 | let what_a_weird_formatting = 10; | ||
108 | another_func(what_a_weird_formatting); | ||
109 | } | ||
110 | "#, | ||
111 | ); | ||
112 | } | ||
113 | |||
114 | #[test] | ||
115 | fn test_uppercase_const_no_diagnostics() { | ||
116 | check_diagnostics( | ||
117 | r#" | ||
118 | fn foo() { | ||
119 | const ANOTHER_ITEM$0: &str = "some_item"; | ||
120 | } | ||
121 | "#, | ||
122 | ); | ||
123 | } | ||
124 | |||
125 | #[test] | ||
126 | fn test_rename_incorrect_case_struct_method() { | ||
127 | check_fix( | ||
128 | r#" | ||
129 | pub struct TestStruct; | ||
130 | |||
131 | impl TestStruct { | ||
132 | pub fn SomeFn$0() -> TestStruct { | ||
133 | TestStruct | ||
134 | } | ||
135 | } | ||
136 | "#, | ||
137 | r#" | ||
138 | pub struct TestStruct; | ||
139 | |||
140 | impl TestStruct { | ||
141 | pub fn some_fn() -> TestStruct { | ||
142 | TestStruct | ||
143 | } | ||
144 | } | ||
145 | "#, | ||
146 | ); | ||
147 | } | ||
148 | |||
149 | #[test] | ||
150 | fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() { | ||
151 | let input = r#"fn FOO$0() {}"#; | ||
152 | let expected = r#"fn foo() {}"#; | ||
153 | |||
154 | let (analysis, file_position) = fixture::position(input); | ||
155 | let diagnostics = analysis | ||
156 | .diagnostics( | ||
157 | &DiagnosticsConfig::default(), | ||
158 | AssistResolveStrategy::All, | ||
159 | file_position.file_id, | ||
160 | ) | ||
161 | .unwrap(); | ||
162 | assert_eq!(diagnostics.len(), 1); | ||
163 | |||
164 | check_fix(input, expected); | ||
165 | } | ||
166 | } | ||