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 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;
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;
@@ -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
49impl 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)]
60pub struct MissingFields { 50pub 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
82impl 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)]
93pub struct MissingPatFields { 83pub 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
152impl 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)]
163pub struct BreakOutsideOfLoop { 151pub 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
180impl 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)]
191pub struct MissingUnsafe { 169pub 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
208impl 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)]
219pub struct MismatchedArgCount { 187pub 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
242impl 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)]
252mod tests { 211mod 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: () }
326impl S { 290impl 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 {
448struct S { foo: i32, bar: () } 412struct S { foo: i32, bar: () }
449fn baz(s: S) { 413fn 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 );