mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-03 07:04:49 +00:00
Add quickfix to add a struct field
This commit is contained in:
parent
b56ad148db
commit
f5ac313000
5 changed files with 134 additions and 5 deletions
|
@ -8,7 +8,7 @@ use std::cell::RefCell;
|
|||
|
||||
use hir::{
|
||||
diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSink},
|
||||
Semantics,
|
||||
HasSource, HirDisplay, Semantics, VariantDef,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use ra_db::{RelativePath, SourceDatabase, SourceDatabaseExt};
|
||||
|
@ -16,7 +16,7 @@ use ra_ide_db::RootDatabase;
|
|||
use ra_prof::profile;
|
||||
use ra_syntax::{
|
||||
algo,
|
||||
ast::{self, make, AstNode},
|
||||
ast::{self, edit::IndentLevel, make, AstNode},
|
||||
SyntaxNode, TextRange, T,
|
||||
};
|
||||
use ra_text_edit::{TextEdit, TextEditBuilder};
|
||||
|
@ -123,7 +123,16 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
|
|||
severity: Severity::Error,
|
||||
fix: Some(fix),
|
||||
})
|
||||
})
|
||||
.on::<hir::diagnostics::NoSuchField, _>(|d| {
|
||||
res.borrow_mut().push(Diagnostic {
|
||||
range: sema.diagnostics_range(d).range,
|
||||
message: d.message(),
|
||||
severity: Severity::Error,
|
||||
fix: missing_struct_field_fix(&sema, file_id, d),
|
||||
})
|
||||
});
|
||||
|
||||
if let Some(m) = sema.to_module_def(file_id) {
|
||||
m.diagnostics(db, &mut sink);
|
||||
};
|
||||
|
@ -131,6 +140,68 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
|
|||
res.into_inner()
|
||||
}
|
||||
|
||||
fn missing_struct_field_fix(
|
||||
sema: &Semantics<RootDatabase>,
|
||||
file_id: FileId,
|
||||
d: &hir::diagnostics::NoSuchField,
|
||||
) -> Option<Fix> {
|
||||
let record_expr = sema.ast(d);
|
||||
|
||||
let record_lit = ast::RecordLit::cast(record_expr.syntax().parent()?.parent()?)?;
|
||||
let def_id = sema.resolve_variant(record_lit)?;
|
||||
let module;
|
||||
let record_fields = match VariantDef::from(def_id) {
|
||||
VariantDef::Struct(s) => {
|
||||
module = s.module(sema.db);
|
||||
let source = s.source(sema.db);
|
||||
let fields = source.value.field_def_list()?;
|
||||
record_field_def_list(fields)?
|
||||
}
|
||||
VariantDef::Union(u) => {
|
||||
module = u.module(sema.db);
|
||||
let source = u.source(sema.db);
|
||||
source.value.record_field_def_list()?
|
||||
}
|
||||
VariantDef::EnumVariant(e) => {
|
||||
module = e.module(sema.db);
|
||||
let source = e.source(sema.db);
|
||||
let fields = source.value.field_def_list()?;
|
||||
record_field_def_list(fields)?
|
||||
}
|
||||
};
|
||||
|
||||
let new_field_type = sema.type_of_expr(&record_expr.expr()?)?;
|
||||
let new_field = make::record_field_def(
|
||||
record_expr.field_name()?,
|
||||
make::type_ref(&new_field_type.display_source_code(sema.db, module.into()).ok()?),
|
||||
);
|
||||
|
||||
let last_field = record_fields.fields().last()?;
|
||||
let last_field_syntax = last_field.syntax();
|
||||
let indent = IndentLevel::from_node(last_field_syntax);
|
||||
|
||||
let mut new_field = format!("\n{}{}", indent, new_field);
|
||||
|
||||
let needs_comma = !last_field_syntax.to_string().ends_with(",");
|
||||
if needs_comma {
|
||||
new_field = format!(",{}", new_field);
|
||||
}
|
||||
|
||||
let source_change = SourceFileEdit {
|
||||
file_id,
|
||||
edit: TextEdit::insert(last_field_syntax.text_range().end(), new_field),
|
||||
};
|
||||
let fix = Fix::new("Create field", source_change.into());
|
||||
return Some(fix);
|
||||
|
||||
fn record_field_def_list(field_def_list: ast::FieldDefList) -> Option<ast::RecordFieldDefList> {
|
||||
match field_def_list {
|
||||
ast::FieldDefList::RecordFieldDefList(it) => Some(it),
|
||||
ast::FieldDefList::TupleFieldDefList(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_unnecessary_braces_in_use_statement(
|
||||
acc: &mut Vec<Diagnostic>,
|
||||
file_id: FileId,
|
||||
|
@ -795,4 +866,27 @@ fn main() {
|
|||
check_struct_shorthand_initialization,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add_field_from_usage() {
|
||||
check_apply_diagnostic_fix(
|
||||
r"
|
||||
fn main() {
|
||||
Foo { bar: 3, baz: false};
|
||||
}
|
||||
struct Foo {
|
||||
bar: i32
|
||||
}
|
||||
",
|
||||
r"
|
||||
fn main() {
|
||||
Foo { bar: 3, baz: false};
|
||||
}
|
||||
struct Foo {
|
||||
bar: i32,
|
||||
baz: bool
|
||||
}
|
||||
",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue