diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/diagnostics.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir_def/src/diagnostics.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/diagnostics.rs | 19 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/diagnostics.rs | 26 | ||||
-rw-r--r-- | crates/ra_ide/src/diagnostics.rs | 87 |
6 files changed, 78 insertions, 74 deletions
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs index 266b513dc..564f6a5db 100644 --- a/crates/ra_hir/src/diagnostics.rs +++ b/crates/ra_hir/src/diagnostics.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | pub use hir_def::diagnostics::UnresolvedModule; | 2 | pub use hir_def::diagnostics::UnresolvedModule; |
3 | pub use hir_expand::diagnostics::{ | 3 | pub use hir_expand::diagnostics::{ |
4 | AstDiagnostic, Diagnostic, DiagnosticSink, DiagnosticSinkBuilder, | 4 | Diagnostic, DiagnosticSink, DiagnosticSinkBuilder, DiagnosticWithFix, |
5 | }; | 5 | }; |
6 | pub use hir_ty::diagnostics::{ | 6 | pub use hir_ty::diagnostics::{ |
7 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField, | 7 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField, |
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index b4420d378..c5bc2baff 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -8,7 +8,7 @@ use hir_def::{ | |||
8 | resolver::{self, HasResolver, Resolver}, | 8 | resolver::{self, HasResolver, Resolver}, |
9 | AsMacroCall, FunctionId, TraitId, VariantId, | 9 | AsMacroCall, FunctionId, TraitId, VariantId, |
10 | }; | 10 | }; |
11 | use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, name::AsName, ExpansionInfo}; | 11 | use hir_expand::{diagnostics::DiagnosticWithFix, hygiene::Hygiene, name::AsName, ExpansionInfo}; |
12 | use hir_ty::associated_type_shorthand_candidates; | 12 | use hir_ty::associated_type_shorthand_candidates; |
13 | use itertools::Itertools; | 13 | use itertools::Itertools; |
14 | use ra_db::{FileId, FileRange}; | 14 | use ra_db::{FileId, FileRange}; |
@@ -109,12 +109,12 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
109 | self.imp.parse(file_id) | 109 | self.imp.parse(file_id) |
110 | } | 110 | } |
111 | 111 | ||
112 | pub fn diagnostic_fix_source<T: AstDiagnostic + Diagnostic>( | 112 | pub fn diagnostic_fix_source<T: DiagnosticWithFix + Diagnostic>( |
113 | &self, | 113 | &self, |
114 | d: &T, | 114 | d: &T, |
115 | ) -> <T as AstDiagnostic>::AST { | 115 | ) -> Option<<T as DiagnosticWithFix>::AST> { |
116 | let file_id = d.presentation().file_id; | 116 | let file_id = d.presentation().file_id; |
117 | let root = self.db.parse_or_expand(file_id).unwrap(); | 117 | let root = self.db.parse_or_expand(file_id)?; |
118 | self.imp.cache(root, file_id); | 118 | self.imp.cache(root, file_id); |
119 | d.fix_source(self.db.upcast()) | 119 | d.fix_source(self.db.upcast()) |
120 | } | 120 | } |
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs index be9612846..033be683c 100644 --- a/crates/ra_hir_def/src/diagnostics.rs +++ b/crates/ra_hir_def/src/diagnostics.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | use std::any::Any; | 3 | use std::any::Any; |
4 | 4 | ||
5 | use hir_expand::diagnostics::{AstDiagnostic, Diagnostic}; | 5 | use hir_expand::diagnostics::{Diagnostic, DiagnosticWithFix}; |
6 | use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; | 6 | use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; |
7 | 7 | ||
8 | use hir_expand::{HirFileId, InFile}; | 8 | use hir_expand::{HirFileId, InFile}; |
@@ -26,10 +26,10 @@ impl Diagnostic for UnresolvedModule { | |||
26 | } | 26 | } |
27 | } | 27 | } |
28 | 28 | ||
29 | impl AstDiagnostic for UnresolvedModule { | 29 | impl DiagnosticWithFix for UnresolvedModule { |
30 | type AST = ast::Module; | 30 | type AST = ast::Module; |
31 | fn fix_source(&self, db: &dyn hir_expand::db::AstDatabase) -> Self::AST { | 31 | fn fix_source(&self, db: &dyn hir_expand::db::AstDatabase) -> Option<Self::AST> { |
32 | let root = db.parse_or_expand(self.file).unwrap(); | 32 | let root = db.parse_or_expand(self.file)?; |
33 | self.decl.to_node(&root) | 33 | Some(self.decl.to_node(&root)) |
34 | } | 34 | } |
35 | } | 35 | } |
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs index 2b74473ce..62a09a73a 100644 --- a/crates/ra_hir_expand/src/diagnostics.rs +++ b/crates/ra_hir_expand/src/diagnostics.rs | |||
@@ -29,15 +29,9 @@ pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { | |||
29 | } | 29 | } |
30 | } | 30 | } |
31 | 31 | ||
32 | pub trait AstDiagnostic { | 32 | pub trait DiagnosticWithFix { |
33 | type AST; | 33 | type AST; |
34 | fn fix_source(&self, db: &dyn AstDatabase) -> Self::AST; | 34 | fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST>; |
35 | } | ||
36 | |||
37 | impl dyn Diagnostic { | ||
38 | pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> { | ||
39 | self.as_any().downcast_ref() | ||
40 | } | ||
41 | } | 35 | } |
42 | 36 | ||
43 | pub struct DiagnosticSink<'a> { | 37 | pub struct DiagnosticSink<'a> { |
@@ -83,12 +77,9 @@ impl<'a> DiagnosticSinkBuilder<'a> { | |||
83 | self | 77 | self |
84 | } | 78 | } |
85 | 79 | ||
86 | pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> Self { | 80 | pub fn on<D: Diagnostic, F: FnMut(&D) -> Option<()> + 'a>(mut self, mut cb: F) -> Self { |
87 | let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() { | 81 | let cb = move |diag: &dyn Diagnostic| match diag.as_any().downcast_ref::<D>() { |
88 | Some(d) => { | 82 | Some(d) => cb(d).ok_or(()), |
89 | cb(d); | ||
90 | Ok(()) | ||
91 | } | ||
92 | None => Err(()), | 83 | None => Err(()), |
93 | }; | 84 | }; |
94 | self.callbacks.push(Box::new(cb)); | 85 | self.callbacks.push(Box::new(cb)); |
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 1e3a44637..b34ba5bfc 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs | |||
@@ -6,7 +6,7 @@ mod unsafe_check; | |||
6 | use std::any::Any; | 6 | use std::any::Any; |
7 | 7 | ||
8 | use hir_def::DefWithBodyId; | 8 | use hir_def::DefWithBodyId; |
9 | use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; | 9 | use hir_expand::diagnostics::{Diagnostic, DiagnosticSink, DiagnosticWithFix}; |
10 | use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; | 10 | use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; |
11 | use ra_prof::profile; | 11 | use ra_prof::profile; |
12 | use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; | 12 | use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; |
@@ -46,12 +46,12 @@ impl Diagnostic for NoSuchField { | |||
46 | } | 46 | } |
47 | } | 47 | } |
48 | 48 | ||
49 | impl AstDiagnostic for NoSuchField { | 49 | impl DiagnosticWithFix for NoSuchField { |
50 | type AST = ast::RecordExprField; | 50 | type AST = ast::RecordExprField; |
51 | 51 | ||
52 | fn fix_source(&self, db: &dyn AstDatabase) -> Self::AST { | 52 | fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST> { |
53 | let root = db.parse_or_expand(self.file).unwrap(); | 53 | let root = db.parse_or_expand(self.file)?; |
54 | self.field.to_node(&root) | 54 | Some(self.field.to_node(&root)) |
55 | } | 55 | } |
56 | } | 56 | } |
57 | 57 | ||
@@ -88,12 +88,12 @@ impl Diagnostic for MissingFields { | |||
88 | } | 88 | } |
89 | } | 89 | } |
90 | 90 | ||
91 | impl AstDiagnostic for MissingFields { | 91 | impl DiagnosticWithFix for MissingFields { |
92 | type AST = ast::RecordExpr; | 92 | type AST = ast::RecordExpr; |
93 | 93 | ||
94 | fn fix_source(&self, db: &dyn AstDatabase) -> Self::AST { | 94 | fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST> { |
95 | let root = db.parse_or_expand(self.file).unwrap(); | 95 | let root = db.parse_or_expand(self.file)?; |
96 | self.field_list_parent.to_node(&root) | 96 | Some(self.field_list_parent.to_node(&root)) |
97 | } | 97 | } |
98 | } | 98 | } |
99 | 99 | ||
@@ -163,12 +163,12 @@ impl Diagnostic for MissingOkInTailExpr { | |||
163 | } | 163 | } |
164 | } | 164 | } |
165 | 165 | ||
166 | impl AstDiagnostic for MissingOkInTailExpr { | 166 | impl DiagnosticWithFix for MissingOkInTailExpr { |
167 | type AST = ast::Expr; | 167 | type AST = ast::Expr; |
168 | 168 | ||
169 | fn fix_source(&self, db: &dyn AstDatabase) -> Self::AST { | 169 | fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST> { |
170 | let root = db.parse_or_expand(self.file).unwrap(); | 170 | let root = db.parse_or_expand(self.file)?; |
171 | self.expr.to_node(&root) | 171 | Some(self.expr.to_node(&root)) |
172 | } | 172 | } |
173 | } | 173 | } |
174 | 174 | ||
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index 55593a8cb..043ce357b 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs | |||
@@ -62,12 +62,18 @@ pub(crate) fn diagnostics( | |||
62 | } | 62 | } |
63 | .into(), | 63 | .into(), |
64 | ); | 64 | ); |
65 | let fix = sema | ||
66 | .diagnostic_fix_source(d) | ||
67 | .map(|unresolved_module| unresolved_module.syntax().text_range()) | ||
68 | .map(|fix_range| (fix, fix_range)); | ||
69 | |||
65 | res.borrow_mut().push(Diagnostic { | 70 | res.borrow_mut().push(Diagnostic { |
66 | range: sema.diagnostics_presentation_range(d).range, | 71 | range: sema.diagnostics_presentation_range(d).range, |
67 | message: d.message(), | 72 | message: d.message(), |
68 | severity: Severity::Error, | 73 | severity: Severity::Error, |
69 | fix: Some((fix, sema.diagnostic_fix_source(d).syntax().text_range())), | 74 | fix, |
70 | }) | 75 | }); |
76 | Some(()) | ||
71 | }) | 77 | }) |
72 | .on::<hir::diagnostics::MissingFields, _>(|d| { | 78 | .on::<hir::diagnostics::MissingFields, _>(|d| { |
73 | // Note that although we could add a diagnostics to | 79 | // Note that although we could add a diagnostics to |
@@ -78,30 +84,29 @@ pub(crate) fn diagnostics( | |||
78 | let fix = if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) { | 84 | let fix = if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) { |
79 | None | 85 | None |
80 | } else { | 86 | } else { |
81 | let record_expr = sema.diagnostic_fix_source(d); | 87 | sema.diagnostic_fix_source(d) |
82 | if let Some(old_field_list) = record_expr.record_expr_field_list() { | 88 | .and_then(|record_expr| record_expr.record_expr_field_list()) |
83 | let mut new_field_list = old_field_list.clone(); | 89 | .map(|old_field_list| { |
84 | for f in d.missed_fields.iter() { | 90 | let mut new_field_list = old_field_list.clone(); |
85 | let field = make::record_expr_field( | 91 | for f in d.missed_fields.iter() { |
86 | make::name_ref(&f.to_string()), | 92 | let field = make::record_expr_field( |
87 | Some(make::expr_unit()), | 93 | make::name_ref(&f.to_string()), |
88 | ); | 94 | Some(make::expr_unit()), |
89 | new_field_list = new_field_list.append_field(&field); | 95 | ); |
90 | } | 96 | new_field_list = new_field_list.append_field(&field); |
91 | 97 | } | |
92 | let edit = { | 98 | |
93 | let mut builder = TextEditBuilder::default(); | 99 | let edit = { |
94 | algo::diff(&old_field_list.syntax(), &new_field_list.syntax()) | 100 | let mut builder = TextEditBuilder::default(); |
95 | .into_text_edit(&mut builder); | 101 | algo::diff(&old_field_list.syntax(), &new_field_list.syntax()) |
96 | builder.finish() | 102 | .into_text_edit(&mut builder); |
97 | }; | 103 | builder.finish() |
98 | Some(( | 104 | }; |
99 | Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into()), | 105 | ( |
100 | sema.original_range(&old_field_list.syntax()).range, | 106 | Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into()), |
101 | )) | 107 | sema.original_range(&old_field_list.syntax()).range, |
102 | } else { | 108 | ) |
103 | None | 109 | }) |
104 | } | ||
105 | }; | 110 | }; |
106 | 111 | ||
107 | res.borrow_mut().push(Diagnostic { | 112 | res.borrow_mut().push(Diagnostic { |
@@ -109,28 +114,36 @@ pub(crate) fn diagnostics( | |||
109 | message: d.message(), | 114 | message: d.message(), |
110 | severity: Severity::Error, | 115 | severity: Severity::Error, |
111 | fix, | 116 | fix, |
112 | }) | 117 | }); |
118 | Some(()) | ||
113 | }) | 119 | }) |
114 | .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| { | 120 | .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| { |
115 | let tail_expr = sema.diagnostic_fix_source(d); | 121 | let fix = sema.diagnostic_fix_source(d).map(|tail_expr| { |
116 | let tail_expr_range = tail_expr.syntax().text_range(); | 122 | let tail_expr_range = tail_expr.syntax().text_range(); |
117 | let edit = TextEdit::replace(tail_expr_range, format!("Ok({})", tail_expr.syntax())); | 123 | let edit = |
118 | let source_change = SourceFileEdit { file_id, edit }.into(); | 124 | TextEdit::replace(tail_expr_range, format!("Ok({})", tail_expr.syntax())); |
125 | let source_change = SourceFileEdit { file_id, edit }.into(); | ||
126 | (Fix::new("Wrap with ok", source_change), tail_expr_range) | ||
127 | }); | ||
128 | |||
119 | res.borrow_mut().push(Diagnostic { | 129 | res.borrow_mut().push(Diagnostic { |
120 | range: sema.diagnostics_presentation_range(d).range, | 130 | range: sema.diagnostics_presentation_range(d).range, |
121 | message: d.message(), | 131 | message: d.message(), |
122 | severity: Severity::Error, | 132 | severity: Severity::Error, |
123 | fix: Some((Fix::new("Wrap with ok", source_change), tail_expr_range)), | 133 | fix, |
124 | }) | 134 | }); |
135 | Some(()) | ||
125 | }) | 136 | }) |
126 | .on::<hir::diagnostics::NoSuchField, _>(|d| { | 137 | .on::<hir::diagnostics::NoSuchField, _>(|d| { |
127 | res.borrow_mut().push(Diagnostic { | 138 | res.borrow_mut().push(Diagnostic { |
128 | range: sema.diagnostics_presentation_range(d).range, | 139 | range: sema.diagnostics_presentation_range(d).range, |
129 | message: d.message(), | 140 | message: d.message(), |
130 | severity: Severity::Error, | 141 | severity: Severity::Error, |
131 | fix: missing_struct_field_fix(&sema, file_id, d) | 142 | fix: missing_struct_field_fix(&sema, file_id, d).and_then(|fix| { |
132 | .map(|fix| (fix, sema.diagnostic_fix_source(d).syntax().text_range())), | 143 | Some((fix, sema.diagnostic_fix_source(d)?.syntax().text_range())) |
133 | }) | 144 | }), |
145 | }); | ||
146 | Some(()) | ||
134 | }) | 147 | }) |
135 | // Only collect experimental diagnostics when they're enabled. | 148 | // Only collect experimental diagnostics when they're enabled. |
136 | .filter(|diag| !diag.is_experimental() || enable_experimental) | 149 | .filter(|diag| !diag.is_experimental() || enable_experimental) |
@@ -156,7 +169,7 @@ fn missing_struct_field_fix( | |||
156 | usage_file_id: FileId, | 169 | usage_file_id: FileId, |
157 | d: &hir::diagnostics::NoSuchField, | 170 | d: &hir::diagnostics::NoSuchField, |
158 | ) -> Option<Fix> { | 171 | ) -> Option<Fix> { |
159 | let record_expr_field = sema.diagnostic_fix_source(d); | 172 | let record_expr_field = sema.diagnostic_fix_source(d)?; |
160 | 173 | ||
161 | let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?; | 174 | let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?; |
162 | let def_id = sema.resolve_variant(record_lit)?; | 175 | let def_id = sema.resolve_variant(record_lit)?; |