aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty
diff options
context:
space:
mode:
authorKirill Bulatov <[email protected]>2020-08-08 23:59:26 +0100
committerKirill Bulatov <[email protected]>2020-08-11 13:09:08 +0100
commit9963f43d51071ea02f8f6d490b9c49882034b42c (patch)
tree7ecdbbd66fb8c988989e6de17c77ab14262589c0 /crates/ra_hir_ty
parentcfbbd91a886e2394e7411f9d7f4966dcbd454764 (diff)
Refactor the diagnostics
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs97
-rw-r--r--crates/ra_hir_ty/src/diagnostics/expr.rs12
2 files changed, 44 insertions, 65 deletions
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index efca09619..1e3a44637 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -9,7 +9,7 @@ use hir_def::DefWithBodyId;
9use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; 9use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink};
10use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; 10use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile};
11use ra_prof::profile; 11use ra_prof::profile;
12use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; 12use ra_syntax::{ast, AstPtr, SyntaxNodePtr};
13use stdx::format_to; 13use stdx::format_to;
14 14
15use crate::db::HirDatabase; 15use crate::db::HirDatabase;
@@ -37,7 +37,7 @@ impl Diagnostic for NoSuchField {
37 "no such field".to_string() 37 "no such field".to_string()
38 } 38 }
39 39
40 fn source(&self) -> InFile<SyntaxNodePtr> { 40 fn presentation(&self) -> InFile<SyntaxNodePtr> {
41 InFile::new(self.file, self.field.clone().into()) 41 InFile::new(self.file, self.field.clone().into())
42 } 42 }
43 43
@@ -49,7 +49,7 @@ impl Diagnostic for NoSuchField {
49impl AstDiagnostic for NoSuchField { 49impl AstDiagnostic for NoSuchField {
50 type AST = ast::RecordExprField; 50 type AST = ast::RecordExprField;
51 51
52 fn ast(&self, db: &dyn AstDatabase) -> Self::AST { 52 fn fix_source(&self, db: &dyn AstDatabase) -> Self::AST {
53 let root = db.parse_or_expand(self.file).unwrap(); 53 let root = db.parse_or_expand(self.file).unwrap();
54 self.field.to_node(&root) 54 self.field.to_node(&root)
55 } 55 }
@@ -58,7 +58,7 @@ impl AstDiagnostic for NoSuchField {
58#[derive(Debug)] 58#[derive(Debug)]
59pub struct MissingFields { 59pub struct MissingFields {
60 pub file: HirFileId, 60 pub file: HirFileId,
61 pub field_list: AstPtr<ast::RecordExprFieldList>, 61 pub field_list_parent: AstPtr<ast::RecordExpr>,
62 pub field_list_parent_path: Option<AstPtr<ast::Path>>, 62 pub field_list_parent_path: Option<AstPtr<ast::Path>>,
63 pub missed_fields: Vec<Name>, 63 pub missed_fields: Vec<Name>,
64} 64}
@@ -71,15 +71,16 @@ impl Diagnostic for MissingFields {
71 } 71 }
72 buf 72 buf
73 } 73 }
74 fn fix_source(&self) -> InFile<SyntaxNodePtr> {
75 InFile { file_id: self.file, value: self.field_list.clone().into() }
76 }
77 74
78 fn source(&self) -> InFile<SyntaxNodePtr> { 75 fn presentation(&self) -> InFile<SyntaxNodePtr> {
79 self.field_list_parent_path 76 InFile {
80 .clone() 77 file_id: self.file,
81 .map(|path| InFile { file_id: self.file, value: path.into() }) 78 value: self
82 .unwrap_or_else(|| self.fix_source()) 79 .field_list_parent_path
80 .clone()
81 .map(SyntaxNodePtr::from)
82 .unwrap_or_else(|| self.field_list_parent.clone().into()),
83 }
83 } 84 }
84 85
85 fn as_any(&self) -> &(dyn Any + Send + 'static) { 86 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -88,18 +89,18 @@ impl Diagnostic for MissingFields {
88} 89}
89 90
90impl AstDiagnostic for MissingFields { 91impl AstDiagnostic for MissingFields {
91 type AST = ast::RecordExprFieldList; 92 type AST = ast::RecordExpr;
92 93
93 fn ast(&self, db: &dyn AstDatabase) -> Self::AST { 94 fn fix_source(&self, db: &dyn AstDatabase) -> Self::AST {
94 let root = db.parse_or_expand(self.file).unwrap(); 95 let root = db.parse_or_expand(self.file).unwrap();
95 self.field_list.to_node(&root) 96 self.field_list_parent.to_node(&root)
96 } 97 }
97} 98}
98 99
99#[derive(Debug)] 100#[derive(Debug)]
100pub struct MissingPatFields { 101pub struct MissingPatFields {
101 pub file: HirFileId, 102 pub file: HirFileId,
102 pub field_list: AstPtr<ast::RecordPatFieldList>, 103 pub field_list_parent: AstPtr<ast::RecordPat>,
103 pub field_list_parent_path: Option<AstPtr<ast::Path>>, 104 pub field_list_parent_path: Option<AstPtr<ast::Path>>,
104 pub missed_fields: Vec<Name>, 105 pub missed_fields: Vec<Name>,
105} 106}
@@ -112,14 +113,13 @@ impl Diagnostic for MissingPatFields {
112 } 113 }
113 buf 114 buf
114 } 115 }
115 fn fix_source(&self) -> InFile<SyntaxNodePtr> { 116 fn presentation(&self) -> InFile<SyntaxNodePtr> {
116 InFile { file_id: self.file, value: self.field_list.clone().into() } 117 let value = self
117 } 118 .field_list_parent_path
118 fn source(&self) -> InFile<SyntaxNodePtr> {
119 self.field_list_parent_path
120 .clone() 119 .clone()
121 .map(|path| InFile { file_id: self.file, value: path.into() }) 120 .map(SyntaxNodePtr::from)
122 .unwrap_or_else(|| self.fix_source()) 121 .unwrap_or_else(|| self.field_list_parent.clone().into());
122 InFile { file_id: self.file, value }
123 } 123 }
124 fn as_any(&self) -> &(dyn Any + Send + 'static) { 124 fn as_any(&self) -> &(dyn Any + Send + 'static) {
125 self 125 self
@@ -137,7 +137,7 @@ impl Diagnostic for MissingMatchArms {
137 fn message(&self) -> String { 137 fn message(&self) -> String {
138 String::from("Missing match arm") 138 String::from("Missing match arm")
139 } 139 }
140 fn source(&self) -> InFile<SyntaxNodePtr> { 140 fn presentation(&self) -> InFile<SyntaxNodePtr> {
141 InFile { file_id: self.file, value: self.match_expr.clone().into() } 141 InFile { file_id: self.file, value: self.match_expr.clone().into() }
142 } 142 }
143 fn as_any(&self) -> &(dyn Any + Send + 'static) { 143 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -155,7 +155,7 @@ impl Diagnostic for MissingOkInTailExpr {
155 fn message(&self) -> String { 155 fn message(&self) -> String {
156 "wrap return expression in Ok".to_string() 156 "wrap return expression in Ok".to_string()
157 } 157 }
158 fn source(&self) -> InFile<SyntaxNodePtr> { 158 fn presentation(&self) -> InFile<SyntaxNodePtr> {
159 InFile { file_id: self.file, value: self.expr.clone().into() } 159 InFile { file_id: self.file, value: self.expr.clone().into() }
160 } 160 }
161 fn as_any(&self) -> &(dyn Any + Send + 'static) { 161 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -166,7 +166,7 @@ impl Diagnostic for MissingOkInTailExpr {
166impl AstDiagnostic for MissingOkInTailExpr { 166impl AstDiagnostic for MissingOkInTailExpr {
167 type AST = ast::Expr; 167 type AST = ast::Expr;
168 168
169 fn ast(&self, db: &dyn AstDatabase) -> Self::AST { 169 fn fix_source(&self, db: &dyn AstDatabase) -> Self::AST {
170 let root = db.parse_or_expand(self.file).unwrap(); 170 let root = db.parse_or_expand(self.file).unwrap();
171 self.expr.to_node(&root) 171 self.expr.to_node(&root)
172 } 172 }
@@ -182,7 +182,7 @@ impl Diagnostic for BreakOutsideOfLoop {
182 fn message(&self) -> String { 182 fn message(&self) -> String {
183 "break outside of loop".to_string() 183 "break outside of loop".to_string()
184 } 184 }
185 fn source(&self) -> InFile<SyntaxNodePtr> { 185 fn presentation(&self) -> InFile<SyntaxNodePtr> {
186 InFile { file_id: self.file, value: self.expr.clone().into() } 186 InFile { file_id: self.file, value: self.expr.clone().into() }
187 } 187 }
188 fn as_any(&self) -> &(dyn Any + Send + 'static) { 188 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -190,15 +190,6 @@ impl Diagnostic for BreakOutsideOfLoop {
190 } 190 }
191} 191}
192 192
193impl AstDiagnostic for BreakOutsideOfLoop {
194 type AST = ast::Expr;
195
196 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
197 let root = db.parse_or_expand(self.file).unwrap();
198 self.expr.to_node(&root)
199 }
200}
201
202#[derive(Debug)] 193#[derive(Debug)]
203pub struct MissingUnsafe { 194pub struct MissingUnsafe {
204 pub file: HirFileId, 195 pub file: HirFileId,
@@ -209,7 +200,7 @@ impl Diagnostic for MissingUnsafe {
209 fn message(&self) -> String { 200 fn message(&self) -> String {
210 format!("This operation is unsafe and requires an unsafe function or block") 201 format!("This operation is unsafe and requires an unsafe function or block")
211 } 202 }
212 fn source(&self) -> InFile<SyntaxNodePtr> { 203 fn presentation(&self) -> InFile<SyntaxNodePtr> {
213 InFile { file_id: self.file, value: self.expr.clone().into() } 204 InFile { file_id: self.file, value: self.expr.clone().into() }
214 } 205 }
215 fn as_any(&self) -> &(dyn Any + Send + 'static) { 206 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -217,15 +208,6 @@ impl Diagnostic for MissingUnsafe {
217 } 208 }
218} 209}
219 210
220impl AstDiagnostic for MissingUnsafe {
221 type AST = ast::Expr;
222
223 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
224 let root = db.parse_or_expand(self.file).unwrap();
225 self.expr.to_node(&root)
226 }
227}
228
229#[derive(Debug)] 211#[derive(Debug)]
230pub struct MismatchedArgCount { 212pub struct MismatchedArgCount {
231 pub file: HirFileId, 213 pub file: HirFileId,
@@ -239,7 +221,7 @@ impl Diagnostic for MismatchedArgCount {
239 let s = if self.expected == 1 { "" } else { "s" }; 221 let s = if self.expected == 1 { "" } else { "s" };
240 format!("Expected {} argument{}, found {}", self.expected, s, self.found) 222 format!("Expected {} argument{}, found {}", self.expected, s, self.found)
241 } 223 }
242 fn source(&self) -> InFile<SyntaxNodePtr> { 224 fn presentation(&self) -> InFile<SyntaxNodePtr> {
243 InFile { file_id: self.file, value: self.call_expr.clone().into() } 225 InFile { file_id: self.file, value: self.call_expr.clone().into() }
244 } 226 }
245 fn as_any(&self) -> &(dyn Any + Send + 'static) { 227 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -250,19 +232,13 @@ impl Diagnostic for MismatchedArgCount {
250 } 232 }
251} 233}
252 234
253impl AstDiagnostic for MismatchedArgCount {
254 type AST = ast::CallExpr;
255 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
256 let root = db.parse_or_expand(self.file).unwrap();
257 let node = self.source().value.to_node(&root);
258 ast::CallExpr::cast(node).unwrap()
259 }
260}
261
262#[cfg(test)] 235#[cfg(test)]
263mod tests { 236mod tests {
264 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId}; 237 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId};
265 use hir_expand::diagnostics::{Diagnostic, DiagnosticSinkBuilder}; 238 use hir_expand::{
239 db::AstDatabase,
240 diagnostics::{Diagnostic, DiagnosticSinkBuilder},
241 };
266 use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; 242 use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt};
267 use ra_syntax::{TextRange, TextSize}; 243 use ra_syntax::{TextRange, TextSize};
268 use rustc_hash::FxHashMap; 244 use rustc_hash::FxHashMap;
@@ -308,8 +284,11 @@ mod tests {
308 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); 284 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
309 db.diagnostics(|d| { 285 db.diagnostics(|d| {
310 // FIXME: macros... 286 // FIXME: macros...
311 let file_id = d.source().file_id.original_file(&db); 287 let diagnostics_presentation = d.presentation();
312 let range = d.syntax_node(&db).text_range(); 288 let root = db.parse_or_expand(diagnostics_presentation.file_id).unwrap();
289
290 let file_id = diagnostics_presentation.file_id.original_file(&db);
291 let range = diagnostics_presentation.value.to_node(&root).text_range();
313 let message = d.message().to_owned(); 292 let message = d.message().to_owned();
314 actual.entry(file_id).or_default().push((range, message)); 293 actual.entry(file_id).or_default().push((range, message));
315 }); 294 });
diff --git a/crates/ra_hir_ty/src/diagnostics/expr.rs b/crates/ra_hir_ty/src/diagnostics/expr.rs
index 98959ab68..51adcecaf 100644
--- a/crates/ra_hir_ty/src/diagnostics/expr.rs
+++ b/crates/ra_hir_ty/src/diagnostics/expr.rs
@@ -100,8 +100,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
100 100
101 if let Ok(source_ptr) = source_map.expr_syntax(id) { 101 if let Ok(source_ptr) = source_map.expr_syntax(id) {
102 let root = source_ptr.file_syntax(db.upcast()); 102 let root = source_ptr.file_syntax(db.upcast());
103 if let ast::Expr::RecordExpr(record_lit) = &source_ptr.value.to_node(&root) { 103 if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root) {
104 if let Some(field_list) = record_lit.record_expr_field_list() { 104 if let Some(_) = record_expr.record_expr_field_list() {
105 let variant_data = variant_data(db.upcast(), variant_def); 105 let variant_data = variant_data(db.upcast(), variant_def);
106 let missed_fields = missed_fields 106 let missed_fields = missed_fields
107 .into_iter() 107 .into_iter()
@@ -109,8 +109,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
109 .collect(); 109 .collect();
110 self.sink.push(MissingFields { 110 self.sink.push(MissingFields {
111 file: source_ptr.file_id, 111 file: source_ptr.file_id,
112 field_list: AstPtr::new(&field_list), 112 field_list_parent: AstPtr::new(&record_expr),
113 field_list_parent_path: record_lit.path().map(|path| AstPtr::new(&path)), 113 field_list_parent_path: record_expr.path().map(|path| AstPtr::new(&path)),
114 missed_fields, 114 missed_fields,
115 }) 115 })
116 } 116 }
@@ -132,7 +132,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
132 if let Some(expr) = source_ptr.value.as_ref().left() { 132 if let Some(expr) = source_ptr.value.as_ref().left() {
133 let root = source_ptr.file_syntax(db.upcast()); 133 let root = source_ptr.file_syntax(db.upcast());
134 if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { 134 if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) {
135 if let Some(field_list) = record_pat.record_pat_field_list() { 135 if let Some(_) = record_pat.record_pat_field_list() {
136 let variant_data = variant_data(db.upcast(), variant_def); 136 let variant_data = variant_data(db.upcast(), variant_def);
137 let missed_fields = missed_fields 137 let missed_fields = missed_fields
138 .into_iter() 138 .into_iter()
@@ -140,7 +140,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
140 .collect(); 140 .collect();
141 self.sink.push(MissingPatFields { 141 self.sink.push(MissingPatFields {
142 file: source_ptr.file_id, 142 file: source_ptr.file_id,
143 field_list: AstPtr::new(&field_list), 143 field_list_parent: AstPtr::new(&record_pat),
144 field_list_parent_path: record_pat 144 field_list_parent_path: record_pat
145 .path() 145 .path()
146 .map(|path| AstPtr::new(&path)), 146 .map(|path| AstPtr::new(&path)),