mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Correctly generate new struct field in file containing struct def
This commit is contained in:
parent
c1eed627d9
commit
43079ba80d
1 changed files with 55 additions and 3 deletions
|
@ -131,7 +131,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
|
||||||
|
|
||||||
fn missing_struct_field_fix(
|
fn missing_struct_field_fix(
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
file_id: FileId,
|
usage_file_id: FileId,
|
||||||
d: &hir::diagnostics::NoSuchField,
|
d: &hir::diagnostics::NoSuchField,
|
||||||
) -> Option<Fix> {
|
) -> Option<Fix> {
|
||||||
let record_expr = sema.ast(d);
|
let record_expr = sema.ast(d);
|
||||||
|
@ -139,25 +139,30 @@ fn missing_struct_field_fix(
|
||||||
let record_lit = ast::RecordLit::cast(record_expr.syntax().parent()?.parent()?)?;
|
let record_lit = ast::RecordLit::cast(record_expr.syntax().parent()?.parent()?)?;
|
||||||
let def_id = sema.resolve_variant(record_lit)?;
|
let def_id = sema.resolve_variant(record_lit)?;
|
||||||
let module;
|
let module;
|
||||||
|
let def_file_id;
|
||||||
let record_fields = match VariantDef::from(def_id) {
|
let record_fields = match VariantDef::from(def_id) {
|
||||||
VariantDef::Struct(s) => {
|
VariantDef::Struct(s) => {
|
||||||
module = s.module(sema.db);
|
module = s.module(sema.db);
|
||||||
let source = s.source(sema.db);
|
let source = s.source(sema.db);
|
||||||
|
def_file_id = source.file_id;
|
||||||
let fields = source.value.field_def_list()?;
|
let fields = source.value.field_def_list()?;
|
||||||
record_field_def_list(fields)?
|
record_field_def_list(fields)?
|
||||||
}
|
}
|
||||||
VariantDef::Union(u) => {
|
VariantDef::Union(u) => {
|
||||||
module = u.module(sema.db);
|
module = u.module(sema.db);
|
||||||
let source = u.source(sema.db);
|
let source = u.source(sema.db);
|
||||||
|
def_file_id = source.file_id;
|
||||||
source.value.record_field_def_list()?
|
source.value.record_field_def_list()?
|
||||||
}
|
}
|
||||||
VariantDef::EnumVariant(e) => {
|
VariantDef::EnumVariant(e) => {
|
||||||
module = e.module(sema.db);
|
module = e.module(sema.db);
|
||||||
let source = e.source(sema.db);
|
let source = e.source(sema.db);
|
||||||
|
def_file_id = source.file_id;
|
||||||
let fields = source.value.field_def_list()?;
|
let fields = source.value.field_def_list()?;
|
||||||
record_field_def_list(fields)?
|
record_field_def_list(fields)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let def_file_id = def_file_id.original_file(sema.db);
|
||||||
|
|
||||||
let new_field_type = sema.type_of_expr(&record_expr.expr()?)?;
|
let new_field_type = sema.type_of_expr(&record_expr.expr()?)?;
|
||||||
if new_field_type.is_unknown() {
|
if new_field_type.is_unknown() {
|
||||||
|
@ -172,7 +177,11 @@ fn missing_struct_field_fix(
|
||||||
let last_field_syntax = last_field.syntax();
|
let last_field_syntax = last_field.syntax();
|
||||||
let indent = IndentLevel::from_node(last_field_syntax);
|
let indent = IndentLevel::from_node(last_field_syntax);
|
||||||
|
|
||||||
let mut new_field = format!("\n{}{}", indent, new_field);
|
let mut new_field = new_field.to_string();
|
||||||
|
if usage_file_id != def_file_id {
|
||||||
|
new_field = format!("pub(crate) {}", new_field);
|
||||||
|
}
|
||||||
|
new_field = format!("\n{}{}", indent, new_field);
|
||||||
|
|
||||||
let needs_comma = !last_field_syntax.to_string().ends_with(",");
|
let needs_comma = !last_field_syntax.to_string().ends_with(",");
|
||||||
if needs_comma {
|
if needs_comma {
|
||||||
|
@ -180,7 +189,7 @@ fn missing_struct_field_fix(
|
||||||
}
|
}
|
||||||
|
|
||||||
let source_change = SourceFileEdit {
|
let source_change = SourceFileEdit {
|
||||||
file_id,
|
file_id: def_file_id,
|
||||||
edit: TextEdit::insert(last_field_syntax.text_range().end(), new_field),
|
edit: TextEdit::insert(last_field_syntax.text_range().end(), new_field),
|
||||||
};
|
};
|
||||||
let fix = Fix::new("Create field", source_change.into());
|
let fix = Fix::new("Create field", source_change.into());
|
||||||
|
@ -309,6 +318,25 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks that a diagnostic applies to the file containing the `<|>` cursor marker
|
||||||
|
/// which has a fix that can apply to other files.
|
||||||
|
fn check_apply_diagnostic_fix_in_other_file(ra_fixture_before: &str, ra_fixture_after: &str) {
|
||||||
|
let ra_fixture_after = &trim_indent(ra_fixture_after);
|
||||||
|
let (analysis, file_pos) = analysis_and_position(ra_fixture_before);
|
||||||
|
let current_file_id = file_pos.file_id;
|
||||||
|
let diagnostic = analysis.diagnostics(current_file_id).unwrap().pop().unwrap();
|
||||||
|
let mut fix = diagnostic.fix.unwrap();
|
||||||
|
let edit = fix.source_change.source_file_edits.pop().unwrap();
|
||||||
|
let changed_file_id = edit.file_id;
|
||||||
|
let before = analysis.file_text(changed_file_id).unwrap();
|
||||||
|
let actual = {
|
||||||
|
let mut actual = before.to_string();
|
||||||
|
edit.edit.apply(&mut actual);
|
||||||
|
actual
|
||||||
|
};
|
||||||
|
assert_eq_text!(ra_fixture_after, &actual);
|
||||||
|
}
|
||||||
|
|
||||||
/// Takes a multi-file input fixture with annotated cursor position and checks that no diagnostics
|
/// Takes a multi-file input fixture with annotated cursor position and checks that no diagnostics
|
||||||
/// apply to the file containing the cursor.
|
/// apply to the file containing the cursor.
|
||||||
fn check_no_diagnostics(ra_fixture: &str) {
|
fn check_no_diagnostics(ra_fixture: &str) {
|
||||||
|
@ -732,4 +760,28 @@ struct Foo {
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_add_field_in_other_file_from_usage() {
|
||||||
|
check_apply_diagnostic_fix_in_other_file(
|
||||||
|
r"
|
||||||
|
//- /main.rs
|
||||||
|
mod foo;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
<|>foo::Foo { bar: 3, baz: false};
|
||||||
|
}
|
||||||
|
//- /foo.rs
|
||||||
|
struct Foo {
|
||||||
|
bar: i32
|
||||||
|
}
|
||||||
|
",
|
||||||
|
r"
|
||||||
|
struct Foo {
|
||||||
|
bar: i32,
|
||||||
|
pub(crate) baz: bool
|
||||||
|
}
|
||||||
|
",
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue