aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/diagnostics/decl_check.rs
diff options
context:
space:
mode:
authorIgor Aleksanov <[email protected]>2020-10-03 16:01:25 +0100
committerIgor Aleksanov <[email protected]>2020-10-12 09:05:00 +0100
commitfb96bba87895c062a78e6599cea161e461ff607d (patch)
tree17a4970bc13ccf9074cc1c8a60e8bf4e2d73c475 /crates/hir_ty/src/diagnostics/decl_check.rs
parente24e22f288eba33928a9e579f13653d6f04fcdfa (diff)
Add diagnostics for enum names and variants
Diffstat (limited to 'crates/hir_ty/src/diagnostics/decl_check.rs')
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs147
1 files changed, 146 insertions, 1 deletions
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index 260aa9607..7fc9c564e 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -315,7 +315,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
315 Some(_) => {} 315 Some(_) => {}
316 None => { 316 None => {
317 log::error!( 317 log::error!(
318 "Replacement ({:?}) was generated for a function parameter which was not found: {:?}", 318 "Replacement ({:?}) was generated for a structure field which was not found: {:?}",
319 field_to_rename, struct_src 319 field_to_rename, struct_src
320 ); 320 );
321 return; 321 return;
@@ -338,6 +338,131 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
338 338
339 fn validate_enum(&mut self, db: &dyn HirDatabase, enum_id: EnumId) { 339 fn validate_enum(&mut self, db: &dyn HirDatabase, enum_id: EnumId) {
340 let data = db.enum_data(enum_id); 340 let data = db.enum_data(enum_id);
341
342 // 1. Check the enum name.
343 let enum_name = data.name.to_string();
344 let enum_name_replacement = if let Some(new_name) = to_camel_case(&enum_name) {
345 let replacement = Replacement {
346 current_name: data.name.clone(),
347 suggested_text: new_name,
348 expected_case: CaseType::UpperCamelCase,
349 };
350 Some(replacement)
351 } else {
352 None
353 };
354
355 // 2. Check the field names.
356 let mut enum_fields_replacements = Vec::new();
357
358 for (_, variant) in data.variants.iter() {
359 let variant_name = variant.name.to_string();
360 if let Some(new_name) = to_camel_case(&variant_name) {
361 let replacement = Replacement {
362 current_name: variant.name.clone(),
363 suggested_text: new_name,
364 expected_case: CaseType::UpperCamelCase,
365 };
366 enum_fields_replacements.push(replacement);
367 }
368 }
369
370 // 3. If there is at least one element to spawn a warning on, go to the source map and generate a warning.
371 self.create_incorrect_case_diagnostic_for_enum(
372 enum_id,
373 db,
374 enum_name_replacement,
375 enum_fields_replacements,
376 )
377 }
378
379 /// Given the information about incorrect names in the struct declaration, looks up into the source code
380 /// for exact locations and adds diagnostics into the sink.
381 fn create_incorrect_case_diagnostic_for_enum(
382 &mut self,
383 enum_id: EnumId,
384 db: &dyn HirDatabase,
385 enum_name_replacement: Option<Replacement>,
386 enum_variants_replacements: Vec<Replacement>,
387 ) {
388 // XXX: only look at sources if we do have incorrect names
389 if enum_name_replacement.is_none() && enum_variants_replacements.is_empty() {
390 return;
391 }
392
393 let enum_loc = enum_id.lookup(db.upcast());
394 let enum_src = enum_loc.source(db.upcast());
395
396 if let Some(replacement) = enum_name_replacement {
397 let ast_ptr = if let Some(name) = enum_src.value.name() {
398 name
399 } else {
400 // We don't want rust-analyzer to panic over this, but it is definitely some kind of error in the logic.
401 log::error!(
402 "Replacement ({:?}) was generated for a enum without a name: {:?}",
403 replacement,
404 enum_src
405 );
406 return;
407 };
408
409 let diagnostic = IncorrectCase {
410 file: enum_src.file_id,
411 ident_type: "Enum".to_string(),
412 ident: AstPtr::new(&ast_ptr).into(),
413 expected_case: replacement.expected_case,
414 ident_text: replacement.current_name.to_string(),
415 suggested_text: replacement.suggested_text,
416 };
417
418 self.sink.push(diagnostic);
419 }
420
421 let enum_variants_list = match enum_src.value.variant_list() {
422 Some(variants) => variants,
423 _ => {
424 if !enum_variants_replacements.is_empty() {
425 log::error!(
426 "Replacements ({:?}) were generated for a enum variants which had no fields list: {:?}",
427 enum_variants_replacements, enum_src
428 );
429 }
430 return;
431 }
432 };
433 let mut enum_variants_iter = enum_variants_list.variants();
434 for variant_to_rename in enum_variants_replacements {
435 // We assume that parameters in replacement are in the same order as in the
436 // actual params list, but just some of them (ones that named correctly) are skipped.
437 let ast_ptr = loop {
438 match enum_variants_iter.next() {
439 Some(variant)
440 if names_equal(variant.name(), &variant_to_rename.current_name) =>
441 {
442 break variant.name().unwrap()
443 }
444 Some(_) => {}
445 None => {
446 log::error!(
447 "Replacement ({:?}) was generated for a enum variant which was not found: {:?}",
448 variant_to_rename, enum_src
449 );
450 return;
451 }
452 }
453 };
454
455 let diagnostic = IncorrectCase {
456 file: enum_src.file_id,
457 ident_type: "Variant".to_string(),
458 ident: AstPtr::new(&ast_ptr).into(),
459 expected_case: variant_to_rename.expected_case,
460 ident_text: variant_to_rename.current_name.to_string(),
461 suggested_text: variant_to_rename.suggested_text,
462 };
463
464 self.sink.push(diagnostic);
465 }
341 } 466 }
342} 467}
343 468
@@ -403,4 +528,24 @@ struct SomeStruct { SomeField: u8 }
403"#, 528"#,
404 ); 529 );
405 } 530 }
531
532 #[test]
533 fn incorrect_enum_name() {
534 check_diagnostics(
535 r#"
536enum some_enum { Val(u8) }
537 // ^^^^^^^^^ Enum `some_enum` should have a CamelCase name, e.g. `SomeEnum`
538"#,
539 );
540 }
541
542 #[test]
543 fn incorrect_enum_variant_name() {
544 check_diagnostics(
545 r#"
546enum SomeEnum { SOME_VARIANT(u8) }
547 // ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have a CamelCase name, e.g. `SomeVariant`
548"#,
549 );
550 }
406} 551}