diff options
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir_def/src/diagnostics.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/diagnostics.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/diagnostics.rs | 55 | ||||
-rw-r--r-- | crates/ra_ide/src/diagnostics.rs | 31 |
5 files changed, 57 insertions, 48 deletions
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index e392130ab..1c5dc3d51 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -145,6 +145,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
145 | self.imp.original_range(node) | 145 | self.imp.original_range(node) |
146 | } | 146 | } |
147 | 147 | ||
148 | pub fn diagnostics_fix_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { | ||
149 | self.imp.diagnostics_fix_range(diagnostics) | ||
150 | } | ||
151 | |||
148 | pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { | 152 | pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { |
149 | self.imp.diagnostics_range(diagnostics) | 153 | self.imp.diagnostics_range(diagnostics) |
150 | } | 154 | } |
@@ -376,6 +380,13 @@ impl<'db> SemanticsImpl<'db> { | |||
376 | original_range(self.db, node.as_ref()) | 380 | original_range(self.db, node.as_ref()) |
377 | } | 381 | } |
378 | 382 | ||
383 | fn diagnostics_fix_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { | ||
384 | let src = diagnostics.fix_source(); | ||
385 | let root = self.db.parse_or_expand(src.file_id).unwrap(); | ||
386 | let node = src.value.to_node(&root); | ||
387 | original_range(self.db, src.with_value(&node)) | ||
388 | } | ||
389 | |||
379 | fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { | 390 | fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { |
380 | let src = diagnostics.source(); | 391 | let src = diagnostics.source(); |
381 | let root = self.db.parse_or_expand(src.file_id).unwrap(); | 392 | let root = self.db.parse_or_expand(src.file_id).unwrap(); |
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs index 30db48f86..e53269589 100644 --- a/crates/ra_hir_def/src/diagnostics.rs +++ b/crates/ra_hir_def/src/diagnostics.rs | |||
@@ -18,7 +18,7 @@ impl Diagnostic for UnresolvedModule { | |||
18 | fn message(&self) -> String { | 18 | fn message(&self) -> String { |
19 | "unresolved module".to_string() | 19 | "unresolved module".to_string() |
20 | } | 20 | } |
21 | fn source(&self) -> InFile<SyntaxNodePtr> { | 21 | fn fix_source(&self) -> InFile<SyntaxNodePtr> { |
22 | InFile::new(self.file, self.decl.clone().into()) | 22 | InFile::new(self.file, self.decl.clone().into()) |
23 | } | 23 | } |
24 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 24 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs index ffeca5e82..074a8c45e 100644 --- a/crates/ra_hir_expand/src/diagnostics.rs +++ b/crates/ra_hir_expand/src/diagnostics.rs | |||
@@ -22,9 +22,9 @@ use crate::{db::AstDatabase, InFile}; | |||
22 | 22 | ||
23 | pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { | 23 | pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { |
24 | fn message(&self) -> String; | 24 | fn message(&self) -> String; |
25 | fn source(&self) -> InFile<SyntaxNodePtr>; | 25 | fn fix_source(&self) -> InFile<SyntaxNodePtr>; |
26 | fn highlighting_source(&self) -> InFile<SyntaxNodePtr> { | 26 | fn source(&self) -> InFile<SyntaxNodePtr> { |
27 | self.source() | 27 | self.fix_source() |
28 | } | 28 | } |
29 | fn as_any(&self) -> &(dyn Any + Send + 'static); | 29 | fn as_any(&self) -> &(dyn Any + Send + 'static); |
30 | fn is_experimental(&self) -> bool { | 30 | fn is_experimental(&self) -> bool { |
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 73d241434..a4cede81d 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs | |||
@@ -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 fix_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 | ||
@@ -50,9 +50,8 @@ impl 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 ast(&self, db: &dyn AstDatabase) -> Self::AST { |
53 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | 53 | let root = db.parse_or_expand(self.file).unwrap(); |
54 | let node = self.source().value.to_node(&root); | 54 | self.field.to_node(&root) |
55 | ast::RecordExprField::cast(node).unwrap() | ||
56 | } | 55 | } |
57 | } | 56 | } |
58 | 57 | ||
@@ -72,19 +71,19 @@ impl Diagnostic for MissingFields { | |||
72 | } | 71 | } |
73 | buf | 72 | buf |
74 | } | 73 | } |
75 | fn source(&self) -> InFile<SyntaxNodePtr> { | 74 | fn fix_source(&self) -> InFile<SyntaxNodePtr> { |
76 | InFile { file_id: self.file, value: self.field_list.clone().into() } | 75 | InFile { file_id: self.file, value: self.field_list.clone().into() } |
77 | } | 76 | } |
78 | 77 | ||
79 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 78 | fn source(&self) -> InFile<SyntaxNodePtr> { |
80 | self | ||
81 | } | ||
82 | |||
83 | fn highlighting_source(&self) -> InFile<SyntaxNodePtr> { | ||
84 | self.list_parent_path | 79 | self.list_parent_path |
85 | .clone() | 80 | .clone() |
86 | .map(|path| InFile { file_id: self.file, value: path.into() }) | 81 | .map(|path| InFile { file_id: self.file, value: path.into() }) |
87 | .unwrap_or_else(|| self.source()) | 82 | .unwrap_or_else(|| self.fix_source()) |
83 | } | ||
84 | |||
85 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
86 | self | ||
88 | } | 87 | } |
89 | } | 88 | } |
90 | 89 | ||
@@ -112,7 +111,7 @@ impl Diagnostic for MissingPatFields { | |||
112 | } | 111 | } |
113 | buf | 112 | buf |
114 | } | 113 | } |
115 | fn source(&self) -> InFile<SyntaxNodePtr> { | 114 | fn fix_source(&self) -> InFile<SyntaxNodePtr> { |
116 | InFile { file_id: self.file, value: self.field_list.clone().into() } | 115 | InFile { file_id: self.file, value: self.field_list.clone().into() } |
117 | } | 116 | } |
118 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 117 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -131,7 +130,7 @@ impl Diagnostic for MissingMatchArms { | |||
131 | fn message(&self) -> String { | 130 | fn message(&self) -> String { |
132 | String::from("Missing match arm") | 131 | String::from("Missing match arm") |
133 | } | 132 | } |
134 | fn source(&self) -> InFile<SyntaxNodePtr> { | 133 | fn fix_source(&self) -> InFile<SyntaxNodePtr> { |
135 | InFile { file_id: self.file, value: self.match_expr.clone().into() } | 134 | InFile { file_id: self.file, value: self.match_expr.clone().into() } |
136 | } | 135 | } |
137 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 136 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -149,7 +148,7 @@ impl Diagnostic for MissingOkInTailExpr { | |||
149 | fn message(&self) -> String { | 148 | fn message(&self) -> String { |
150 | "wrap return expression in Ok".to_string() | 149 | "wrap return expression in Ok".to_string() |
151 | } | 150 | } |
152 | fn source(&self) -> InFile<SyntaxNodePtr> { | 151 | fn fix_source(&self) -> InFile<SyntaxNodePtr> { |
153 | InFile { file_id: self.file, value: self.expr.clone().into() } | 152 | InFile { file_id: self.file, value: self.expr.clone().into() } |
154 | } | 153 | } |
155 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 154 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -162,8 +161,7 @@ impl AstDiagnostic for MissingOkInTailExpr { | |||
162 | 161 | ||
163 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | 162 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { |
164 | let root = db.parse_or_expand(self.file).unwrap(); | 163 | let root = db.parse_or_expand(self.file).unwrap(); |
165 | let node = self.source().value.to_node(&root); | 164 | self.expr.to_node(&root) |
166 | ast::Expr::cast(node).unwrap() | ||
167 | } | 165 | } |
168 | } | 166 | } |
169 | 167 | ||
@@ -177,7 +175,7 @@ impl Diagnostic for BreakOutsideOfLoop { | |||
177 | fn message(&self) -> String { | 175 | fn message(&self) -> String { |
178 | "break outside of loop".to_string() | 176 | "break outside of loop".to_string() |
179 | } | 177 | } |
180 | fn source(&self) -> InFile<SyntaxNodePtr> { | 178 | fn fix_source(&self) -> InFile<SyntaxNodePtr> { |
181 | InFile { file_id: self.file, value: self.expr.clone().into() } | 179 | InFile { file_id: self.file, value: self.expr.clone().into() } |
182 | } | 180 | } |
183 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 181 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -190,8 +188,7 @@ impl AstDiagnostic for BreakOutsideOfLoop { | |||
190 | 188 | ||
191 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | 189 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { |
192 | let root = db.parse_or_expand(self.file).unwrap(); | 190 | let root = db.parse_or_expand(self.file).unwrap(); |
193 | let node = self.source().value.to_node(&root); | 191 | self.expr.to_node(&root) |
194 | ast::Expr::cast(node).unwrap() | ||
195 | } | 192 | } |
196 | } | 193 | } |
197 | 194 | ||
@@ -205,7 +202,7 @@ impl Diagnostic for MissingUnsafe { | |||
205 | fn message(&self) -> String { | 202 | fn message(&self) -> String { |
206 | format!("This operation is unsafe and requires an unsafe function or block") | 203 | format!("This operation is unsafe and requires an unsafe function or block") |
207 | } | 204 | } |
208 | fn source(&self) -> InFile<SyntaxNodePtr> { | 205 | fn fix_source(&self) -> InFile<SyntaxNodePtr> { |
209 | InFile { file_id: self.file, value: self.expr.clone().into() } | 206 | InFile { file_id: self.file, value: self.expr.clone().into() } |
210 | } | 207 | } |
211 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 208 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -217,9 +214,8 @@ impl AstDiagnostic for MissingUnsafe { | |||
217 | type AST = ast::Expr; | 214 | type AST = ast::Expr; |
218 | 215 | ||
219 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | 216 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { |
220 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | 217 | let root = db.parse_or_expand(self.file).unwrap(); |
221 | let node = self.source().value.to_node(&root); | 218 | self.expr.to_node(&root) |
222 | ast::Expr::cast(node).unwrap() | ||
223 | } | 219 | } |
224 | } | 220 | } |
225 | 221 | ||
@@ -236,7 +232,7 @@ impl Diagnostic for MismatchedArgCount { | |||
236 | let s = if self.expected == 1 { "" } else { "s" }; | 232 | let s = if self.expected == 1 { "" } else { "s" }; |
237 | format!("Expected {} argument{}, found {}", self.expected, s, self.found) | 233 | format!("Expected {} argument{}, found {}", self.expected, s, self.found) |
238 | } | 234 | } |
239 | fn source(&self) -> InFile<SyntaxNodePtr> { | 235 | fn fix_source(&self) -> InFile<SyntaxNodePtr> { |
240 | InFile { file_id: self.file, value: self.call_expr.clone().into() } | 236 | InFile { file_id: self.file, value: self.call_expr.clone().into() } |
241 | } | 237 | } |
242 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 238 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -250,7 +246,7 @@ impl Diagnostic for MismatchedArgCount { | |||
250 | impl AstDiagnostic for MismatchedArgCount { | 246 | impl AstDiagnostic for MismatchedArgCount { |
251 | type AST = ast::CallExpr; | 247 | type AST = ast::CallExpr; |
252 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | 248 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { |
253 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | 249 | let root = db.parse_or_expand(self.file).unwrap(); |
254 | let node = self.source().value.to_node(&root); | 250 | let node = self.source().value.to_node(&root); |
255 | ast::CallExpr::cast(node).unwrap() | 251 | ast::CallExpr::cast(node).unwrap() |
256 | } | 252 | } |
@@ -308,12 +304,11 @@ mod tests { | |||
308 | let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); | 304 | let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); |
309 | db.diagnostics(|d| { | 305 | db.diagnostics(|d| { |
310 | // FXIME: macros... | 306 | // FXIME: macros... |
311 | let file_id = d.source().file_id.original_file(&db); | 307 | let source = d.source(); |
312 | let highlighting_source = d.highlighting_source(); | 308 | let root = db.parse_or_expand(source.file_id).unwrap(); |
313 | let node = db.parse_or_expand(highlighting_source.file_id).unwrap(); | 309 | let range = source.value.to_node(&root).text_range(); |
314 | let range = highlighting_source.value.to_node(&node).text_range(); | ||
315 | let message = d.message().to_owned(); | 310 | let message = d.message().to_owned(); |
316 | actual.entry(file_id).or_default().push((range, message)); | 311 | actual.entry(source.file_id.original_file(&db)).or_default().push((range, message)); |
317 | }); | 312 | }); |
318 | 313 | ||
319 | for (file_id, diags) in actual.iter_mut() { | 314 | for (file_id, diags) in actual.iter_mut() { |
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index e847df6ea..0d2ff17e1 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs | |||
@@ -54,18 +54,19 @@ pub(crate) fn diagnostics( | |||
54 | let res = RefCell::new(res); | 54 | let res = RefCell::new(res); |
55 | let mut sink = DiagnosticSinkBuilder::new() | 55 | let mut sink = DiagnosticSinkBuilder::new() |
56 | .on::<hir::diagnostics::UnresolvedModule, _>(|d| { | 56 | .on::<hir::diagnostics::UnresolvedModule, _>(|d| { |
57 | let original_file = d.source().file_id.original_file(db); | ||
58 | let fix = Fix::new( | 57 | let fix = Fix::new( |
59 | "Create module", | 58 | "Create module", |
60 | FileSystemEdit::CreateFile { anchor: original_file, dst: d.candidate.clone() } | 59 | FileSystemEdit::CreateFile { |
61 | .into(), | 60 | anchor: d.file.original_file(db), |
61 | dst: d.candidate.clone(), | ||
62 | } | ||
63 | .into(), | ||
62 | ); | 64 | ); |
63 | let range = sema.diagnostics_range(d).range; | ||
64 | res.borrow_mut().push(Diagnostic { | 65 | res.borrow_mut().push(Diagnostic { |
65 | range, | 66 | range: sema.diagnostics_range(d).range, |
66 | message: d.message(), | 67 | message: d.message(), |
67 | severity: Severity::Error, | 68 | severity: Severity::Error, |
68 | fix: Some((fix, range)), | 69 | fix: Some((fix, sema.diagnostics_fix_range(d).range)), |
69 | }) | 70 | }) |
70 | }) | 71 | }) |
71 | .on::<hir::diagnostics::MissingFields, _>(|d| { | 72 | .on::<hir::diagnostics::MissingFields, _>(|d| { |
@@ -94,12 +95,12 @@ pub(crate) fn diagnostics( | |||
94 | }; | 95 | }; |
95 | Some(( | 96 | Some(( |
96 | Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into()), | 97 | Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into()), |
97 | sema.diagnostics_range(d).range, | 98 | sema.diagnostics_fix_range(d).range, |
98 | )) | 99 | )) |
99 | }; | 100 | }; |
100 | 101 | ||
101 | res.borrow_mut().push(Diagnostic { | 102 | res.borrow_mut().push(Diagnostic { |
102 | range: d.highlighting_source().file_syntax(db).text_range(), | 103 | range: sema.diagnostics_range(d).range, |
103 | message: d.message(), | 104 | message: d.message(), |
104 | severity: Severity::Error, | 105 | severity: Severity::Error, |
105 | fix, | 106 | fix, |
@@ -110,21 +111,23 @@ pub(crate) fn diagnostics( | |||
110 | let replacement = format!("Ok({})", node.syntax()); | 111 | let replacement = format!("Ok({})", node.syntax()); |
111 | let edit = TextEdit::replace(node.syntax().text_range(), replacement); | 112 | let edit = TextEdit::replace(node.syntax().text_range(), replacement); |
112 | let source_change = SourceFileEdit { file_id, edit }.into(); | 113 | let source_change = SourceFileEdit { file_id, edit }.into(); |
113 | let range = sema.diagnostics_range(d).range; | ||
114 | res.borrow_mut().push(Diagnostic { | 114 | res.borrow_mut().push(Diagnostic { |
115 | range, | 115 | range: sema.diagnostics_range(d).range, |
116 | message: d.message(), | 116 | message: d.message(), |
117 | severity: Severity::Error, | 117 | severity: Severity::Error, |
118 | fix: Some((Fix::new("Wrap with ok", source_change), range)), | 118 | fix: Some(( |
119 | Fix::new("Wrap with ok", source_change), | ||
120 | sema.diagnostics_fix_range(d).range, | ||
121 | )), | ||
119 | }) | 122 | }) |
120 | }) | 123 | }) |
121 | .on::<hir::diagnostics::NoSuchField, _>(|d| { | 124 | .on::<hir::diagnostics::NoSuchField, _>(|d| { |
122 | let range = sema.diagnostics_range(d).range; | ||
123 | res.borrow_mut().push(Diagnostic { | 125 | res.borrow_mut().push(Diagnostic { |
124 | range, | 126 | range: sema.diagnostics_range(d).range, |
125 | message: d.message(), | 127 | message: d.message(), |
126 | severity: Severity::Error, | 128 | severity: Severity::Error, |
127 | fix: missing_struct_field_fix(&sema, file_id, d).map(|fix| (fix, range)), | 129 | fix: missing_struct_field_fix(&sema, file_id, d) |
130 | .map(|fix| (fix, sema.diagnostics_fix_range(d).range)), | ||
128 | }) | 131 | }) |
129 | }) | 132 | }) |
130 | // Only collect experimental diagnostics when they're enabled. | 133 | // Only collect experimental diagnostics when they're enabled. |