Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-diagnostics/src/handlers/missing_fields.rs')
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/missing_fields.rs | 57 |
1 files changed, 52 insertions, 5 deletions
diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs index 050d5477f6..85368cc09f 100644 --- a/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -1,6 +1,6 @@ use either::Either; use hir::{ - AssocItem, FindPathConfig, HirDisplay, InFile, Type, + AssocItem, FindPathConfig, HasVisibility, HirDisplay, InFile, Type, db::{ExpandDatabase, HirDatabase}, sym, }; @@ -35,7 +35,7 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, fix}; // ``` pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic { let mut message = String::from("missing structure fields:\n"); - for field in &d.missed_fields { + for (field, _) in &d.missed_fields { format_to!(message, "- {}\n", field.display(ctx.sema.db, ctx.edition)); } @@ -57,7 +57,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass // `struct A(usize);` // `let a = A { 0: () }` // but it is uncommon usage and it should not be encouraged. - if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) { + if d.missed_fields.iter().any(|(name, _)| name.as_tuple_index().is_some()) { return None; } @@ -68,6 +68,12 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass let range = InFile::new(d.file, d.field_list_parent.text_range()) .original_node_file_range_rooted_opt(ctx.sema.db)?; + if let Some(current_module) = current_module + && d.missed_fields.iter().any(|(_, field)| !field.is_visible_from(ctx.db(), current_module)) + { + return None; + } + let build_text_edit = |new_syntax: &SyntaxNode, old_syntax| { let edit = { let old_range = ctx.sema.original_range_opt(old_syntax)?; @@ -120,7 +126,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass let field_expr = if let Some(local_candidate) = locals.get(&f.name(ctx.sema.db)) { cov_mark::hit!(field_shorthand); let candidate_ty = local_candidate.ty(ctx.sema.db); - if ty.could_unify_with(ctx.sema.db, &candidate_ty) { + if candidate_ty.could_coerce_to(ctx.sema.db, ty) { None } else { Some(generate_fill_expr(ty)) @@ -254,7 +260,7 @@ fn get_default_constructor( #[cfg(test)] mod tests { - use crate::tests::{check_diagnostics, check_fix}; + use crate::tests::{check_diagnostics, check_fix, check_no_fix}; #[test] fn missing_record_pat_field_diagnostic() { @@ -934,4 +940,45 @@ fn main() { "#, ); } + + #[test] + fn coerce_existing_local() { + check_fix( + r#" +struct A { + v: f64, +} + +fn f() -> A { + let v = loop {}; + A {$0} +} + "#, + r#" +struct A { + v: f64, +} + +fn f() -> A { + let v = loop {}; + A { v } +} + "#, + ); + } + + #[test] + fn inaccessible_fields() { + check_no_fix( + r#" +mod foo { + pub struct Bar { baz: i32 } +} + +fn qux() { + foo::Bar {$0}; +} + "#, + ); + } } |