diff options
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r-- | crates/ra_hir_ty/src/diagnostics.rs | 128 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/diagnostics/expr.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/diagnostics/match_check.rs | 8 |
3 files changed, 59 insertions, 91 deletions
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 977c0525b..7ab7f79db 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs | |||
@@ -6,10 +6,10 @@ mod unsafe_check; | |||
6 | use std::any::Any; | 6 | use std::any::Any; |
7 | 7 | ||
8 | use hir_def::DefWithBodyId; | 8 | use hir_def::DefWithBodyId; |
9 | use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; | 9 | use hir_expand::diagnostics::{Diagnostic, DiagnosticSink}; |
10 | use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; | 10 | use hir_expand::{name::Name, HirFileId, InFile}; |
11 | use ra_prof::profile; | 11 | use ra_prof::profile; |
12 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; | 12 | use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; |
13 | use stdx::format_to; | 13 | use stdx::format_to; |
14 | 14 | ||
15 | use crate::db::HirDatabase; | 15 | use 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 display_source(&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 | ||
@@ -46,20 +46,11 @@ impl Diagnostic for NoSuchField { | |||
46 | } | 46 | } |
47 | } | 47 | } |
48 | 48 | ||
49 | impl AstDiagnostic for NoSuchField { | ||
50 | type AST = ast::RecordExprField; | ||
51 | |||
52 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
53 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | ||
54 | let node = self.source().value.to_node(&root); | ||
55 | ast::RecordExprField::cast(node).unwrap() | ||
56 | } | ||
57 | } | ||
58 | |||
59 | #[derive(Debug)] | 49 | #[derive(Debug)] |
60 | pub struct MissingFields { | 50 | pub struct MissingFields { |
61 | pub file: HirFileId, | 51 | pub file: HirFileId, |
62 | pub field_list: AstPtr<ast::RecordExprFieldList>, | 52 | pub field_list_parent: AstPtr<ast::RecordExpr>, |
53 | pub field_list_parent_path: Option<AstPtr<ast::Path>>, | ||
63 | pub missed_fields: Vec<Name>, | 54 | pub missed_fields: Vec<Name>, |
64 | } | 55 | } |
65 | 56 | ||
@@ -71,28 +62,28 @@ impl Diagnostic for MissingFields { | |||
71 | } | 62 | } |
72 | buf | 63 | buf |
73 | } | 64 | } |
74 | fn source(&self) -> InFile<SyntaxNodePtr> { | 65 | |
75 | InFile { file_id: self.file, value: self.field_list.clone().into() } | 66 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
67 | InFile { | ||
68 | file_id: self.file, | ||
69 | value: self | ||
70 | .field_list_parent_path | ||
71 | .clone() | ||
72 | .map(SyntaxNodePtr::from) | ||
73 | .unwrap_or_else(|| self.field_list_parent.clone().into()), | ||
74 | } | ||
76 | } | 75 | } |
76 | |||
77 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 77 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
78 | self | 78 | self |
79 | } | 79 | } |
80 | } | 80 | } |
81 | 81 | ||
82 | impl AstDiagnostic for MissingFields { | ||
83 | type AST = ast::RecordExprFieldList; | ||
84 | |||
85 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
86 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | ||
87 | let node = self.source().value.to_node(&root); | ||
88 | ast::RecordExprFieldList::cast(node).unwrap() | ||
89 | } | ||
90 | } | ||
91 | |||
92 | #[derive(Debug)] | 82 | #[derive(Debug)] |
93 | pub struct MissingPatFields { | 83 | pub struct MissingPatFields { |
94 | pub file: HirFileId, | 84 | pub file: HirFileId, |
95 | pub field_list: AstPtr<ast::RecordPatFieldList>, | 85 | pub field_list_parent: AstPtr<ast::RecordPat>, |
86 | pub field_list_parent_path: Option<AstPtr<ast::Path>>, | ||
96 | pub missed_fields: Vec<Name>, | 87 | pub missed_fields: Vec<Name>, |
97 | } | 88 | } |
98 | 89 | ||
@@ -104,8 +95,15 @@ impl Diagnostic for MissingPatFields { | |||
104 | } | 95 | } |
105 | buf | 96 | buf |
106 | } | 97 | } |
107 | fn source(&self) -> InFile<SyntaxNodePtr> { | 98 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
108 | InFile { file_id: self.file, value: self.field_list.clone().into() } | 99 | InFile { |
100 | file_id: self.file, | ||
101 | value: self | ||
102 | .field_list_parent_path | ||
103 | .clone() | ||
104 | .map(SyntaxNodePtr::from) | ||
105 | .unwrap_or_else(|| self.field_list_parent.clone().into()), | ||
106 | } | ||
109 | } | 107 | } |
110 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 108 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
111 | self | 109 | self |
@@ -123,7 +121,7 @@ impl Diagnostic for MissingMatchArms { | |||
123 | fn message(&self) -> String { | 121 | fn message(&self) -> String { |
124 | String::from("Missing match arm") | 122 | String::from("Missing match arm") |
125 | } | 123 | } |
126 | fn source(&self) -> InFile<SyntaxNodePtr> { | 124 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
127 | InFile { file_id: self.file, value: self.match_expr.clone().into() } | 125 | InFile { file_id: self.file, value: self.match_expr.clone().into() } |
128 | } | 126 | } |
129 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 127 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -141,7 +139,7 @@ impl Diagnostic for MissingOkInTailExpr { | |||
141 | fn message(&self) -> String { | 139 | fn message(&self) -> String { |
142 | "wrap return expression in Ok".to_string() | 140 | "wrap return expression in Ok".to_string() |
143 | } | 141 | } |
144 | fn source(&self) -> InFile<SyntaxNodePtr> { | 142 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
145 | InFile { file_id: self.file, value: self.expr.clone().into() } | 143 | InFile { file_id: self.file, value: self.expr.clone().into() } |
146 | } | 144 | } |
147 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 145 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -149,16 +147,6 @@ impl Diagnostic for MissingOkInTailExpr { | |||
149 | } | 147 | } |
150 | } | 148 | } |
151 | 149 | ||
152 | impl AstDiagnostic for MissingOkInTailExpr { | ||
153 | type AST = ast::Expr; | ||
154 | |||
155 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
156 | let root = db.parse_or_expand(self.file).unwrap(); | ||
157 | let node = self.source().value.to_node(&root); | ||
158 | ast::Expr::cast(node).unwrap() | ||
159 | } | ||
160 | } | ||
161 | |||
162 | #[derive(Debug)] | 150 | #[derive(Debug)] |
163 | pub struct BreakOutsideOfLoop { | 151 | pub struct BreakOutsideOfLoop { |
164 | pub file: HirFileId, | 152 | pub file: HirFileId, |
@@ -169,7 +157,7 @@ impl Diagnostic for BreakOutsideOfLoop { | |||
169 | fn message(&self) -> String { | 157 | fn message(&self) -> String { |
170 | "break outside of loop".to_string() | 158 | "break outside of loop".to_string() |
171 | } | 159 | } |
172 | fn source(&self) -> InFile<SyntaxNodePtr> { | 160 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
173 | InFile { file_id: self.file, value: self.expr.clone().into() } | 161 | InFile { file_id: self.file, value: self.expr.clone().into() } |
174 | } | 162 | } |
175 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 163 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -177,16 +165,6 @@ impl Diagnostic for BreakOutsideOfLoop { | |||
177 | } | 165 | } |
178 | } | 166 | } |
179 | 167 | ||
180 | impl AstDiagnostic for BreakOutsideOfLoop { | ||
181 | type AST = ast::Expr; | ||
182 | |||
183 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
184 | let root = db.parse_or_expand(self.file).unwrap(); | ||
185 | let node = self.source().value.to_node(&root); | ||
186 | ast::Expr::cast(node).unwrap() | ||
187 | } | ||
188 | } | ||
189 | |||
190 | #[derive(Debug)] | 168 | #[derive(Debug)] |
191 | pub struct MissingUnsafe { | 169 | pub struct MissingUnsafe { |
192 | pub file: HirFileId, | 170 | pub file: HirFileId, |
@@ -197,7 +175,7 @@ impl Diagnostic for MissingUnsafe { | |||
197 | fn message(&self) -> String { | 175 | fn message(&self) -> String { |
198 | format!("This operation is unsafe and requires an unsafe function or block") | 176 | format!("This operation is unsafe and requires an unsafe function or block") |
199 | } | 177 | } |
200 | fn source(&self) -> InFile<SyntaxNodePtr> { | 178 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
201 | InFile { file_id: self.file, value: self.expr.clone().into() } | 179 | InFile { file_id: self.file, value: self.expr.clone().into() } |
202 | } | 180 | } |
203 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 181 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -205,16 +183,6 @@ impl Diagnostic for MissingUnsafe { | |||
205 | } | 183 | } |
206 | } | 184 | } |
207 | 185 | ||
208 | impl AstDiagnostic for MissingUnsafe { | ||
209 | type AST = ast::Expr; | ||
210 | |||
211 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
212 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | ||
213 | let node = self.source().value.to_node(&root); | ||
214 | ast::Expr::cast(node).unwrap() | ||
215 | } | ||
216 | } | ||
217 | |||
218 | #[derive(Debug)] | 186 | #[derive(Debug)] |
219 | pub struct MismatchedArgCount { | 187 | pub struct MismatchedArgCount { |
220 | pub file: HirFileId, | 188 | pub file: HirFileId, |
@@ -228,7 +196,7 @@ impl Diagnostic for MismatchedArgCount { | |||
228 | let s = if self.expected == 1 { "" } else { "s" }; | 196 | let s = if self.expected == 1 { "" } else { "s" }; |
229 | format!("Expected {} argument{}, found {}", self.expected, s, self.found) | 197 | format!("Expected {} argument{}, found {}", self.expected, s, self.found) |
230 | } | 198 | } |
231 | fn source(&self) -> InFile<SyntaxNodePtr> { | 199 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
232 | InFile { file_id: self.file, value: self.call_expr.clone().into() } | 200 | InFile { file_id: self.file, value: self.call_expr.clone().into() } |
233 | } | 201 | } |
234 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 202 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -239,19 +207,13 @@ impl Diagnostic for MismatchedArgCount { | |||
239 | } | 207 | } |
240 | } | 208 | } |
241 | 209 | ||
242 | impl AstDiagnostic for MismatchedArgCount { | ||
243 | type AST = ast::CallExpr; | ||
244 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
245 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | ||
246 | let node = self.source().value.to_node(&root); | ||
247 | ast::CallExpr::cast(node).unwrap() | ||
248 | } | ||
249 | } | ||
250 | |||
251 | #[cfg(test)] | 210 | #[cfg(test)] |
252 | mod tests { | 211 | mod tests { |
253 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId}; | 212 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId}; |
254 | use hir_expand::diagnostics::{Diagnostic, DiagnosticSinkBuilder}; | 213 | use hir_expand::{ |
214 | db::AstDatabase, | ||
215 | diagnostics::{Diagnostic, DiagnosticSinkBuilder}, | ||
216 | }; | ||
255 | use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; | 217 | use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; |
256 | use ra_syntax::{TextRange, TextSize}; | 218 | use ra_syntax::{TextRange, TextSize}; |
257 | use rustc_hash::FxHashMap; | 219 | use rustc_hash::FxHashMap; |
@@ -296,9 +258,11 @@ mod tests { | |||
296 | 258 | ||
297 | let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); | 259 | let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); |
298 | db.diagnostics(|d| { | 260 | db.diagnostics(|d| { |
299 | // FXIME: macros... | 261 | let src = d.display_source(); |
300 | let file_id = d.source().file_id.original_file(&db); | 262 | let root = db.parse_or_expand(src.file_id).unwrap(); |
301 | let range = d.syntax_node(&db).text_range(); | 263 | // FIXME: macros... |
264 | let file_id = src.file_id.original_file(&db); | ||
265 | let range = src.value.to_node(&root).text_range(); | ||
302 | let message = d.message().to_owned(); | 266 | let message = d.message().to_owned(); |
303 | actual.entry(file_id).or_default().push((range, message)); | 267 | actual.entry(file_id).or_default().push((range, message)); |
304 | }); | 268 | }); |
@@ -326,8 +290,8 @@ struct S { foo: i32, bar: () } | |||
326 | impl S { | 290 | impl S { |
327 | fn new() -> S { | 291 | fn new() -> S { |
328 | S { | 292 | S { |
329 | //^... Missing structure fields: | 293 | //^ Missing structure fields: |
330 | //| - bar | 294 | //| - bar |
331 | foo: 92, | 295 | foo: 92, |
332 | baz: 62, | 296 | baz: 62, |
333 | //^^^^^^^ no such field | 297 | //^^^^^^^ no such field |
@@ -448,8 +412,8 @@ impl Foo { | |||
448 | struct S { foo: i32, bar: () } | 412 | struct S { foo: i32, bar: () } |
449 | fn baz(s: S) { | 413 | fn baz(s: S) { |
450 | let S { foo: _ } = s; | 414 | let S { foo: _ } = s; |
451 | //^^^^^^^^^^ Missing structure fields: | 415 | //^ Missing structure fields: |
452 | // | - bar | 416 | //| - bar |
453 | } | 417 | } |
454 | "#, | 418 | "#, |
455 | ); | 419 | ); |
diff --git a/crates/ra_hir_ty/src/diagnostics/expr.rs b/crates/ra_hir_ty/src/diagnostics/expr.rs index 95bbf2d95..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,7 +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_expr.path().map(|path| AstPtr::new(&path)), | ||
113 | missed_fields, | 114 | missed_fields, |
114 | }) | 115 | }) |
115 | } | 116 | } |
@@ -131,7 +132,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
131 | if let Some(expr) = source_ptr.value.as_ref().left() { | 132 | if let Some(expr) = source_ptr.value.as_ref().left() { |
132 | let root = source_ptr.file_syntax(db.upcast()); | 133 | let root = source_ptr.file_syntax(db.upcast()); |
133 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { | 134 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { |
134 | if let Some(field_list) = record_pat.record_pat_field_list() { | 135 | if let Some(_) = record_pat.record_pat_field_list() { |
135 | let variant_data = variant_data(db.upcast(), variant_def); | 136 | let variant_data = variant_data(db.upcast(), variant_def); |
136 | let missed_fields = missed_fields | 137 | let missed_fields = missed_fields |
137 | .into_iter() | 138 | .into_iter() |
@@ -139,7 +140,10 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
139 | .collect(); | 140 | .collect(); |
140 | self.sink.push(MissingPatFields { | 141 | self.sink.push(MissingPatFields { |
141 | file: source_ptr.file_id, | 142 | file: source_ptr.file_id, |
142 | field_list: AstPtr::new(&field_list), | 143 | field_list_parent: AstPtr::new(&record_pat), |
144 | field_list_parent_path: record_pat | ||
145 | .path() | ||
146 | .map(|path| AstPtr::new(&path)), | ||
143 | missed_fields, | 147 | missed_fields, |
144 | }) | 148 | }) |
145 | } | 149 | } |
diff --git a/crates/ra_hir_ty/src/diagnostics/match_check.rs b/crates/ra_hir_ty/src/diagnostics/match_check.rs index 507edcb7d..deca244db 100644 --- a/crates/ra_hir_ty/src/diagnostics/match_check.rs +++ b/crates/ra_hir_ty/src/diagnostics/match_check.rs | |||
@@ -1161,15 +1161,15 @@ fn main() { | |||
1161 | //^ Missing match arm | 1161 | //^ Missing match arm |
1162 | match a { | 1162 | match a { |
1163 | Either::A { } => (), | 1163 | Either::A { } => (), |
1164 | //^^^ Missing structure fields: | 1164 | //^^^^^^^^^ Missing structure fields: |
1165 | // | - foo | 1165 | // | - foo |
1166 | Either::B => (), | 1166 | Either::B => (), |
1167 | } | 1167 | } |
1168 | match a { | 1168 | match a { |
1169 | //^ Missing match arm | 1169 | //^ Missing match arm |
1170 | Either::A { } => (), | 1170 | Either::A { } => (), |
1171 | } //^^^ Missing structure fields: | 1171 | } //^^^^^^^^^ Missing structure fields: |
1172 | // | - foo | 1172 | // | - foo |
1173 | 1173 | ||
1174 | match a { | 1174 | match a { |
1175 | Either::A { foo: true } => (), | 1175 | Either::A { foo: true } => (), |