Skip to content

Commit 6f02bef

Browse files
author
Jonas Schievink
committed
Add a builder for DiagnosticSink
1 parent c3defe2 commit 6f02bef

File tree

4 files changed

+102
-88
lines changed

4 files changed

+102
-88
lines changed

crates/ra_hir/src/diagnostics.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! FIXME: write short doc here
22
pub use hir_def::diagnostics::UnresolvedModule;
3-
pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink};
3+
pub use hir_expand::diagnostics::{
4+
AstDiagnostic, Diagnostic, DiagnosticSink, DiagnosticSinkBuilder,
5+
};
46
pub use hir_ty::diagnostics::{
57
MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField,
68
};

crates/ra_hir_expand/src/diagnostics.rs

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,23 +48,6 @@ pub struct DiagnosticSink<'a> {
4848
}
4949

5050
impl<'a> DiagnosticSink<'a> {
51-
/// FIXME: split `new` and `on` into a separate builder type
52-
pub fn new(cb: impl FnMut(&dyn Diagnostic) + 'a) -> DiagnosticSink<'a> {
53-
DiagnosticSink { callbacks: Vec::new(), default_callback: Box::new(cb) }
54-
}
55-
56-
pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> DiagnosticSink<'a> {
57-
let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() {
58-
Some(d) => {
59-
cb(d);
60-
Ok(())
61-
}
62-
None => Err(()),
63-
};
64-
self.callbacks.push(Box::new(cb));
65-
self
66-
}
67-
6851
pub fn push(&mut self, d: impl Diagnostic) {
6952
let d: &dyn Diagnostic = &d;
7053
self._push(d);
@@ -80,3 +63,29 @@ impl<'a> DiagnosticSink<'a> {
8063
(self.default_callback)(d)
8164
}
8265
}
66+
67+
pub struct DiagnosticSinkBuilder<'a> {
68+
callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
69+
}
70+
71+
impl<'a> DiagnosticSinkBuilder<'a> {
72+
pub fn new() -> Self {
73+
Self { callbacks: Vec::new() }
74+
}
75+
76+
pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> Self {
77+
let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() {
78+
Some(d) => {
79+
cb(d);
80+
Ok(())
81+
}
82+
None => Err(()),
83+
};
84+
self.callbacks.push(Box::new(cb));
85+
self
86+
}
87+
88+
pub fn build<F: FnMut(&dyn Diagnostic) + 'a>(self, default_callback: F) -> DiagnosticSink<'a> {
89+
DiagnosticSink { callbacks: self.callbacks, default_callback: Box::new(default_callback) }
90+
}
91+
}

crates/ra_hir_ty/src/diagnostics.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ impl AstDiagnostic for MismatchedArgCount {
248248
#[cfg(test)]
249249
mod tests {
250250
use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId};
251-
use hir_expand::diagnostics::{Diagnostic, DiagnosticSink};
251+
use hir_expand::diagnostics::{Diagnostic, DiagnosticSinkBuilder};
252252
use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt};
253253
use ra_syntax::{TextRange, TextSize};
254254
use rustc_hash::FxHashMap;
@@ -280,7 +280,7 @@ mod tests {
280280
}
281281

282282
for f in fns {
283-
let mut sink = DiagnosticSink::new(&mut cb);
283+
let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
284284
validate_body(self, f.into(), &mut sink);
285285
}
286286
}

crates/ra_ide/src/diagnostics.rs

Lines changed: 71 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use std::cell::RefCell;
88

99
use hir::{
10-
diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSink},
10+
diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSinkBuilder},
1111
HasSource, HirDisplay, Semantics, VariantDef,
1212
};
1313
use itertools::Itertools;
@@ -48,79 +48,82 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
4848
check_struct_shorthand_initialization(&mut res, file_id, &node);
4949
}
5050
let res = RefCell::new(res);
51-
let mut sink = DiagnosticSink::new(|d| {
52-
res.borrow_mut().push(Diagnostic {
53-
message: d.message(),
54-
range: sema.diagnostics_range(d).range,
55-
severity: Severity::Error,
56-
fix: None,
51+
let mut sink = DiagnosticSinkBuilder::new()
52+
.on::<hir::diagnostics::UnresolvedModule, _>(|d| {
53+
let original_file = d.source().file_id.original_file(db);
54+
let fix = Fix::new(
55+
"Create module",
56+
FileSystemEdit::CreateFile { anchor: original_file, dst: d.candidate.clone() }
57+
.into(),
58+
);
59+
res.borrow_mut().push(Diagnostic {
60+
range: sema.diagnostics_range(d).range,
61+
message: d.message(),
62+
severity: Severity::Error,
63+
fix: Some(fix),
64+
})
5765
})
58-
})
59-
.on::<hir::diagnostics::UnresolvedModule, _>(|d| {
60-
let original_file = d.source().file_id.original_file(db);
61-
let fix = Fix::new(
62-
"Create module",
63-
FileSystemEdit::CreateFile { anchor: original_file, dst: d.candidate.clone() }.into(),
64-
);
65-
res.borrow_mut().push(Diagnostic {
66-
range: sema.diagnostics_range(d).range,
67-
message: d.message(),
68-
severity: Severity::Error,
69-
fix: Some(fix),
70-
})
71-
})
72-
.on::<hir::diagnostics::MissingFields, _>(|d| {
73-
// Note that although we could add a diagnostics to
74-
// fill the missing tuple field, e.g :
75-
// `struct A(usize);`
76-
// `let a = A { 0: () }`
77-
// but it is uncommon usage and it should not be encouraged.
78-
let fix = if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
79-
None
80-
} else {
81-
let mut field_list = d.ast(db);
82-
for f in d.missed_fields.iter() {
83-
let field =
84-
make::record_field(make::name_ref(&f.to_string()), Some(make::expr_unit()));
85-
field_list = field_list.append_field(&field);
86-
}
87-
88-
let edit = {
89-
let mut builder = TextEditBuilder::default();
90-
algo::diff(&d.ast(db).syntax(), &field_list.syntax()).into_text_edit(&mut builder);
91-
builder.finish()
66+
.on::<hir::diagnostics::MissingFields, _>(|d| {
67+
// Note that although we could add a diagnostics to
68+
// fill the missing tuple field, e.g :
69+
// `struct A(usize);`
70+
// `let a = A { 0: () }`
71+
// but it is uncommon usage and it should not be encouraged.
72+
let fix = if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
73+
None
74+
} else {
75+
let mut field_list = d.ast(db);
76+
for f in d.missed_fields.iter() {
77+
let field =
78+
make::record_field(make::name_ref(&f.to_string()), Some(make::expr_unit()));
79+
field_list = field_list.append_field(&field);
80+
}
81+
82+
let edit = {
83+
let mut builder = TextEditBuilder::default();
84+
algo::diff(&d.ast(db).syntax(), &field_list.syntax())
85+
.into_text_edit(&mut builder);
86+
builder.finish()
87+
};
88+
Some(Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into()))
9289
};
93-
Some(Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into()))
94-
};
9590

96-
res.borrow_mut().push(Diagnostic {
97-
range: sema.diagnostics_range(d).range,
98-
message: d.message(),
99-
severity: Severity::Error,
100-
fix,
91+
res.borrow_mut().push(Diagnostic {
92+
range: sema.diagnostics_range(d).range,
93+
message: d.message(),
94+
severity: Severity::Error,
95+
fix,
96+
})
10197
})
102-
})
103-
.on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| {
104-
let node = d.ast(db);
105-
let replacement = format!("Ok({})", node.syntax());
106-
let edit = TextEdit::replace(node.syntax().text_range(), replacement);
107-
let source_change = SourceFileEdit { file_id, edit }.into();
108-
let fix = Fix::new("Wrap with ok", source_change);
109-
res.borrow_mut().push(Diagnostic {
110-
range: sema.diagnostics_range(d).range,
111-
message: d.message(),
112-
severity: Severity::Error,
113-
fix: Some(fix),
98+
.on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| {
99+
let node = d.ast(db);
100+
let replacement = format!("Ok({})", node.syntax());
101+
let edit = TextEdit::replace(node.syntax().text_range(), replacement);
102+
let source_change = SourceFileEdit { file_id, edit }.into();
103+
let fix = Fix::new("Wrap with ok", source_change);
104+
res.borrow_mut().push(Diagnostic {
105+
range: sema.diagnostics_range(d).range,
106+
message: d.message(),
107+
severity: Severity::Error,
108+
fix: Some(fix),
109+
})
114110
})
115-
})
116-
.on::<hir::diagnostics::NoSuchField, _>(|d| {
117-
res.borrow_mut().push(Diagnostic {
118-
range: sema.diagnostics_range(d).range,
119-
message: d.message(),
120-
severity: Severity::Error,
121-
fix: missing_struct_field_fix(&sema, file_id, d),
111+
.on::<hir::diagnostics::NoSuchField, _>(|d| {
112+
res.borrow_mut().push(Diagnostic {
113+
range: sema.diagnostics_range(d).range,
114+
message: d.message(),
115+
severity: Severity::Error,
116+
fix: missing_struct_field_fix(&sema, file_id, d),
117+
})
122118
})
123-
});
119+
.build(|d| {
120+
res.borrow_mut().push(Diagnostic {
121+
message: d.message(),
122+
range: sema.diagnostics_range(d).range,
123+
severity: Severity::Error,
124+
fix: None,
125+
})
126+
});
124127

125128
if let Some(m) = sema.to_module_def(file_id) {
126129
m.diagnostics(db, &mut sink);

0 commit comments

Comments
 (0)