diff options
Diffstat (limited to 'crates/ra_hir_ty/src/diagnostics.rs')
-rw-r--r-- | crates/ra_hir_ty/src/diagnostics.rs | 128 |
1 files changed, 46 insertions, 82 deletions
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 56acd3bbf..45e31033e 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; |
@@ -41,7 +41,7 @@ impl Diagnostic for NoSuchField { | |||
41 | "no such field".to_string() | 41 | "no such field".to_string() |
42 | } | 42 | } |
43 | 43 | ||
44 | fn source(&self) -> InFile<SyntaxNodePtr> { | 44 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
45 | InFile::new(self.file, self.field.clone().into()) | 45 | InFile::new(self.file, self.field.clone().into()) |
46 | } | 46 | } |
47 | 47 | ||
@@ -50,20 +50,11 @@ impl Diagnostic for NoSuchField { | |||
50 | } | 50 | } |
51 | } | 51 | } |
52 | 52 | ||
53 | impl AstDiagnostic for NoSuchField { | ||
54 | type AST = ast::RecordExprField; | ||
55 | |||
56 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
57 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | ||
58 | let node = self.source().value.to_node(&root); | ||
59 | ast::RecordExprField::cast(node).unwrap() | ||
60 | } | ||
61 | } | ||
62 | |||
63 | #[derive(Debug)] | 53 | #[derive(Debug)] |
64 | pub struct MissingFields { | 54 | pub struct MissingFields { |
65 | pub file: HirFileId, | 55 | pub file: HirFileId, |
66 | pub field_list: AstPtr<ast::RecordExprFieldList>, | 56 | pub field_list_parent: AstPtr<ast::RecordExpr>, |
57 | pub field_list_parent_path: Option<AstPtr<ast::Path>>, | ||
67 | pub missed_fields: Vec<Name>, | 58 | pub missed_fields: Vec<Name>, |
68 | } | 59 | } |
69 | 60 | ||
@@ -78,28 +69,28 @@ impl Diagnostic for MissingFields { | |||
78 | } | 69 | } |
79 | buf | 70 | buf |
80 | } | 71 | } |
81 | fn source(&self) -> InFile<SyntaxNodePtr> { | 72 | |
82 | InFile { file_id: self.file, value: self.field_list.clone().into() } | 73 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
74 | InFile { | ||
75 | file_id: self.file, | ||
76 | value: self | ||
77 | .field_list_parent_path | ||
78 | .clone() | ||
79 | .map(SyntaxNodePtr::from) | ||
80 | .unwrap_or_else(|| self.field_list_parent.clone().into()), | ||
81 | } | ||
83 | } | 82 | } |
83 | |||
84 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 84 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
85 | self | 85 | self |
86 | } | 86 | } |
87 | } | 87 | } |
88 | 88 | ||
89 | impl AstDiagnostic for MissingFields { | ||
90 | type AST = ast::RecordExprFieldList; | ||
91 | |||
92 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
93 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | ||
94 | let node = self.source().value.to_node(&root); | ||
95 | ast::RecordExprFieldList::cast(node).unwrap() | ||
96 | } | ||
97 | } | ||
98 | |||
99 | #[derive(Debug)] | 89 | #[derive(Debug)] |
100 | pub struct MissingPatFields { | 90 | pub struct MissingPatFields { |
101 | pub file: HirFileId, | 91 | pub file: HirFileId, |
102 | pub field_list: AstPtr<ast::RecordPatFieldList>, | 92 | pub field_list_parent: AstPtr<ast::RecordPat>, |
93 | pub field_list_parent_path: Option<AstPtr<ast::Path>>, | ||
103 | pub missed_fields: Vec<Name>, | 94 | pub missed_fields: Vec<Name>, |
104 | } | 95 | } |
105 | 96 | ||
@@ -114,8 +105,15 @@ impl Diagnostic for MissingPatFields { | |||
114 | } | 105 | } |
115 | buf | 106 | buf |
116 | } | 107 | } |
117 | fn source(&self) -> InFile<SyntaxNodePtr> { | 108 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
118 | InFile { file_id: self.file, value: self.field_list.clone().into() } | 109 | InFile { |
110 | file_id: self.file, | ||
111 | value: self | ||
112 | .field_list_parent_path | ||
113 | .clone() | ||
114 | .map(SyntaxNodePtr::from) | ||
115 | .unwrap_or_else(|| self.field_list_parent.clone().into()), | ||
116 | } | ||
119 | } | 117 | } |
120 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 118 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
121 | self | 119 | self |
@@ -136,7 +134,7 @@ impl Diagnostic for MissingMatchArms { | |||
136 | fn message(&self) -> String { | 134 | fn message(&self) -> String { |
137 | String::from("Missing match arm") | 135 | String::from("Missing match arm") |
138 | } | 136 | } |
139 | fn source(&self) -> InFile<SyntaxNodePtr> { | 137 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
140 | InFile { file_id: self.file, value: self.match_expr.clone().into() } | 138 | InFile { file_id: self.file, value: self.match_expr.clone().into() } |
141 | } | 139 | } |
142 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 140 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -157,7 +155,7 @@ impl Diagnostic for MissingOkInTailExpr { | |||
157 | fn message(&self) -> String { | 155 | fn message(&self) -> String { |
158 | "wrap return expression in Ok".to_string() | 156 | "wrap return expression in Ok".to_string() |
159 | } | 157 | } |
160 | fn source(&self) -> InFile<SyntaxNodePtr> { | 158 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
161 | InFile { file_id: self.file, value: self.expr.clone().into() } | 159 | InFile { file_id: self.file, value: self.expr.clone().into() } |
162 | } | 160 | } |
163 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 161 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -165,16 +163,6 @@ impl Diagnostic for MissingOkInTailExpr { | |||
165 | } | 163 | } |
166 | } | 164 | } |
167 | 165 | ||
168 | impl AstDiagnostic for MissingOkInTailExpr { | ||
169 | type AST = ast::Expr; | ||
170 | |||
171 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
172 | let root = db.parse_or_expand(self.file).unwrap(); | ||
173 | let node = self.source().value.to_node(&root); | ||
174 | ast::Expr::cast(node).unwrap() | ||
175 | } | ||
176 | } | ||
177 | |||
178 | #[derive(Debug)] | 166 | #[derive(Debug)] |
179 | pub struct BreakOutsideOfLoop { | 167 | pub struct BreakOutsideOfLoop { |
180 | pub file: HirFileId, | 168 | pub file: HirFileId, |
@@ -188,7 +176,7 @@ impl Diagnostic for BreakOutsideOfLoop { | |||
188 | fn message(&self) -> String { | 176 | fn message(&self) -> String { |
189 | "break outside of loop".to_string() | 177 | "break outside of loop".to_string() |
190 | } | 178 | } |
191 | fn source(&self) -> InFile<SyntaxNodePtr> { | 179 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
192 | InFile { file_id: self.file, value: self.expr.clone().into() } | 180 | InFile { file_id: self.file, value: self.expr.clone().into() } |
193 | } | 181 | } |
194 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 182 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -196,16 +184,6 @@ impl Diagnostic for BreakOutsideOfLoop { | |||
196 | } | 184 | } |
197 | } | 185 | } |
198 | 186 | ||
199 | impl AstDiagnostic for BreakOutsideOfLoop { | ||
200 | type AST = ast::Expr; | ||
201 | |||
202 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
203 | let root = db.parse_or_expand(self.file).unwrap(); | ||
204 | let node = self.source().value.to_node(&root); | ||
205 | ast::Expr::cast(node).unwrap() | ||
206 | } | ||
207 | } | ||
208 | |||
209 | #[derive(Debug)] | 187 | #[derive(Debug)] |
210 | pub struct MissingUnsafe { | 188 | pub struct MissingUnsafe { |
211 | pub file: HirFileId, | 189 | pub file: HirFileId, |
@@ -219,7 +197,7 @@ impl Diagnostic for MissingUnsafe { | |||
219 | fn message(&self) -> String { | 197 | fn message(&self) -> String { |
220 | format!("This operation is unsafe and requires an unsafe function or block") | 198 | format!("This operation is unsafe and requires an unsafe function or block") |
221 | } | 199 | } |
222 | fn source(&self) -> InFile<SyntaxNodePtr> { | 200 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
223 | InFile { file_id: self.file, value: self.expr.clone().into() } | 201 | InFile { file_id: self.file, value: self.expr.clone().into() } |
224 | } | 202 | } |
225 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 203 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -227,16 +205,6 @@ impl Diagnostic for MissingUnsafe { | |||
227 | } | 205 | } |
228 | } | 206 | } |
229 | 207 | ||
230 | impl AstDiagnostic for MissingUnsafe { | ||
231 | type AST = ast::Expr; | ||
232 | |||
233 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
234 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | ||
235 | let node = self.source().value.to_node(&root); | ||
236 | ast::Expr::cast(node).unwrap() | ||
237 | } | ||
238 | } | ||
239 | |||
240 | #[derive(Debug)] | 208 | #[derive(Debug)] |
241 | pub struct MismatchedArgCount { | 209 | pub struct MismatchedArgCount { |
242 | pub file: HirFileId, | 210 | pub file: HirFileId, |
@@ -253,7 +221,7 @@ impl Diagnostic for MismatchedArgCount { | |||
253 | let s = if self.expected == 1 { "" } else { "s" }; | 221 | let s = if self.expected == 1 { "" } else { "s" }; |
254 | format!("Expected {} argument{}, found {}", self.expected, s, self.found) | 222 | format!("Expected {} argument{}, found {}", self.expected, s, self.found) |
255 | } | 223 | } |
256 | fn source(&self) -> InFile<SyntaxNodePtr> { | 224 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
257 | InFile { file_id: self.file, value: self.call_expr.clone().into() } | 225 | InFile { file_id: self.file, value: self.call_expr.clone().into() } |
258 | } | 226 | } |
259 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 227 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -264,19 +232,13 @@ impl Diagnostic for MismatchedArgCount { | |||
264 | } | 232 | } |
265 | } | 233 | } |
266 | 234 | ||
267 | impl AstDiagnostic for MismatchedArgCount { | ||
268 | type AST = ast::CallExpr; | ||
269 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
270 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | ||
271 | let node = self.source().value.to_node(&root); | ||
272 | ast::CallExpr::cast(node).unwrap() | ||
273 | } | ||
274 | } | ||
275 | |||
276 | #[cfg(test)] | 235 | #[cfg(test)] |
277 | mod tests { | 236 | mod tests { |
278 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId}; | 237 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId}; |
279 | use hir_expand::diagnostics::{Diagnostic, DiagnosticSinkBuilder}; | 238 | use hir_expand::{ |
239 | db::AstDatabase, | ||
240 | diagnostics::{Diagnostic, DiagnosticSinkBuilder}, | ||
241 | }; | ||
280 | use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; | 242 | use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; |
281 | use ra_syntax::{TextRange, TextSize}; | 243 | use ra_syntax::{TextRange, TextSize}; |
282 | use rustc_hash::FxHashMap; | 244 | use rustc_hash::FxHashMap; |
@@ -321,9 +283,11 @@ mod tests { | |||
321 | 283 | ||
322 | let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); | 284 | let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); |
323 | db.diagnostics(|d| { | 285 | db.diagnostics(|d| { |
324 | // FXIME: macros... | 286 | let src = d.display_source(); |
325 | let file_id = d.source().file_id.original_file(&db); | 287 | let root = db.parse_or_expand(src.file_id).unwrap(); |
326 | let range = d.syntax_node(&db).text_range(); | 288 | // FIXME: macros... |
289 | let file_id = src.file_id.original_file(&db); | ||
290 | let range = src.value.to_node(&root).text_range(); | ||
327 | let message = d.message().to_owned(); | 291 | let message = d.message().to_owned(); |
328 | actual.entry(file_id).or_default().push((range, message)); | 292 | actual.entry(file_id).or_default().push((range, message)); |
329 | }); | 293 | }); |
@@ -351,8 +315,8 @@ struct S { foo: i32, bar: () } | |||
351 | impl S { | 315 | impl S { |
352 | fn new() -> S { | 316 | fn new() -> S { |
353 | S { | 317 | S { |
354 | //^... Missing structure fields: | 318 | //^ Missing structure fields: |
355 | //| - bar | 319 | //| - bar |
356 | foo: 92, | 320 | foo: 92, |
357 | baz: 62, | 321 | baz: 62, |
358 | //^^^^^^^ no such field | 322 | //^^^^^^^ no such field |
@@ -473,8 +437,8 @@ impl Foo { | |||
473 | struct S { foo: i32, bar: () } | 437 | struct S { foo: i32, bar: () } |
474 | fn baz(s: S) { | 438 | fn baz(s: S) { |
475 | let S { foo: _ } = s; | 439 | let S { foo: _ } = s; |
476 | //^^^^^^^^^^ Missing structure fields: | 440 | //^ Missing structure fields: |
477 | // | - bar | 441 | //| - bar |
478 | } | 442 | } |
479 | "#, | 443 | "#, |
480 | ); | 444 | ); |