aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock4
-rw-r--r--crates/assists/src/handlers/generate_enum_match_method.rs10
-rw-r--r--crates/assists/src/tests/generated.rs1
-rw-r--r--crates/hir_ty/src/diagnostics.rs33
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs279
-rw-r--r--crates/stdx/Cargo.toml2
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]]
19name = "always-assert" 19name = "always-assert"
20version = "0.1.1" 20version = "0.1.2"
21source = "registry+https://github.com/rust-lang/crates.io-index" 21source = "registry+https://github.com/rust-lang/crates.io-index"
22checksum = "727786f78c5bc0cda8011831616589f72084cb16b7df4213a997b78749b55a60" 22checksum = "fbf688625d06217d5b1bb0ea9d9c44a1635fd0ee3534466388d18203174f4d11"
23dependencies = [ 23dependencies = [
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
135impl Variant { 140impl 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 {
180enum Variant { Undefined } 186enum Variant { Undefined }
181 187
182impl Variant { 188impl 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
206impl Variant { 213impl 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
480impl Version { 480impl 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)]
349pub enum IdentType {
350 Argument,
351 Constant,
352 Enum,
353 Field,
354 Function,
355 StaticVariable,
356 Structure,
357 Variable,
358 Variant,
359}
360
361impl 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};
26use stdx::{always, never};
26use syntax::{ 27use 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
32use crate::{ 33use 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
37mod allow { 38mod 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
43pub(super) struct DeclValidator<'a, 'b: 'a> { 44pub(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(&param_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(), &param_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
699fn 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
707fn 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)]
716mod tests { 675mod 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]
13backtrace = { version = "0.3.44", optional = true } 13backtrace = { version = "0.3.44", optional = true }
14always-assert = { version = "0.1.1", features = ["log"] } 14always-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]