aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide')
-rw-r--r--crates/ra_ide/src/diagnostics.rs28
-rw-r--r--crates/ra_ide/src/diagnostics/diagnostics_with_fix.rs46
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 @@
7use std::cell::RefCell; 7use std::cell::RefCell;
8 8
9use hir::{ 9use 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};
13use itertools::Itertools; 14use itertools::Itertools;
14use ra_db::SourceDatabase; 15use ra_db::{SourceDatabase, Upcast};
15use ra_ide_db::RootDatabase; 16use ra_ide_db::RootDatabase;
16use ra_prof::profile; 17use ra_prof::profile;
17use ra_syntax::{ 18use ra_syntax::{
@@ -23,6 +24,9 @@ use ra_text_edit::{TextEdit, TextEditBuilder};
23 24
24use crate::{Diagnostic, FileId, FileSystemEdit, Fix, SourceFileEdit}; 25use crate::{Diagnostic, FileId, FileSystemEdit, Fix, SourceFileEdit};
25 26
27mod diagnostics_with_fix;
28use diagnostics_with_fix::DiagnosticWithFix;
29
26#[derive(Debug, Copy, Clone)] 30#[derive(Debug, Copy, Clone)]
27pub enum Severity { 31pub 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
171fn 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
167fn missing_struct_field_fix( 181fn 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 @@
1use hir::{
2 db::AstDatabase,
3 diagnostics::{MissingFields, MissingOkInTailExpr, NoSuchField, UnresolvedModule},
4};
5use ra_syntax::ast;
6
7// TODO kb
8pub trait DiagnosticWithFix {
9 type AST;
10 fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST>;
11}
12
13impl 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
21impl 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
30impl 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
39impl 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}