diff options
author | Aleksey Kladov <[email protected]> | 2021-04-12 15:58:01 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-04-12 15:58:01 +0100 |
commit | 426d098bd6a032cb03e61d4b3d091caeaecbd4d0 (patch) | |
tree | eb54a5d4e72a875b072af5f266673c6265057f3d /crates/ide/src/diagnostics | |
parent | cae920a1bb827726aa142e5c81da9e6b0ca38d97 (diff) |
internal: prepare for lazy diagnostics
Diffstat (limited to 'crates/ide/src/diagnostics')
-rw-r--r-- | crates/ide/src/diagnostics/field_shorthand.rs | 8 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/fixes.rs | 42 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/unlinked_file.rs | 14 |
3 files changed, 38 insertions, 26 deletions
diff --git a/crates/ide/src/diagnostics/field_shorthand.rs b/crates/ide/src/diagnostics/field_shorthand.rs index 5c89e2170..2b1787f9b 100644 --- a/crates/ide/src/diagnostics/field_shorthand.rs +++ b/crates/ide/src/diagnostics/field_shorthand.rs | |||
@@ -5,7 +5,7 @@ use ide_db::{base_db::FileId, source_change::SourceChange}; | |||
5 | use syntax::{ast, match_ast, AstNode, SyntaxNode}; | 5 | use syntax::{ast, match_ast, AstNode, SyntaxNode}; |
6 | use text_edit::TextEdit; | 6 | use text_edit::TextEdit; |
7 | 7 | ||
8 | use crate::{Diagnostic, Fix}; | 8 | use crate::{diagnostics::fix, Diagnostic}; |
9 | 9 | ||
10 | pub(super) fn check(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &SyntaxNode) { | 10 | pub(super) fn check(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &SyntaxNode) { |
11 | match_ast! { | 11 | match_ast! { |
@@ -47,7 +47,8 @@ fn check_expr_field_shorthand( | |||
47 | let field_range = record_field.syntax().text_range(); | 47 | let field_range = record_field.syntax().text_range(); |
48 | acc.push( | 48 | acc.push( |
49 | Diagnostic::hint(field_range, "Shorthand struct initialization".to_string()).with_fix( | 49 | Diagnostic::hint(field_range, "Shorthand struct initialization".to_string()).with_fix( |
50 | Some(Fix::new( | 50 | Some(fix( |
51 | "use_expr_field_shorthand", | ||
51 | "Use struct shorthand initialization", | 52 | "Use struct shorthand initialization", |
52 | SourceChange::from_text_edit(file_id, edit), | 53 | SourceChange::from_text_edit(file_id, edit), |
53 | field_range, | 54 | field_range, |
@@ -86,7 +87,8 @@ fn check_pat_field_shorthand( | |||
86 | 87 | ||
87 | let field_range = record_pat_field.syntax().text_range(); | 88 | let field_range = record_pat_field.syntax().text_range(); |
88 | acc.push(Diagnostic::hint(field_range, "Shorthand struct pattern".to_string()).with_fix( | 89 | acc.push(Diagnostic::hint(field_range, "Shorthand struct pattern".to_string()).with_fix( |
89 | Some(Fix::new( | 90 | Some(fix( |
91 | "use_pat_field_shorthand", | ||
90 | "Use struct field shorthand", | 92 | "Use struct field shorthand", |
91 | SourceChange::from_text_edit(file_id, edit), | 93 | SourceChange::from_text_edit(file_id, edit), |
92 | field_range, | 94 | field_range, |
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs index 5fb3e2d91..69cf5288c 100644 --- a/crates/ide/src/diagnostics/fixes.rs +++ b/crates/ide/src/diagnostics/fixes.rs | |||
@@ -20,20 +20,21 @@ use syntax::{ | |||
20 | }; | 20 | }; |
21 | use text_edit::TextEdit; | 21 | use text_edit::TextEdit; |
22 | 22 | ||
23 | use crate::{diagnostics::Fix, references::rename::rename_with_semantics, FilePosition}; | 23 | use crate::{diagnostics::fix, references::rename::rename_with_semantics, Assist, FilePosition}; |
24 | 24 | ||
25 | /// A [Diagnostic] that potentially has a fix available. | 25 | /// A [Diagnostic] that potentially has a fix available. |
26 | /// | 26 | /// |
27 | /// [Diagnostic]: hir::diagnostics::Diagnostic | 27 | /// [Diagnostic]: hir::diagnostics::Diagnostic |
28 | pub(crate) trait DiagnosticWithFix: Diagnostic { | 28 | pub(crate) trait DiagnosticWithFix: Diagnostic { |
29 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix>; | 29 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Assist>; |
30 | } | 30 | } |
31 | 31 | ||
32 | impl DiagnosticWithFix for UnresolvedModule { | 32 | impl DiagnosticWithFix for UnresolvedModule { |
33 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { | 33 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Assist> { |
34 | let root = sema.db.parse_or_expand(self.file)?; | 34 | let root = sema.db.parse_or_expand(self.file)?; |
35 | let unresolved_module = self.decl.to_node(&root); | 35 | let unresolved_module = self.decl.to_node(&root); |
36 | Some(Fix::new( | 36 | Some(fix( |
37 | "create_module", | ||
37 | "Create module", | 38 | "Create module", |
38 | FileSystemEdit::CreateFile { | 39 | FileSystemEdit::CreateFile { |
39 | dst: AnchoredPathBuf { | 40 | dst: AnchoredPathBuf { |
@@ -49,7 +50,7 @@ impl DiagnosticWithFix for UnresolvedModule { | |||
49 | } | 50 | } |
50 | 51 | ||
51 | impl DiagnosticWithFix for NoSuchField { | 52 | impl DiagnosticWithFix for NoSuchField { |
52 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { | 53 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Assist> { |
53 | let root = sema.db.parse_or_expand(self.file)?; | 54 | let root = sema.db.parse_or_expand(self.file)?; |
54 | missing_record_expr_field_fix( | 55 | missing_record_expr_field_fix( |
55 | &sema, | 56 | &sema, |
@@ -60,7 +61,7 @@ impl DiagnosticWithFix for NoSuchField { | |||
60 | } | 61 | } |
61 | 62 | ||
62 | impl DiagnosticWithFix for MissingFields { | 63 | impl DiagnosticWithFix for MissingFields { |
63 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { | 64 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Assist> { |
64 | // Note that although we could add a diagnostics to | 65 | // Note that although we could add a diagnostics to |
65 | // fill the missing tuple field, e.g : | 66 | // fill the missing tuple field, e.g : |
66 | // `struct A(usize);` | 67 | // `struct A(usize);` |
@@ -86,7 +87,8 @@ impl DiagnosticWithFix for MissingFields { | |||
86 | .into_text_edit(&mut builder); | 87 | .into_text_edit(&mut builder); |
87 | builder.finish() | 88 | builder.finish() |
88 | }; | 89 | }; |
89 | Some(Fix::new( | 90 | Some(fix( |
91 | "fill_missing_fields", | ||
90 | "Fill struct fields", | 92 | "Fill struct fields", |
91 | SourceChange::from_text_edit(self.file.original_file(sema.db), edit), | 93 | SourceChange::from_text_edit(self.file.original_file(sema.db), edit), |
92 | sema.original_range(&field_list_parent.syntax()).range, | 94 | sema.original_range(&field_list_parent.syntax()).range, |
@@ -95,7 +97,7 @@ impl DiagnosticWithFix for MissingFields { | |||
95 | } | 97 | } |
96 | 98 | ||
97 | impl DiagnosticWithFix for MissingOkOrSomeInTailExpr { | 99 | impl DiagnosticWithFix for MissingOkOrSomeInTailExpr { |
98 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { | 100 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Assist> { |
99 | let root = sema.db.parse_or_expand(self.file)?; | 101 | let root = sema.db.parse_or_expand(self.file)?; |
100 | let tail_expr = self.expr.to_node(&root); | 102 | let tail_expr = self.expr.to_node(&root); |
101 | let tail_expr_range = tail_expr.syntax().text_range(); | 103 | let tail_expr_range = tail_expr.syntax().text_range(); |
@@ -103,12 +105,12 @@ impl DiagnosticWithFix for MissingOkOrSomeInTailExpr { | |||
103 | let edit = TextEdit::replace(tail_expr_range, replacement); | 105 | let edit = TextEdit::replace(tail_expr_range, replacement); |
104 | let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit); | 106 | let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit); |
105 | let name = if self.required == "Ok" { "Wrap with Ok" } else { "Wrap with Some" }; | 107 | let name = if self.required == "Ok" { "Wrap with Ok" } else { "Wrap with Some" }; |
106 | Some(Fix::new(name, source_change, tail_expr_range)) | 108 | Some(fix("wrap_tail_expr", name, source_change, tail_expr_range)) |
107 | } | 109 | } |
108 | } | 110 | } |
109 | 111 | ||
110 | impl DiagnosticWithFix for RemoveThisSemicolon { | 112 | impl DiagnosticWithFix for RemoveThisSemicolon { |
111 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { | 113 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Assist> { |
112 | let root = sema.db.parse_or_expand(self.file)?; | 114 | let root = sema.db.parse_or_expand(self.file)?; |
113 | 115 | ||
114 | let semicolon = self | 116 | let semicolon = self |
@@ -123,12 +125,12 @@ impl DiagnosticWithFix for RemoveThisSemicolon { | |||
123 | let edit = TextEdit::delete(semicolon); | 125 | let edit = TextEdit::delete(semicolon); |
124 | let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit); | 126 | let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit); |
125 | 127 | ||
126 | Some(Fix::new("Remove this semicolon", source_change, semicolon)) | 128 | Some(fix("remove_semicolon", "Remove this semicolon", source_change, semicolon)) |
127 | } | 129 | } |
128 | } | 130 | } |
129 | 131 | ||
130 | impl DiagnosticWithFix for IncorrectCase { | 132 | impl DiagnosticWithFix for IncorrectCase { |
131 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { | 133 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Assist> { |
132 | let root = sema.db.parse_or_expand(self.file)?; | 134 | let root = sema.db.parse_or_expand(self.file)?; |
133 | let name_node = self.ident.to_node(&root); | 135 | let name_node = self.ident.to_node(&root); |
134 | 136 | ||
@@ -140,12 +142,12 @@ impl DiagnosticWithFix for IncorrectCase { | |||
140 | rename_with_semantics(sema, file_position, &self.suggested_text).ok()?; | 142 | rename_with_semantics(sema, file_position, &self.suggested_text).ok()?; |
141 | 143 | ||
142 | let label = format!("Rename to {}", self.suggested_text); | 144 | let label = format!("Rename to {}", self.suggested_text); |
143 | Some(Fix::new(&label, rename_changes, frange.range)) | 145 | Some(fix("change_case", &label, rename_changes, frange.range)) |
144 | } | 146 | } |
145 | } | 147 | } |
146 | 148 | ||
147 | impl DiagnosticWithFix for ReplaceFilterMapNextWithFindMap { | 149 | impl DiagnosticWithFix for ReplaceFilterMapNextWithFindMap { |
148 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { | 150 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Assist> { |
149 | let root = sema.db.parse_or_expand(self.file)?; | 151 | let root = sema.db.parse_or_expand(self.file)?; |
150 | let next_expr = self.next_expr.to_node(&root); | 152 | let next_expr = self.next_expr.to_node(&root); |
151 | let next_call = ast::MethodCallExpr::cast(next_expr.syntax().clone())?; | 153 | let next_call = ast::MethodCallExpr::cast(next_expr.syntax().clone())?; |
@@ -163,7 +165,8 @@ impl DiagnosticWithFix for ReplaceFilterMapNextWithFindMap { | |||
163 | 165 | ||
164 | let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit); | 166 | let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit); |
165 | 167 | ||
166 | Some(Fix::new( | 168 | Some(fix( |
169 | "replace_with_find_map", | ||
167 | "Replace filter_map(..).next() with find_map()", | 170 | "Replace filter_map(..).next() with find_map()", |
168 | source_change, | 171 | source_change, |
169 | trigger_range, | 172 | trigger_range, |
@@ -175,7 +178,7 @@ fn missing_record_expr_field_fix( | |||
175 | sema: &Semantics<RootDatabase>, | 178 | sema: &Semantics<RootDatabase>, |
176 | usage_file_id: FileId, | 179 | usage_file_id: FileId, |
177 | record_expr_field: &ast::RecordExprField, | 180 | record_expr_field: &ast::RecordExprField, |
178 | ) -> Option<Fix> { | 181 | ) -> Option<Assist> { |
179 | let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?; | 182 | let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?; |
180 | let def_id = sema.resolve_variant(record_lit)?; | 183 | let def_id = sema.resolve_variant(record_lit)?; |
181 | let module; | 184 | let module; |
@@ -233,7 +236,12 @@ fn missing_record_expr_field_fix( | |||
233 | def_file_id, | 236 | def_file_id, |
234 | TextEdit::insert(last_field_syntax.text_range().end(), new_field), | 237 | TextEdit::insert(last_field_syntax.text_range().end(), new_field), |
235 | ); | 238 | ); |
236 | return Some(Fix::new("Create field", source_change, record_expr_field.syntax().text_range())); | 239 | return Some(fix( |
240 | "create_field", | ||
241 | "Create field", | ||
242 | source_change, | ||
243 | record_expr_field.syntax().text_range(), | ||
244 | )); | ||
237 | 245 | ||
238 | fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> { | 246 | fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> { |
239 | match field_def_list { | 247 | match field_def_list { |
diff --git a/crates/ide/src/diagnostics/unlinked_file.rs b/crates/ide/src/diagnostics/unlinked_file.rs index e174fb767..5482b7287 100644 --- a/crates/ide/src/diagnostics/unlinked_file.rs +++ b/crates/ide/src/diagnostics/unlinked_file.rs | |||
@@ -16,9 +16,10 @@ use syntax::{ | |||
16 | }; | 16 | }; |
17 | use text_edit::TextEdit; | 17 | use text_edit::TextEdit; |
18 | 18 | ||
19 | use crate::Fix; | 19 | use crate::{ |
20 | 20 | diagnostics::{fix, fixes::DiagnosticWithFix}, | |
21 | use super::fixes::DiagnosticWithFix; | 21 | Assist, |
22 | }; | ||
22 | 23 | ||
23 | // Diagnostic: unlinked-file | 24 | // Diagnostic: unlinked-file |
24 | // | 25 | // |
@@ -49,7 +50,7 @@ impl Diagnostic for UnlinkedFile { | |||
49 | } | 50 | } |
50 | 51 | ||
51 | impl DiagnosticWithFix for UnlinkedFile { | 52 | impl DiagnosticWithFix for UnlinkedFile { |
52 | fn fix(&self, sema: &hir::Semantics<RootDatabase>) -> Option<Fix> { | 53 | fn fix(&self, sema: &hir::Semantics<RootDatabase>) -> Option<Assist> { |
53 | // If there's an existing module that could add a `mod` item to include the unlinked file, | 54 | // If there's an existing module that could add a `mod` item to include the unlinked file, |
54 | // suggest that as a fix. | 55 | // suggest that as a fix. |
55 | 56 | ||
@@ -100,7 +101,7 @@ fn make_fix( | |||
100 | parent_file_id: FileId, | 101 | parent_file_id: FileId, |
101 | new_mod_name: &str, | 102 | new_mod_name: &str, |
102 | added_file_id: FileId, | 103 | added_file_id: FileId, |
103 | ) -> Option<Fix> { | 104 | ) -> Option<Assist> { |
104 | fn is_outline_mod(item: &ast::Item) -> bool { | 105 | fn is_outline_mod(item: &ast::Item) -> bool { |
105 | matches!(item, ast::Item::Module(m) if m.item_list().is_none()) | 106 | matches!(item, ast::Item::Module(m) if m.item_list().is_none()) |
106 | } | 107 | } |
@@ -152,7 +153,8 @@ fn make_fix( | |||
152 | 153 | ||
153 | let edit = builder.finish(); | 154 | let edit = builder.finish(); |
154 | let trigger_range = db.parse(added_file_id).tree().syntax().text_range(); | 155 | let trigger_range = db.parse(added_file_id).tree().syntax().text_range(); |
155 | Some(Fix::new( | 156 | Some(fix( |
157 | "add_mod_declaration", | ||
156 | &format!("Insert `{}`", mod_decl), | 158 | &format!("Insert `{}`", mod_decl), |
157 | SourceChange::from_text_edit(parent_file_id, edit), | 159 | SourceChange::from_text_edit(parent_file_id, edit), |
158 | trigger_range, | 160 | trigger_range, |