aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/diagnostics.rs2
-rw-r--r--crates/ra_hir/src/semantics.rs8
-rw-r--r--crates/ra_hir_def/src/diagnostics.rs10
-rw-r--r--crates/ra_hir_expand/src/diagnostics.rs19
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs26
-rw-r--r--crates/ra_ide/src/diagnostics.rs87
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
2pub use hir_def::diagnostics::UnresolvedModule; 2pub use hir_def::diagnostics::UnresolvedModule;
3pub use hir_expand::diagnostics::{ 3pub use hir_expand::diagnostics::{
4 AstDiagnostic, Diagnostic, DiagnosticSink, DiagnosticSinkBuilder, 4 Diagnostic, DiagnosticSink, DiagnosticSinkBuilder, DiagnosticWithFix,
5}; 5};
6pub use hir_ty::diagnostics::{ 6pub 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};
11use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, name::AsName, ExpansionInfo}; 11use hir_expand::{diagnostics::DiagnosticWithFix, hygiene::Hygiene, name::AsName, ExpansionInfo};
12use hir_ty::associated_type_shorthand_candidates; 12use hir_ty::associated_type_shorthand_candidates;
13use itertools::Itertools; 13use itertools::Itertools;
14use ra_db::{FileId, FileRange}; 14use 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
3use std::any::Any; 3use std::any::Any;
4 4
5use hir_expand::diagnostics::{AstDiagnostic, Diagnostic}; 5use hir_expand::diagnostics::{Diagnostic, DiagnosticWithFix};
6use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; 6use ra_syntax::{ast, AstPtr, SyntaxNodePtr};
7 7
8use hir_expand::{HirFileId, InFile}; 8use hir_expand::{HirFileId, InFile};
@@ -26,10 +26,10 @@ impl Diagnostic for UnresolvedModule {
26 } 26 }
27} 27}
28 28
29impl AstDiagnostic for UnresolvedModule { 29impl 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
32pub trait AstDiagnostic { 32pub 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
37impl dyn Diagnostic {
38 pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> {
39 self.as_any().downcast_ref()
40 }
41} 35}
42 36
43pub struct DiagnosticSink<'a> { 37pub 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;
6use std::any::Any; 6use std::any::Any;
7 7
8use hir_def::DefWithBodyId; 8use hir_def::DefWithBodyId;
9use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; 9use hir_expand::diagnostics::{Diagnostic, DiagnosticSink, DiagnosticWithFix};
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, AstPtr, SyntaxNodePtr}; 12use ra_syntax::{ast, AstPtr, SyntaxNodePtr};
@@ -46,12 +46,12 @@ impl Diagnostic for NoSuchField {
46 } 46 }
47} 47}
48 48
49impl AstDiagnostic for NoSuchField { 49impl 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
91impl AstDiagnostic for MissingFields { 91impl 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
166impl AstDiagnostic for MissingOkInTailExpr { 166impl 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)?;