diff options
-rw-r--r-- | Cargo.lock | 4 | ||||
-rw-r--r-- | crates/assists/src/handlers/generate_enum_match_method.rs | 10 | ||||
-rw-r--r-- | crates/assists/src/tests/generated.rs | 1 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics.rs | 33 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/decl_check.rs | 279 | ||||
-rw-r--r-- | crates/stdx/Cargo.toml | 2 |
6 files changed, 164 insertions, 165 deletions
diff --git a/Cargo.lock b/Cargo.lock index 8f1a8401f..1ceae965f 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -17,9 +17,9 @@ checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" | |||
17 | 17 | ||
18 | [[package]] | 18 | [[package]] |
19 | name = "always-assert" | 19 | name = "always-assert" |
20 | version = "0.1.1" | 20 | version = "0.1.2" |
21 | source = "registry+https://github.com/rust-lang/crates.io-index" | 21 | source = "registry+https://github.com/rust-lang/crates.io-index" |
22 | checksum = "727786f78c5bc0cda8011831616589f72084cb16b7df4213a997b78749b55a60" | 22 | checksum = "fbf688625d06217d5b1bb0ea9d9c44a1635fd0ee3534466388d18203174f4d11" |
23 | dependencies = [ | 23 | dependencies = [ |
24 | "log", | 24 | "log", |
25 | ] | 25 | ] |
diff --git a/crates/assists/src/handlers/generate_enum_match_method.rs b/crates/assists/src/handlers/generate_enum_match_method.rs index 270b438b7..ee89d4208 100644 --- a/crates/assists/src/handlers/generate_enum_match_method.rs +++ b/crates/assists/src/handlers/generate_enum_match_method.rs | |||
@@ -25,6 +25,7 @@ use crate::{utils::find_struct_impl, AssistContext, AssistId, AssistKind, Assist | |||
25 | // } | 25 | // } |
26 | // | 26 | // |
27 | // impl Version { | 27 | // impl Version { |
28 | // /// Returns `true` if the version is [`Minor`]. | ||
28 | // fn is_minor(&self) -> bool { | 29 | // fn is_minor(&self) -> bool { |
29 | // matches!(self, Self::Minor) | 30 | // matches!(self, Self::Minor) |
30 | // } | 31 | // } |
@@ -39,6 +40,7 @@ pub(crate) fn generate_enum_match_method(acc: &mut Assists, ctx: &AssistContext) | |||
39 | return None; | 40 | return None; |
40 | } | 41 | } |
41 | 42 | ||
43 | let enum_lowercase_name = to_lower_snake_case(&parent_enum.name()?.to_string()); | ||
42 | let fn_name = to_lower_snake_case(&variant_name.to_string()); | 44 | let fn_name = to_lower_snake_case(&variant_name.to_string()); |
43 | 45 | ||
44 | // Return early if we've found an existing new fn | 46 | // Return early if we've found an existing new fn |
@@ -64,9 +66,12 @@ pub(crate) fn generate_enum_match_method(acc: &mut Assists, ctx: &AssistContext) | |||
64 | 66 | ||
65 | format_to!( | 67 | format_to!( |
66 | buf, | 68 | buf, |
67 | " {}fn is_{}(&self) -> bool {{ | 69 | " /// Returns `true` if the {} is [`{}`]. |
70 | {}fn is_{}(&self) -> bool {{ | ||
68 | matches!(self, Self::{}) | 71 | matches!(self, Self::{}) |
69 | }}", | 72 | }}", |
73 | enum_lowercase_name, | ||
74 | variant_name, | ||
70 | vis, | 75 | vis, |
71 | fn_name, | 76 | fn_name, |
72 | variant_name | 77 | variant_name |
@@ -133,6 +138,7 @@ enum Variant { | |||
133 | } | 138 | } |
134 | 139 | ||
135 | impl Variant { | 140 | impl Variant { |
141 | /// Returns `true` if the variant is [`Minor`]. | ||
136 | fn is_minor(&self) -> bool { | 142 | fn is_minor(&self) -> bool { |
137 | matches!(self, Self::Minor) | 143 | matches!(self, Self::Minor) |
138 | } | 144 | } |
@@ -180,6 +186,7 @@ enum Variant { | |||
180 | enum Variant { Undefined } | 186 | enum Variant { Undefined } |
181 | 187 | ||
182 | impl Variant { | 188 | impl Variant { |
189 | /// Returns `true` if the variant is [`Undefined`]. | ||
183 | fn is_undefined(&self) -> bool { | 190 | fn is_undefined(&self) -> bool { |
184 | matches!(self, Self::Undefined) | 191 | matches!(self, Self::Undefined) |
185 | } | 192 | } |
@@ -204,6 +211,7 @@ pub(crate) enum Variant { | |||
204 | } | 211 | } |
205 | 212 | ||
206 | impl Variant { | 213 | impl Variant { |
214 | /// Returns `true` if the variant is [`Minor`]. | ||
207 | pub(crate) fn is_minor(&self) -> bool { | 215 | pub(crate) fn is_minor(&self) -> bool { |
208 | matches!(self, Self::Minor) | 216 | matches!(self, Self::Minor) |
209 | } | 217 | } |
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs index 960815bd9..0dbb05f2a 100644 --- a/crates/assists/src/tests/generated.rs +++ b/crates/assists/src/tests/generated.rs | |||
@@ -478,6 +478,7 @@ enum Version { | |||
478 | } | 478 | } |
479 | 479 | ||
480 | impl Version { | 480 | impl Version { |
481 | /// Returns `true` if the version is [`Minor`]. | ||
481 | fn is_minor(&self) -> bool { | 482 | fn is_minor(&self) -> bool { |
482 | matches!(self, Self::Minor) | 483 | matches!(self, Self::Minor) |
483 | } | 484 | } |
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs index 323c5f963..08483760c 100644 --- a/crates/hir_ty/src/diagnostics.rs +++ b/crates/hir_ty/src/diagnostics.rs | |||
@@ -345,6 +345,37 @@ impl fmt::Display for CaseType { | |||
345 | } | 345 | } |
346 | } | 346 | } |
347 | 347 | ||
348 | #[derive(Debug)] | ||
349 | pub enum IdentType { | ||
350 | Argument, | ||
351 | Constant, | ||
352 | Enum, | ||
353 | Field, | ||
354 | Function, | ||
355 | StaticVariable, | ||
356 | Structure, | ||
357 | Variable, | ||
358 | Variant, | ||
359 | } | ||
360 | |||
361 | impl fmt::Display for IdentType { | ||
362 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
363 | let repr = match self { | ||
364 | IdentType::Argument => "Argument", | ||
365 | IdentType::Constant => "Constant", | ||
366 | IdentType::Enum => "Enum", | ||
367 | IdentType::Field => "Field", | ||
368 | IdentType::Function => "Function", | ||
369 | IdentType::StaticVariable => "Static variable", | ||
370 | IdentType::Structure => "Structure", | ||
371 | IdentType::Variable => "Variable", | ||
372 | IdentType::Variant => "Variant", | ||
373 | }; | ||
374 | |||
375 | write!(f, "{}", repr) | ||
376 | } | ||
377 | } | ||
378 | |||
348 | // Diagnostic: incorrect-ident-case | 379 | // Diagnostic: incorrect-ident-case |
349 | // | 380 | // |
350 | // 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]. | 381 | // 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]. |
@@ -353,7 +384,7 @@ pub struct IncorrectCase { | |||
353 | pub file: HirFileId, | 384 | pub file: HirFileId, |
354 | pub ident: AstPtr<ast::Name>, | 385 | pub ident: AstPtr<ast::Name>, |
355 | pub expected_case: CaseType, | 386 | pub expected_case: CaseType, |
356 | pub ident_type: String, | 387 | pub ident_type: IdentType, |
357 | pub ident_text: String, | 388 | pub ident_text: String, |
358 | pub suggested_text: String, | 389 | pub suggested_text: String, |
359 | } | 390 | } |
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs index eaeb6899f..6773ddea3 100644 --- a/crates/hir_ty/src/diagnostics/decl_check.rs +++ b/crates/hir_ty/src/diagnostics/decl_check.rs | |||
@@ -23,6 +23,7 @@ use hir_expand::{ | |||
23 | diagnostics::DiagnosticSink, | 23 | diagnostics::DiagnosticSink, |
24 | name::{AsName, Name}, | 24 | name::{AsName, Name}, |
25 | }; | 25 | }; |
26 | use stdx::{always, never}; | ||
26 | use syntax::{ | 27 | use syntax::{ |
27 | ast::{self, NameOwner}, | 28 | ast::{self, NameOwner}, |
28 | AstNode, AstPtr, | 29 | AstNode, AstPtr, |
@@ -31,7 +32,7 @@ use test_utils::mark; | |||
31 | 32 | ||
32 | use crate::{ | 33 | use crate::{ |
33 | db::HirDatabase, | 34 | db::HirDatabase, |
34 | diagnostics::{decl_check::case_conv::*, CaseType, IncorrectCase}, | 35 | diagnostics::{decl_check::case_conv::*, CaseType, IdentType, IncorrectCase}, |
35 | }; | 36 | }; |
36 | 37 | ||
37 | mod allow { | 38 | mod allow { |
@@ -40,7 +41,7 @@ mod allow { | |||
40 | pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types"; | 41 | pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types"; |
41 | } | 42 | } |
42 | 43 | ||
43 | pub(super) struct DeclValidator<'a, 'b: 'a> { | 44 | pub(super) struct DeclValidator<'a, 'b> { |
44 | db: &'a dyn HirDatabase, | 45 | db: &'a dyn HirDatabase, |
45 | krate: CrateId, | 46 | krate: CrateId, |
46 | sink: &'a mut DiagnosticSink<'b>, | 47 | sink: &'a mut DiagnosticSink<'b>, |
@@ -77,7 +78,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
77 | AdtId::StructId(struct_id) => self.validate_struct(struct_id), | 78 | AdtId::StructId(struct_id) => self.validate_struct(struct_id), |
78 | AdtId::EnumId(enum_id) => self.validate_enum(enum_id), | 79 | AdtId::EnumId(enum_id) => self.validate_enum(enum_id), |
79 | AdtId::UnionId(_) => { | 80 | AdtId::UnionId(_) => { |
80 | // Unions aren't yet supported by this validator. | 81 | // FIXME: Unions aren't yet supported by this validator. |
81 | } | 82 | } |
82 | } | 83 | } |
83 | } | 84 | } |
@@ -111,63 +112,50 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
111 | 112 | ||
112 | // Check the function name. | 113 | // Check the function name. |
113 | let function_name = data.name.to_string(); | 114 | let function_name = data.name.to_string(); |
114 | let fn_name_replacement = if let Some(new_name) = to_lower_snake_case(&function_name) { | 115 | let fn_name_replacement = to_lower_snake_case(&function_name).map(|new_name| Replacement { |
115 | let replacement = Replacement { | 116 | current_name: data.name.clone(), |
116 | current_name: data.name.clone(), | 117 | suggested_text: new_name, |
117 | suggested_text: new_name, | 118 | expected_case: CaseType::LowerSnakeCase, |
118 | expected_case: CaseType::LowerSnakeCase, | 119 | }); |
119 | }; | ||
120 | Some(replacement) | ||
121 | } else { | ||
122 | None | ||
123 | }; | ||
124 | 120 | ||
125 | // Check the param names. | 121 | // Check the param names. |
126 | let mut fn_param_replacements = Vec::new(); | 122 | let fn_param_replacements = body |
127 | 123 | .params | |
128 | for pat_id in body.params.iter().cloned() { | 124 | .iter() |
129 | let pat = &body[pat_id]; | 125 | .filter_map(|&id| match &body[id] { |
130 | 126 | Pat::Bind { name, .. } => Some(name), | |
131 | let param_name = match pat { | 127 | _ => None, |
132 | Pat::Bind { name, .. } => name, | 128 | }) |
133 | _ => continue, | 129 | .filter_map(|param_name| { |
134 | }; | 130 | Some(Replacement { |
135 | |||
136 | let name = param_name.to_string(); | ||
137 | if let Some(new_name) = to_lower_snake_case(&name) { | ||
138 | let replacement = Replacement { | ||
139 | current_name: param_name.clone(), | 131 | current_name: param_name.clone(), |
140 | suggested_text: new_name, | 132 | suggested_text: to_lower_snake_case(¶m_name.to_string())?, |
141 | expected_case: CaseType::LowerSnakeCase, | 133 | expected_case: CaseType::LowerSnakeCase, |
142 | }; | 134 | }) |
143 | fn_param_replacements.push(replacement); | 135 | }) |
144 | } | 136 | .collect(); |
145 | } | ||
146 | 137 | ||
147 | // Check the patterns inside the function body. | 138 | // Check the patterns inside the function body. |
148 | let mut pats_replacements = Vec::new(); | 139 | let pats_replacements = body |
149 | 140 | .pats | |
150 | for (pat_idx, pat) in body.pats.iter() { | 141 | .iter() |
151 | if body.params.contains(&pat_idx) { | 142 | // We aren't interested in function parameters, we've processed them above. |
152 | // We aren't interested in function parameters, we've processed them above. | 143 | .filter(|(pat_idx, _)| !body.params.contains(&pat_idx)) |
153 | continue; | 144 | .filter_map(|(id, pat)| match pat { |
154 | } | 145 | Pat::Bind { name, .. } => Some((id, name)), |
155 | 146 | _ => None, | |
156 | let bind_name = match pat { | 147 | }) |
157 | Pat::Bind { name, .. } => name, | 148 | .filter_map(|(id, bind_name)| { |
158 | _ => continue, | 149 | Some(( |
159 | }; | 150 | id, |
160 | 151 | Replacement { | |
161 | let name = bind_name.to_string(); | 152 | current_name: bind_name.clone(), |
162 | if let Some(new_name) = to_lower_snake_case(&name) { | 153 | suggested_text: to_lower_snake_case(&bind_name.to_string())?, |
163 | let replacement = Replacement { | 154 | expected_case: CaseType::LowerSnakeCase, |
164 | current_name: bind_name.clone(), | 155 | }, |
165 | suggested_text: new_name, | 156 | )) |
166 | expected_case: CaseType::LowerSnakeCase, | 157 | }) |
167 | }; | 158 | .collect(); |
168 | pats_replacements.push((pat_idx, replacement)); | ||
169 | } | ||
170 | } | ||
171 | 159 | ||
172 | // If there is at least one element to spawn a warning on, go to the source map and generate a warning. | 160 | // If there is at least one element to spawn a warning on, go to the source map and generate a warning. |
173 | self.create_incorrect_case_diagnostic_for_func( | 161 | self.create_incorrect_case_diagnostic_for_func( |
@@ -199,8 +187,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
199 | let ast_ptr = match fn_src.value.name() { | 187 | let ast_ptr = match fn_src.value.name() { |
200 | Some(name) => name, | 188 | Some(name) => name, |
201 | None => { | 189 | None => { |
202 | // We don't want rust-analyzer to panic over this, but it is definitely some kind of error in the logic. | 190 | never!( |
203 | log::error!( | ||
204 | "Replacement ({:?}) was generated for a function without a name: {:?}", | 191 | "Replacement ({:?}) was generated for a function without a name: {:?}", |
205 | replacement, | 192 | replacement, |
206 | fn_src | 193 | fn_src |
@@ -211,7 +198,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
211 | 198 | ||
212 | let diagnostic = IncorrectCase { | 199 | let diagnostic = IncorrectCase { |
213 | file: fn_src.file_id, | 200 | file: fn_src.file_id, |
214 | ident_type: "Function".to_string(), | 201 | ident_type: IdentType::Function, |
215 | ident: AstPtr::new(&ast_ptr).into(), | 202 | ident: AstPtr::new(&ast_ptr).into(), |
216 | expected_case: replacement.expected_case, | 203 | expected_case: replacement.expected_case, |
217 | ident_text: replacement.current_name.to_string(), | 204 | ident_text: replacement.current_name.to_string(), |
@@ -225,12 +212,12 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
225 | let fn_params_list = match fn_src.value.param_list() { | 212 | let fn_params_list = match fn_src.value.param_list() { |
226 | Some(params) => params, | 213 | Some(params) => params, |
227 | None => { | 214 | None => { |
228 | if !fn_param_replacements.is_empty() { | 215 | always!( |
229 | log::error!( | 216 | fn_param_replacements.is_empty(), |
230 | "Replacements ({:?}) were generated for a function parameters which had no parameters list: {:?}", | 217 | "Replacements ({:?}) were generated for a function parameters which had no parameters list: {:?}", |
231 | fn_param_replacements, fn_src | 218 | fn_param_replacements, |
232 | ); | 219 | fn_src |
233 | } | 220 | ); |
234 | return; | 221 | return; |
235 | } | 222 | } |
236 | }; | 223 | }; |
@@ -240,23 +227,25 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
240 | // actual params list, but just some of them (ones that named correctly) are skipped. | 227 | // actual params list, but just some of them (ones that named correctly) are skipped. |
241 | let ast_ptr: ast::Name = loop { | 228 | let ast_ptr: ast::Name = loop { |
242 | match fn_params_iter.next() { | 229 | match fn_params_iter.next() { |
243 | Some(element) | 230 | Some(element) => { |
244 | if pat_equals_to_name(element.pat(), ¶m_to_rename.current_name) => | 231 | if let Some(ast::Pat::IdentPat(pat)) = element.pat() { |
245 | { | 232 | if pat.to_string() == param_to_rename.current_name.to_string() { |
246 | if let ast::Pat::IdentPat(pat) = element.pat().unwrap() { | 233 | if let Some(name) = pat.name() { |
247 | break pat.name().unwrap(); | 234 | break name; |
248 | } else { | 235 | } |
249 | // This is critical. If we consider this parameter the expected one, | 236 | // This is critical. If we consider this parameter the expected one, |
250 | // it **must** have a name. | 237 | // it **must** have a name. |
251 | panic!( | 238 | never!( |
252 | "Pattern {:?} equals to expected replacement {:?}, but has no name", | 239 | "Pattern {:?} equals to expected replacement {:?}, but has no name", |
253 | element, param_to_rename | 240 | element, |
254 | ); | 241 | param_to_rename |
242 | ); | ||
243 | return; | ||
244 | } | ||
255 | } | 245 | } |
256 | } | 246 | } |
257 | Some(_) => {} | ||
258 | None => { | 247 | None => { |
259 | log::error!( | 248 | never!( |
260 | "Replacement ({:?}) was generated for a function parameter which was not found: {:?}", | 249 | "Replacement ({:?}) was generated for a function parameter which was not found: {:?}", |
261 | param_to_rename, fn_src | 250 | param_to_rename, fn_src |
262 | ); | 251 | ); |
@@ -267,7 +256,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
267 | 256 | ||
268 | let diagnostic = IncorrectCase { | 257 | let diagnostic = IncorrectCase { |
269 | file: fn_src.file_id, | 258 | file: fn_src.file_id, |
270 | ident_type: "Argument".to_string(), | 259 | ident_type: IdentType::Argument, |
271 | ident: AstPtr::new(&ast_ptr).into(), | 260 | ident: AstPtr::new(&ast_ptr).into(), |
272 | expected_case: param_to_rename.expected_case, | 261 | expected_case: param_to_rename.expected_case, |
273 | ident_text: param_to_rename.current_name.to_string(), | 262 | ident_text: param_to_rename.current_name.to_string(), |
@@ -309,8 +298,8 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
309 | // We have to check that it's either `let var = ...` or `var @ Variant(_)` statement, | 298 | // We have to check that it's either `let var = ...` or `var @ Variant(_)` statement, |
310 | // because e.g. match arms are patterns as well. | 299 | // because e.g. match arms are patterns as well. |
311 | // In other words, we check that it's a named variable binding. | 300 | // In other words, we check that it's a named variable binding. |
312 | let is_binding = ast::LetStmt::cast(parent.clone()).is_some() | 301 | let is_binding = ast::LetStmt::can_cast(parent.kind()) |
313 | || (ast::MatchArm::cast(parent).is_some() | 302 | || (ast::MatchArm::can_cast(parent.kind()) |
314 | && ident_pat.at_token().is_some()); | 303 | && ident_pat.at_token().is_some()); |
315 | if !is_binding { | 304 | if !is_binding { |
316 | // This pattern is not an actual variable declaration, e.g. `Some(val) => {..}` match arm. | 305 | // This pattern is not an actual variable declaration, e.g. `Some(val) => {..}` match arm. |
@@ -319,7 +308,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
319 | 308 | ||
320 | let diagnostic = IncorrectCase { | 309 | let diagnostic = IncorrectCase { |
321 | file: source_ptr.file_id, | 310 | file: source_ptr.file_id, |
322 | ident_type: "Variable".to_string(), | 311 | ident_type: IdentType::Variable, |
323 | ident: AstPtr::new(&name_ast).into(), | 312 | ident: AstPtr::new(&name_ast).into(), |
324 | expected_case: replacement.expected_case, | 313 | expected_case: replacement.expected_case, |
325 | ident_text: replacement.current_name.to_string(), | 314 | ident_text: replacement.current_name.to_string(), |
@@ -341,17 +330,12 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
341 | 330 | ||
342 | // Check the structure name. | 331 | // Check the structure name. |
343 | let struct_name = data.name.to_string(); | 332 | let struct_name = data.name.to_string(); |
344 | let struct_name_replacement = if let Some(new_name) = to_camel_case(&struct_name) { | 333 | let struct_name_replacement = if !non_camel_case_allowed { |
345 | let replacement = Replacement { | 334 | to_camel_case(&struct_name).map(|new_name| Replacement { |
346 | current_name: data.name.clone(), | 335 | current_name: data.name.clone(), |
347 | suggested_text: new_name, | 336 | suggested_text: new_name, |
348 | expected_case: CaseType::UpperCamelCase, | 337 | expected_case: CaseType::UpperCamelCase, |
349 | }; | 338 | }) |
350 | if non_camel_case_allowed { | ||
351 | None | ||
352 | } else { | ||
353 | Some(replacement) | ||
354 | } | ||
355 | } else { | 339 | } else { |
356 | None | 340 | None |
357 | }; | 341 | }; |
@@ -403,8 +387,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
403 | let ast_ptr = match struct_src.value.name() { | 387 | let ast_ptr = match struct_src.value.name() { |
404 | Some(name) => name, | 388 | Some(name) => name, |
405 | None => { | 389 | None => { |
406 | // We don't want rust-analyzer to panic over this, but it is definitely some kind of error in the logic. | 390 | never!( |
407 | log::error!( | ||
408 | "Replacement ({:?}) was generated for a structure without a name: {:?}", | 391 | "Replacement ({:?}) was generated for a structure without a name: {:?}", |
409 | replacement, | 392 | replacement, |
410 | struct_src | 393 | struct_src |
@@ -415,7 +398,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
415 | 398 | ||
416 | let diagnostic = IncorrectCase { | 399 | let diagnostic = IncorrectCase { |
417 | file: struct_src.file_id, | 400 | file: struct_src.file_id, |
418 | ident_type: "Structure".to_string(), | 401 | ident_type: IdentType::Structure, |
419 | ident: AstPtr::new(&ast_ptr).into(), | 402 | ident: AstPtr::new(&ast_ptr).into(), |
420 | expected_case: replacement.expected_case, | 403 | expected_case: replacement.expected_case, |
421 | ident_text: replacement.current_name.to_string(), | 404 | ident_text: replacement.current_name.to_string(), |
@@ -428,12 +411,12 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
428 | let struct_fields_list = match struct_src.value.field_list() { | 411 | let struct_fields_list = match struct_src.value.field_list() { |
429 | Some(ast::FieldList::RecordFieldList(fields)) => fields, | 412 | Some(ast::FieldList::RecordFieldList(fields)) => fields, |
430 | _ => { | 413 | _ => { |
431 | if !struct_fields_replacements.is_empty() { | 414 | always!( |
432 | log::error!( | 415 | struct_fields_replacements.is_empty(), |
433 | "Replacements ({:?}) were generated for a structure fields which had no fields list: {:?}", | 416 | "Replacements ({:?}) were generated for a structure fields which had no fields list: {:?}", |
434 | struct_fields_replacements, struct_src | 417 | struct_fields_replacements, |
435 | ); | 418 | struct_src |
436 | } | 419 | ); |
437 | return; | 420 | return; |
438 | } | 421 | } |
439 | }; | 422 | }; |
@@ -442,13 +425,14 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
442 | // We assume that parameters in replacement are in the same order as in the | 425 | // We assume that parameters in replacement are in the same order as in the |
443 | // actual params list, but just some of them (ones that named correctly) are skipped. | 426 | // actual params list, but just some of them (ones that named correctly) are skipped. |
444 | let ast_ptr = loop { | 427 | let ast_ptr = loop { |
445 | match struct_fields_iter.next() { | 428 | match struct_fields_iter.next().and_then(|field| field.name()) { |
446 | Some(element) if names_equal(element.name(), &field_to_rename.current_name) => { | 429 | Some(field_name) => { |
447 | break element.name().unwrap() | 430 | if field_name.as_name() == field_to_rename.current_name { |
431 | break field_name; | ||
432 | } | ||
448 | } | 433 | } |
449 | Some(_) => {} | ||
450 | None => { | 434 | None => { |
451 | log::error!( | 435 | never!( |
452 | "Replacement ({:?}) was generated for a structure field which was not found: {:?}", | 436 | "Replacement ({:?}) was generated for a structure field which was not found: {:?}", |
453 | field_to_rename, struct_src | 437 | field_to_rename, struct_src |
454 | ); | 438 | ); |
@@ -459,7 +443,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
459 | 443 | ||
460 | let diagnostic = IncorrectCase { | 444 | let diagnostic = IncorrectCase { |
461 | file: struct_src.file_id, | 445 | file: struct_src.file_id, |
462 | ident_type: "Field".to_string(), | 446 | ident_type: IdentType::Field, |
463 | ident: AstPtr::new(&ast_ptr).into(), | 447 | ident: AstPtr::new(&ast_ptr).into(), |
464 | expected_case: field_to_rename.expected_case, | 448 | expected_case: field_to_rename.expected_case, |
465 | ident_text: field_to_rename.current_name.to_string(), | 449 | ident_text: field_to_rename.current_name.to_string(), |
@@ -480,31 +464,24 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
480 | 464 | ||
481 | // Check the enum name. | 465 | // Check the enum name. |
482 | let enum_name = data.name.to_string(); | 466 | let enum_name = data.name.to_string(); |
483 | let enum_name_replacement = if let Some(new_name) = to_camel_case(&enum_name) { | 467 | let enum_name_replacement = to_camel_case(&enum_name).map(|new_name| Replacement { |
484 | let replacement = Replacement { | 468 | current_name: data.name.clone(), |
485 | current_name: data.name.clone(), | 469 | suggested_text: new_name, |
486 | suggested_text: new_name, | 470 | expected_case: CaseType::UpperCamelCase, |
487 | expected_case: CaseType::UpperCamelCase, | 471 | }); |
488 | }; | ||
489 | Some(replacement) | ||
490 | } else { | ||
491 | None | ||
492 | }; | ||
493 | 472 | ||
494 | // Check the field names. | 473 | // Check the field names. |
495 | let mut enum_fields_replacements = Vec::new(); | 474 | let enum_fields_replacements = data |
496 | 475 | .variants | |
497 | for (_, variant) in data.variants.iter() { | 476 | .iter() |
498 | let variant_name = variant.name.to_string(); | 477 | .filter_map(|(_, variant)| { |
499 | if let Some(new_name) = to_camel_case(&variant_name) { | 478 | Some(Replacement { |
500 | let replacement = Replacement { | ||
501 | current_name: variant.name.clone(), | 479 | current_name: variant.name.clone(), |
502 | suggested_text: new_name, | 480 | suggested_text: to_camel_case(&variant.name.to_string())?, |
503 | expected_case: CaseType::UpperCamelCase, | 481 | expected_case: CaseType::UpperCamelCase, |
504 | }; | 482 | }) |
505 | enum_fields_replacements.push(replacement); | 483 | }) |
506 | } | 484 | .collect(); |
507 | } | ||
508 | 485 | ||
509 | // If there is at least one element to spawn a warning on, go to the source map and generate a warning. | 486 | // If there is at least one element to spawn a warning on, go to the source map and generate a warning. |
510 | self.create_incorrect_case_diagnostic_for_enum( | 487 | self.create_incorrect_case_diagnostic_for_enum( |
@@ -534,8 +511,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
534 | let ast_ptr = match enum_src.value.name() { | 511 | let ast_ptr = match enum_src.value.name() { |
535 | Some(name) => name, | 512 | Some(name) => name, |
536 | None => { | 513 | None => { |
537 | // We don't want rust-analyzer to panic over this, but it is definitely some kind of error in the logic. | 514 | never!( |
538 | log::error!( | ||
539 | "Replacement ({:?}) was generated for a enum without a name: {:?}", | 515 | "Replacement ({:?}) was generated for a enum without a name: {:?}", |
540 | replacement, | 516 | replacement, |
541 | enum_src | 517 | enum_src |
@@ -546,7 +522,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
546 | 522 | ||
547 | let diagnostic = IncorrectCase { | 523 | let diagnostic = IncorrectCase { |
548 | file: enum_src.file_id, | 524 | file: enum_src.file_id, |
549 | ident_type: "Enum".to_string(), | 525 | ident_type: IdentType::Enum, |
550 | ident: AstPtr::new(&ast_ptr).into(), | 526 | ident: AstPtr::new(&ast_ptr).into(), |
551 | expected_case: replacement.expected_case, | 527 | expected_case: replacement.expected_case, |
552 | ident_text: replacement.current_name.to_string(), | 528 | ident_text: replacement.current_name.to_string(), |
@@ -559,12 +535,12 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
559 | let enum_variants_list = match enum_src.value.variant_list() { | 535 | let enum_variants_list = match enum_src.value.variant_list() { |
560 | Some(variants) => variants, | 536 | Some(variants) => variants, |
561 | _ => { | 537 | _ => { |
562 | if !enum_variants_replacements.is_empty() { | 538 | always!( |
563 | log::error!( | 539 | enum_variants_replacements.is_empty(), |
564 | "Replacements ({:?}) were generated for a enum variants which had no fields list: {:?}", | 540 | "Replacements ({:?}) were generated for a enum variants which had no fields list: {:?}", |
565 | enum_variants_replacements, enum_src | 541 | enum_variants_replacements, |
566 | ); | 542 | enum_src |
567 | } | 543 | ); |
568 | return; | 544 | return; |
569 | } | 545 | } |
570 | }; | 546 | }; |
@@ -573,15 +549,14 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
573 | // We assume that parameters in replacement are in the same order as in the | 549 | // We assume that parameters in replacement are in the same order as in the |
574 | // actual params list, but just some of them (ones that named correctly) are skipped. | 550 | // actual params list, but just some of them (ones that named correctly) are skipped. |
575 | let ast_ptr = loop { | 551 | let ast_ptr = loop { |
576 | match enum_variants_iter.next() { | 552 | match enum_variants_iter.next().and_then(|v| v.name()) { |
577 | Some(variant) | 553 | Some(variant_name) => { |
578 | if names_equal(variant.name(), &variant_to_rename.current_name) => | 554 | if variant_name.as_name() == variant_to_rename.current_name { |
579 | { | 555 | break variant_name; |
580 | break variant.name().unwrap() | 556 | } |
581 | } | 557 | } |
582 | Some(_) => {} | ||
583 | None => { | 558 | None => { |
584 | log::error!( | 559 | never!( |
585 | "Replacement ({:?}) was generated for a enum variant which was not found: {:?}", | 560 | "Replacement ({:?}) was generated for a enum variant which was not found: {:?}", |
586 | variant_to_rename, enum_src | 561 | variant_to_rename, enum_src |
587 | ); | 562 | ); |
@@ -592,7 +567,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
592 | 567 | ||
593 | let diagnostic = IncorrectCase { | 568 | let diagnostic = IncorrectCase { |
594 | file: enum_src.file_id, | 569 | file: enum_src.file_id, |
595 | ident_type: "Variant".to_string(), | 570 | ident_type: IdentType::Variant, |
596 | ident: AstPtr::new(&ast_ptr).into(), | 571 | ident: AstPtr::new(&ast_ptr).into(), |
597 | expected_case: variant_to_rename.expected_case, | 572 | expected_case: variant_to_rename.expected_case, |
598 | ident_text: variant_to_rename.current_name.to_string(), | 573 | ident_text: variant_to_rename.current_name.to_string(), |
@@ -637,7 +612,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
637 | 612 | ||
638 | let diagnostic = IncorrectCase { | 613 | let diagnostic = IncorrectCase { |
639 | file: const_src.file_id, | 614 | file: const_src.file_id, |
640 | ident_type: "Constant".to_string(), | 615 | ident_type: IdentType::Constant, |
641 | ident: AstPtr::new(&ast_ptr).into(), | 616 | ident: AstPtr::new(&ast_ptr).into(), |
642 | expected_case: replacement.expected_case, | 617 | expected_case: replacement.expected_case, |
643 | ident_text: replacement.current_name.to_string(), | 618 | ident_text: replacement.current_name.to_string(), |
@@ -685,7 +660,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
685 | 660 | ||
686 | let diagnostic = IncorrectCase { | 661 | let diagnostic = IncorrectCase { |
687 | file: static_src.file_id, | 662 | file: static_src.file_id, |
688 | ident_type: "Static variable".to_string(), | 663 | ident_type: IdentType::StaticVariable, |
689 | ident: AstPtr::new(&ast_ptr).into(), | 664 | ident: AstPtr::new(&ast_ptr).into(), |
690 | expected_case: replacement.expected_case, | 665 | expected_case: replacement.expected_case, |
691 | ident_text: replacement.current_name.to_string(), | 666 | ident_text: replacement.current_name.to_string(), |
@@ -696,22 +671,6 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
696 | } | 671 | } |
697 | } | 672 | } |
698 | 673 | ||
699 | fn names_equal(left: Option<ast::Name>, right: &Name) -> bool { | ||
700 | if let Some(left) = left { | ||
701 | &left.as_name() == right | ||
702 | } else { | ||
703 | false | ||
704 | } | ||
705 | } | ||
706 | |||
707 | fn pat_equals_to_name(pat: Option<ast::Pat>, name: &Name) -> bool { | ||
708 | if let Some(ast::Pat::IdentPat(ident)) = pat { | ||
709 | ident.to_string() == name.to_string() | ||
710 | } else { | ||
711 | false | ||
712 | } | ||
713 | } | ||
714 | |||
715 | #[cfg(test)] | 674 | #[cfg(test)] |
716 | mod tests { | 675 | mod tests { |
717 | use test_utils::mark; | 676 | use test_utils::mark; |
diff --git a/crates/stdx/Cargo.toml b/crates/stdx/Cargo.toml index 5866c0a28..d28b5e658 100644 --- a/crates/stdx/Cargo.toml +++ b/crates/stdx/Cargo.toml | |||
@@ -11,7 +11,7 @@ doctest = false | |||
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | backtrace = { version = "0.3.44", optional = true } | 13 | backtrace = { version = "0.3.44", optional = true } |
14 | always-assert = { version = "0.1.1", features = ["log"] } | 14 | always-assert = { version = "0.1.2", features = ["log"] } |
15 | # Think twice before adding anything here | 15 | # Think twice before adding anything here |
16 | 16 | ||
17 | [features] | 17 | [features] |