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.rs97
1 files changed, 38 insertions, 59 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 });