Skip to content

Commit c6509a4

Browse files
committed
internal: move missing_fields diagnostics
1 parent efa069d commit c6509a4

File tree

6 files changed

+98
-109
lines changed

6 files changed

+98
-109
lines changed

crates/hir/src/diagnostics.rs

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub use crate::diagnostics_sink::{
1616
};
1717

1818
macro_rules! diagnostics {
19-
($($diag:ident)*) => {
19+
($($diag:ident),*) => {
2020
pub enum AnyDiagnostic {$(
2121
$diag(Box<$diag>),
2222
)*}
@@ -31,7 +31,7 @@ macro_rules! diagnostics {
3131
};
3232
}
3333

34-
diagnostics![UnresolvedModule];
34+
diagnostics![UnresolvedModule, MissingFields];
3535

3636
#[derive(Debug)]
3737
pub struct UnresolvedModule {
@@ -321,17 +321,6 @@ impl Diagnostic for MissingUnsafe {
321321
}
322322
}
323323

324-
// Diagnostic: missing-structure-fields
325-
//
326-
// This diagnostic is triggered if record lacks some fields that exist in the corresponding structure.
327-
//
328-
// Example:
329-
//
330-
// ```rust
331-
// struct A { a: u8, b: u8 }
332-
//
333-
// let a = A { a: 10 };
334-
// ```
335324
#[derive(Debug)]
336325
pub struct MissingFields {
337326
pub file: HirFileId,
@@ -340,34 +329,6 @@ pub struct MissingFields {
340329
pub missed_fields: Vec<Name>,
341330
}
342331

343-
impl Diagnostic for MissingFields {
344-
fn code(&self) -> DiagnosticCode {
345-
DiagnosticCode("missing-structure-fields")
346-
}
347-
fn message(&self) -> String {
348-
let mut buf = String::from("Missing structure fields:\n");
349-
for field in &self.missed_fields {
350-
format_to!(buf, "- {}\n", field);
351-
}
352-
buf
353-
}
354-
355-
fn display_source(&self) -> InFile<SyntaxNodePtr> {
356-
InFile {
357-
file_id: self.file,
358-
value: self
359-
.field_list_parent_path
360-
.clone()
361-
.map(SyntaxNodePtr::from)
362-
.unwrap_or_else(|| self.field_list_parent.clone().into()),
363-
}
364-
}
365-
366-
fn as_any(&self) -> &(dyn Any + Send + 'static) {
367-
self
368-
}
369-
}
370-
371332
// Diagnostic: missing-pat-fields
372333
//
373334
// This diagnostic is triggered if pattern lacks some fields that exist in the corresponding structure.

crates/hir/src/lib.rs

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -609,23 +609,21 @@ impl Module {
609609
}
610610
for decl in self.declarations(db) {
611611
match decl {
612-
crate::ModuleDef::Function(f) => f.diagnostics(db, sink, internal_diagnostics),
613-
crate::ModuleDef::Module(m) => {
612+
ModuleDef::Function(f) => acc.extend(f.diagnostics(db, sink, internal_diagnostics)),
613+
ModuleDef::Module(m) => {
614614
// Only add diagnostics from inline modules
615615
if def_map[m.id.local_id].origin.is_inline() {
616616
acc.extend(m.diagnostics(db, sink, internal_diagnostics))
617617
}
618618
}
619-
_ => {
620-
decl.diagnostics(db, sink);
621-
}
619+
_ => decl.diagnostics(db, sink),
622620
}
623621
}
624622

625623
for impl_def in self.impl_defs(db) {
626624
for item in impl_def.items(db) {
627625
if let AssocItem::Function(f) = item {
628-
f.diagnostics(db, sink, internal_diagnostics);
626+
acc.extend(f.diagnostics(db, sink, internal_diagnostics));
629627
}
630628
}
631629
}
@@ -1033,7 +1031,8 @@ impl Function {
10331031
db: &dyn HirDatabase,
10341032
sink: &mut DiagnosticSink,
10351033
internal_diagnostics: bool,
1036-
) {
1034+
) -> Vec<AnyDiagnostic> {
1035+
let mut acc: Vec<AnyDiagnostic> = Vec::new();
10371036
let krate = self.module(db).id.krate();
10381037

10391038
let source_map = db.body_with_source_map(self.id.into()).1;
@@ -1114,14 +1113,17 @@ impl Function {
11141113
.into_iter()
11151114
.map(|idx| variant_data.fields()[idx].name.clone())
11161115
.collect();
1117-
sink.push(MissingFields {
1118-
file: source_ptr.file_id,
1119-
field_list_parent: AstPtr::new(record_expr),
1120-
field_list_parent_path: record_expr
1121-
.path()
1122-
.map(|path| AstPtr::new(&path)),
1123-
missed_fields,
1124-
})
1116+
acc.push(
1117+
MissingFields {
1118+
file: source_ptr.file_id,
1119+
field_list_parent: AstPtr::new(record_expr),
1120+
field_list_parent_path: record_expr
1121+
.path()
1122+
.map(|path| AstPtr::new(&path)),
1123+
missed_fields,
1124+
}
1125+
.into(),
1126+
)
11251127
}
11261128
}
11271129
}
@@ -1234,6 +1236,7 @@ impl Function {
12341236
for diag in hir_ty::diagnostics::validate_module_item(db, krate, self.id.into()) {
12351237
sink.push(diag)
12361238
}
1239+
acc
12371240
}
12381241

12391242
/// Whether this function declaration has a definition.

crates/ide/src/diagnostics.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
//! original files. So we need to map the ranges.
66
77
mod unresolved_module;
8+
mod missing_fields;
89

910
mod fixes;
1011
mod field_shorthand;
@@ -123,9 +124,6 @@ pub(crate) fn diagnostics(
123124
}
124125
let res = RefCell::new(res);
125126
let sink_builder = DiagnosticSinkBuilder::new()
126-
.on::<hir::diagnostics::MissingFields, _>(|d| {
127-
res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve));
128-
})
129127
.on::<hir::diagnostics::MissingOkOrSomeInTailExpr, _>(|d| {
130128
res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve));
131129
})
@@ -232,7 +230,8 @@ pub(crate) fn diagnostics(
232230
let ctx = DiagnosticsContext { config, sema, resolve };
233231
for diag in diags {
234232
let d = match diag {
235-
AnyDiagnostic::UnresolvedModule(d) => unresolved_module::render(&ctx, &d),
233+
AnyDiagnostic::UnresolvedModule(d) => unresolved_module::unresolved_module(&ctx, &d),
234+
AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d),
236235
};
237236
if let Some(code) = d.code {
238237
if ctx.config.disabled.contains(code.as_str()) {

crates/ide/src/diagnostics/fixes.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
//! The same module also has all curret custom fixes for the diagnostics implemented.
33
mod change_case;
44
mod create_field;
5-
mod fill_missing_fields;
65
mod remove_semicolon;
76
mod replace_with_find_map;
87
mod wrap_tail_expr;

crates/ide/src/diagnostics/fixes/fill_missing_fields.rs renamed to crates/ide/src/diagnostics/missing_fields.rs

Lines changed: 71 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,77 @@
1-
use hir::{db::AstDatabase, diagnostics::MissingFields, Semantics};
2-
use ide_assists::AssistResolveStrategy;
3-
use ide_db::{source_change::SourceChange, RootDatabase};
4-
use syntax::{algo, ast::make, AstNode};
1+
use hir::{db::AstDatabase, InFile};
2+
use ide_assists::Assist;
3+
use ide_db::source_change::SourceChange;
4+
use stdx::format_to;
5+
use syntax::{algo, ast::make, AstNode, SyntaxNodePtr};
56
use text_edit::TextEdit;
67

7-
use crate::{
8-
diagnostics::{fix, fixes::DiagnosticWithFixes},
9-
Assist,
10-
};
11-
12-
impl DiagnosticWithFixes for MissingFields {
13-
fn fixes(
14-
&self,
15-
sema: &Semantics<RootDatabase>,
16-
_resolve: &AssistResolveStrategy,
17-
) -> Option<Vec<Assist>> {
18-
// Note that although we could add a diagnostics to
19-
// fill the missing tuple field, e.g :
20-
// `struct A(usize);`
21-
// `let a = A { 0: () }`
22-
// but it is uncommon usage and it should not be encouraged.
23-
if self.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
24-
return None;
25-
}
26-
27-
let root = sema.db.parse_or_expand(self.file)?;
28-
let field_list_parent = self.field_list_parent.to_node(&root);
29-
let old_field_list = field_list_parent.record_expr_field_list()?;
30-
let new_field_list = old_field_list.clone_for_update();
31-
for f in self.missed_fields.iter() {
32-
let field =
33-
make::record_expr_field(make::name_ref(&f.to_string()), Some(make::expr_unit()))
34-
.clone_for_update();
35-
new_field_list.add_field(field);
36-
}
37-
38-
let edit = {
39-
let mut builder = TextEdit::builder();
40-
algo::diff(old_field_list.syntax(), new_field_list.syntax())
41-
.into_text_edit(&mut builder);
42-
builder.finish()
43-
};
44-
Some(vec![fix(
45-
"fill_missing_fields",
46-
"Fill struct fields",
47-
SourceChange::from_text_edit(self.file.original_file(sema.db), edit),
48-
sema.original_range(field_list_parent.syntax()).range,
49-
)])
8+
use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext};
9+
10+
// Diagnostic: missing-structure-fields
11+
//
12+
// This diagnostic is triggered if record lacks some fields that exist in the corresponding structure.
13+
//
14+
// Example:
15+
//
16+
// ```rust
17+
// struct A { a: u8, b: u8 }
18+
//
19+
// let a = A { a: 10 };
20+
// ```
21+
pub(super) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic {
22+
let mut message = String::from("Missing structure fields:\n");
23+
for field in &d.missed_fields {
24+
format_to!(message, "- {}\n", field);
5025
}
26+
27+
let ptr = InFile::new(
28+
d.file,
29+
d.field_list_parent_path
30+
.clone()
31+
.map(SyntaxNodePtr::from)
32+
.unwrap_or_else(|| d.field_list_parent.clone().into()),
33+
);
34+
35+
Diagnostic::new(
36+
"missing-structure-fields",
37+
message,
38+
ctx.sema.diagnostics_display_range(ptr).range,
39+
)
40+
.with_fixes(fixes(ctx, d))
41+
}
42+
43+
fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Assist>> {
44+
// Note that although we could add a diagnostics to
45+
// fill the missing tuple field, e.g :
46+
// `struct A(usize);`
47+
// `let a = A { 0: () }`
48+
// but it is uncommon usage and it should not be encouraged.
49+
if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
50+
return None;
51+
}
52+
53+
let root = ctx.sema.db.parse_or_expand(d.file)?;
54+
let field_list_parent = d.field_list_parent.to_node(&root);
55+
let old_field_list = field_list_parent.record_expr_field_list()?;
56+
let new_field_list = old_field_list.clone_for_update();
57+
for f in d.missed_fields.iter() {
58+
let field =
59+
make::record_expr_field(make::name_ref(&f.to_string()), Some(make::expr_unit()))
60+
.clone_for_update();
61+
new_field_list.add_field(field);
62+
}
63+
64+
let edit = {
65+
let mut builder = TextEdit::builder();
66+
algo::diff(old_field_list.syntax(), new_field_list.syntax()).into_text_edit(&mut builder);
67+
builder.finish()
68+
};
69+
Some(vec![fix(
70+
"fill_missing_fields",
71+
"Fill struct fields",
72+
SourceChange::from_text_edit(d.file.original_file(ctx.sema.db), edit),
73+
ctx.sema.original_range(field_list_parent.syntax()).range,
74+
)])
5175
}
5276

5377
#[cfg(test)]

crates/ide/src/diagnostics/unresolved_module.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext};
88
// Diagnostic: unresolved-module
99
//
1010
// This diagnostic is triggered if rust-analyzer is unable to discover referred module.
11-
pub(super) fn render(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedModule) -> Diagnostic {
11+
pub(super) fn unresolved_module(
12+
ctx: &DiagnosticsContext<'_>,
13+
d: &hir::UnresolvedModule,
14+
) -> Diagnostic {
1215
Diagnostic::new(
1316
"unresolved-module",
1417
"unresolved module",

0 commit comments

Comments
 (0)