diff options
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r-- | crates/ra_ide/src/diagnostics.rs | 28 | ||||
-rw-r--r-- | crates/ra_ide/src/diagnostics/diagnostics_with_fix.rs | 46 |
2 files changed, 67 insertions, 7 deletions
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index 043ce357b..ca1a7c1aa 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs | |||
@@ -7,11 +7,12 @@ | |||
7 | use std::cell::RefCell; | 7 | use std::cell::RefCell; |
8 | 8 | ||
9 | use hir::{ | 9 | use hir::{ |
10 | db::AstDatabase, | ||
10 | diagnostics::{Diagnostic as _, DiagnosticSinkBuilder}, | 11 | diagnostics::{Diagnostic as _, DiagnosticSinkBuilder}, |
11 | HasSource, HirDisplay, Semantics, VariantDef, | 12 | HasSource, HirDisplay, Semantics, VariantDef, |
12 | }; | 13 | }; |
13 | use itertools::Itertools; | 14 | use itertools::Itertools; |
14 | use ra_db::SourceDatabase; | 15 | use ra_db::{SourceDatabase, Upcast}; |
15 | use ra_ide_db::RootDatabase; | 16 | use ra_ide_db::RootDatabase; |
16 | use ra_prof::profile; | 17 | use ra_prof::profile; |
17 | use ra_syntax::{ | 18 | use ra_syntax::{ |
@@ -23,6 +24,9 @@ use ra_text_edit::{TextEdit, TextEditBuilder}; | |||
23 | 24 | ||
24 | use crate::{Diagnostic, FileId, FileSystemEdit, Fix, SourceFileEdit}; | 25 | use crate::{Diagnostic, FileId, FileSystemEdit, Fix, SourceFileEdit}; |
25 | 26 | ||
27 | mod diagnostics_with_fix; | ||
28 | use diagnostics_with_fix::DiagnosticWithFix; | ||
29 | |||
26 | #[derive(Debug, Copy, Clone)] | 30 | #[derive(Debug, Copy, Clone)] |
27 | pub enum Severity { | 31 | pub enum Severity { |
28 | Error, | 32 | Error, |
@@ -62,8 +66,7 @@ pub(crate) fn diagnostics( | |||
62 | } | 66 | } |
63 | .into(), | 67 | .into(), |
64 | ); | 68 | ); |
65 | let fix = sema | 69 | let fix = diagnostic_fix_source(&sema, d) |
66 | .diagnostic_fix_source(d) | ||
67 | .map(|unresolved_module| unresolved_module.syntax().text_range()) | 70 | .map(|unresolved_module| unresolved_module.syntax().text_range()) |
68 | .map(|fix_range| (fix, fix_range)); | 71 | .map(|fix_range| (fix, fix_range)); |
69 | 72 | ||
@@ -84,7 +87,7 @@ pub(crate) fn diagnostics( | |||
84 | let fix = if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) { | 87 | let fix = if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) { |
85 | None | 88 | None |
86 | } else { | 89 | } else { |
87 | sema.diagnostic_fix_source(d) | 90 | diagnostic_fix_source(&sema, d) |
88 | .and_then(|record_expr| record_expr.record_expr_field_list()) | 91 | .and_then(|record_expr| record_expr.record_expr_field_list()) |
89 | .map(|old_field_list| { | 92 | .map(|old_field_list| { |
90 | let mut new_field_list = old_field_list.clone(); | 93 | let mut new_field_list = old_field_list.clone(); |
@@ -105,6 +108,7 @@ pub(crate) fn diagnostics( | |||
105 | ( | 108 | ( |
106 | Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into()), | 109 | Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into()), |
107 | sema.original_range(&old_field_list.syntax()).range, | 110 | sema.original_range(&old_field_list.syntax()).range, |
111 | // old_field_list.syntax().text_range(), | ||
108 | ) | 112 | ) |
109 | }) | 113 | }) |
110 | }; | 114 | }; |
@@ -118,7 +122,7 @@ pub(crate) fn diagnostics( | |||
118 | Some(()) | 122 | Some(()) |
119 | }) | 123 | }) |
120 | .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| { | 124 | .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| { |
121 | let fix = sema.diagnostic_fix_source(d).map(|tail_expr| { | 125 | let fix = diagnostic_fix_source(&sema, d).map(|tail_expr| { |
122 | let tail_expr_range = tail_expr.syntax().text_range(); | 126 | let tail_expr_range = tail_expr.syntax().text_range(); |
123 | let edit = | 127 | let edit = |
124 | TextEdit::replace(tail_expr_range, format!("Ok({})", tail_expr.syntax())); | 128 | TextEdit::replace(tail_expr_range, format!("Ok({})", tail_expr.syntax())); |
@@ -140,7 +144,7 @@ pub(crate) fn diagnostics( | |||
140 | message: d.message(), | 144 | message: d.message(), |
141 | severity: Severity::Error, | 145 | severity: Severity::Error, |
142 | fix: missing_struct_field_fix(&sema, file_id, d).and_then(|fix| { | 146 | fix: missing_struct_field_fix(&sema, file_id, d).and_then(|fix| { |
143 | Some((fix, sema.diagnostic_fix_source(d)?.syntax().text_range())) | 147 | Some((fix, diagnostic_fix_source(&sema, d)?.syntax().text_range())) |
144 | }), | 148 | }), |
145 | }); | 149 | }); |
146 | Some(()) | 150 | Some(()) |
@@ -164,12 +168,22 @@ pub(crate) fn diagnostics( | |||
164 | res.into_inner() | 168 | res.into_inner() |
165 | } | 169 | } |
166 | 170 | ||
171 | fn diagnostic_fix_source<T: DiagnosticWithFix + hir::diagnostics::Diagnostic>( | ||
172 | sema: &Semantics<RootDatabase>, | ||
173 | d: &T, | ||
174 | ) -> Option<<T as DiagnosticWithFix>::AST> { | ||
175 | let file_id = d.presentation().file_id; | ||
176 | let root = sema.db.parse_or_expand(file_id)?; | ||
177 | sema.cache(root, file_id); | ||
178 | d.fix_source(sema.db.upcast()) | ||
179 | } | ||
180 | |||
167 | fn missing_struct_field_fix( | 181 | fn missing_struct_field_fix( |
168 | sema: &Semantics<RootDatabase>, | 182 | sema: &Semantics<RootDatabase>, |
169 | usage_file_id: FileId, | 183 | usage_file_id: FileId, |
170 | d: &hir::diagnostics::NoSuchField, | 184 | d: &hir::diagnostics::NoSuchField, |
171 | ) -> Option<Fix> { | 185 | ) -> Option<Fix> { |
172 | let record_expr_field = sema.diagnostic_fix_source(d)?; | 186 | let record_expr_field = diagnostic_fix_source(&sema, d)?; |
173 | 187 | ||
174 | let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?; | 188 | let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?; |
175 | let def_id = sema.resolve_variant(record_lit)?; | 189 | let def_id = sema.resolve_variant(record_lit)?; |
diff --git a/crates/ra_ide/src/diagnostics/diagnostics_with_fix.rs b/crates/ra_ide/src/diagnostics/diagnostics_with_fix.rs new file mode 100644 index 000000000..8578a90ec --- /dev/null +++ b/crates/ra_ide/src/diagnostics/diagnostics_with_fix.rs | |||
@@ -0,0 +1,46 @@ | |||
1 | use hir::{ | ||
2 | db::AstDatabase, | ||
3 | diagnostics::{MissingFields, MissingOkInTailExpr, NoSuchField, UnresolvedModule}, | ||
4 | }; | ||
5 | use ra_syntax::ast; | ||
6 | |||
7 | // TODO kb | ||
8 | pub trait DiagnosticWithFix { | ||
9 | type AST; | ||
10 | fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST>; | ||
11 | } | ||
12 | |||
13 | impl DiagnosticWithFix for UnresolvedModule { | ||
14 | type AST = ast::Module; | ||
15 | fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST> { | ||
16 | let root = db.parse_or_expand(self.file)?; | ||
17 | Some(self.decl.to_node(&root)) | ||
18 | } | ||
19 | } | ||
20 | |||
21 | impl DiagnosticWithFix for NoSuchField { | ||
22 | type AST = ast::RecordExprField; | ||
23 | |||
24 | fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST> { | ||
25 | let root = db.parse_or_expand(self.file)?; | ||
26 | Some(self.field.to_node(&root)) | ||
27 | } | ||
28 | } | ||
29 | |||
30 | impl DiagnosticWithFix for MissingFields { | ||
31 | type AST = ast::RecordExpr; | ||
32 | |||
33 | fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST> { | ||
34 | let root = db.parse_or_expand(self.file)?; | ||
35 | Some(self.field_list_parent.to_node(&root)) | ||
36 | } | ||
37 | } | ||
38 | |||
39 | impl DiagnosticWithFix for MissingOkInTailExpr { | ||
40 | type AST = ast::Expr; | ||
41 | |||
42 | fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST> { | ||
43 | let root = db.parse_or_expand(self.file)?; | ||
44 | Some(self.expr.to_node(&root)) | ||
45 | } | ||
46 | } | ||