aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/diagnostics.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src/diagnostics.rs')
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs128
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;
6use std::any::Any; 6use std::any::Any;
7 7
8use hir_def::DefWithBodyId; 8use hir_def::DefWithBodyId;
9use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; 9use hir_expand::diagnostics::{Diagnostic, DiagnosticSink};
10use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; 10use hir_expand::{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;
@@ -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
53impl 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)]
64pub struct MissingFields { 54pub 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
89impl 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)]
100pub struct MissingPatFields { 90pub 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
168impl 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)]
179pub struct BreakOutsideOfLoop { 167pub 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
199impl 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)]
210pub struct MissingUnsafe { 188pub 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
230impl 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)]
241pub struct MismatchedArgCount { 209pub 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
267impl 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)]
277mod tests { 236mod 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: () }
351impl S { 315impl 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 {
473struct S { foo: i32, bar: () } 437struct S { foo: i32, bar: () }
474fn baz(s: S) { 438fn 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 );