diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-04-13 10:09:24 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2021-04-13 10:09:24 +0100 |
commit | 6081b437cc842f8885c26636bef8af4cbc5483e3 (patch) | |
tree | d608b8a7edd630a8b028c117c615ece9a48c4186 /crates | |
parent | fe29a9e837c6e9699185ccae55e83902b4f6ef6a (diff) | |
parent | 06a633ff421b764428bb946ced914e59532fe13f (diff) |
Merge #8498
8498: feat: improve performance by delaying computation of fixes for diagnostics r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ide/src/diagnostics.rs | 60 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/fixes.rs | 38 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/unlinked_file.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/lib.rs | 32 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/diagnostics.rs | 3 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 40 | ||||
-rw-r--r-- | crates/rust-analyzer/tests/rust-analyzer/support.rs | 1 |
7 files changed, 115 insertions, 61 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 4f0b4a62e..9a883acb9 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -84,6 +84,7 @@ pub struct DiagnosticsConfig { | |||
84 | pub(crate) fn diagnostics( | 84 | pub(crate) fn diagnostics( |
85 | db: &RootDatabase, | 85 | db: &RootDatabase, |
86 | config: &DiagnosticsConfig, | 86 | config: &DiagnosticsConfig, |
87 | resolve: bool, | ||
87 | file_id: FileId, | 88 | file_id: FileId, |
88 | ) -> Vec<Diagnostic> { | 89 | ) -> Vec<Diagnostic> { |
89 | let _p = profile::span("diagnostics"); | 90 | let _p = profile::span("diagnostics"); |
@@ -107,25 +108,25 @@ pub(crate) fn diagnostics( | |||
107 | let res = RefCell::new(res); | 108 | let res = RefCell::new(res); |
108 | let sink_builder = DiagnosticSinkBuilder::new() | 109 | let sink_builder = DiagnosticSinkBuilder::new() |
109 | .on::<hir::diagnostics::UnresolvedModule, _>(|d| { | 110 | .on::<hir::diagnostics::UnresolvedModule, _>(|d| { |
110 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); | 111 | res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve)); |
111 | }) | 112 | }) |
112 | .on::<hir::diagnostics::MissingFields, _>(|d| { | 113 | .on::<hir::diagnostics::MissingFields, _>(|d| { |
113 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); | 114 | res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve)); |
114 | }) | 115 | }) |
115 | .on::<hir::diagnostics::MissingOkOrSomeInTailExpr, _>(|d| { | 116 | .on::<hir::diagnostics::MissingOkOrSomeInTailExpr, _>(|d| { |
116 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); | 117 | res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve)); |
117 | }) | 118 | }) |
118 | .on::<hir::diagnostics::NoSuchField, _>(|d| { | 119 | .on::<hir::diagnostics::NoSuchField, _>(|d| { |
119 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); | 120 | res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve)); |
120 | }) | 121 | }) |
121 | .on::<hir::diagnostics::RemoveThisSemicolon, _>(|d| { | 122 | .on::<hir::diagnostics::RemoveThisSemicolon, _>(|d| { |
122 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); | 123 | res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve)); |
123 | }) | 124 | }) |
124 | .on::<hir::diagnostics::IncorrectCase, _>(|d| { | 125 | .on::<hir::diagnostics::IncorrectCase, _>(|d| { |
125 | res.borrow_mut().push(warning_with_fix(d, &sema)); | 126 | res.borrow_mut().push(warning_with_fix(d, &sema, resolve)); |
126 | }) | 127 | }) |
127 | .on::<hir::diagnostics::ReplaceFilterMapNextWithFindMap, _>(|d| { | 128 | .on::<hir::diagnostics::ReplaceFilterMapNextWithFindMap, _>(|d| { |
128 | res.borrow_mut().push(warning_with_fix(d, &sema)); | 129 | res.borrow_mut().push(warning_with_fix(d, &sema, resolve)); |
129 | }) | 130 | }) |
130 | .on::<hir::diagnostics::InactiveCode, _>(|d| { | 131 | .on::<hir::diagnostics::InactiveCode, _>(|d| { |
131 | // If there's inactive code somewhere in a macro, don't propagate to the call-site. | 132 | // If there's inactive code somewhere in a macro, don't propagate to the call-site. |
@@ -152,7 +153,7 @@ pub(crate) fn diagnostics( | |||
152 | // Override severity and mark as unused. | 153 | // Override severity and mark as unused. |
153 | res.borrow_mut().push( | 154 | res.borrow_mut().push( |
154 | Diagnostic::hint(range, d.message()) | 155 | Diagnostic::hint(range, d.message()) |
155 | .with_fix(d.fix(&sema)) | 156 | .with_fix(d.fix(&sema, resolve)) |
156 | .with_code(Some(d.code())), | 157 | .with_code(Some(d.code())), |
157 | ); | 158 | ); |
158 | }) | 159 | }) |
@@ -208,15 +209,23 @@ pub(crate) fn diagnostics( | |||
208 | res.into_inner() | 209 | res.into_inner() |
209 | } | 210 | } |
210 | 211 | ||
211 | fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { | 212 | fn diagnostic_with_fix<D: DiagnosticWithFix>( |
213 | d: &D, | ||
214 | sema: &Semantics<RootDatabase>, | ||
215 | resolve: bool, | ||
216 | ) -> Diagnostic { | ||
212 | Diagnostic::error(sema.diagnostics_display_range(d.display_source()).range, d.message()) | 217 | Diagnostic::error(sema.diagnostics_display_range(d.display_source()).range, d.message()) |
213 | .with_fix(d.fix(&sema)) | 218 | .with_fix(d.fix(&sema, resolve)) |
214 | .with_code(Some(d.code())) | 219 | .with_code(Some(d.code())) |
215 | } | 220 | } |
216 | 221 | ||
217 | fn warning_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { | 222 | fn warning_with_fix<D: DiagnosticWithFix>( |
223 | d: &D, | ||
224 | sema: &Semantics<RootDatabase>, | ||
225 | resolve: bool, | ||
226 | ) -> Diagnostic { | ||
218 | Diagnostic::hint(sema.diagnostics_display_range(d.display_source()).range, d.message()) | 227 | Diagnostic::hint(sema.diagnostics_display_range(d.display_source()).range, d.message()) |
219 | .with_fix(d.fix(&sema)) | 228 | .with_fix(d.fix(&sema, resolve)) |
220 | .with_code(Some(d.code())) | 229 | .with_code(Some(d.code())) |
221 | } | 230 | } |
222 | 231 | ||
@@ -271,13 +280,19 @@ fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement( | |||
271 | } | 280 | } |
272 | 281 | ||
273 | fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist { | 282 | fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist { |
283 | let mut res = unresolved_fix(id, label, target); | ||
284 | res.source_change = Some(source_change); | ||
285 | res | ||
286 | } | ||
287 | |||
288 | fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist { | ||
274 | assert!(!id.contains(' ')); | 289 | assert!(!id.contains(' ')); |
275 | Assist { | 290 | Assist { |
276 | id: AssistId(id, AssistKind::QuickFix), | 291 | id: AssistId(id, AssistKind::QuickFix), |
277 | label: Label::new(label), | 292 | label: Label::new(label), |
278 | group: None, | 293 | group: None, |
279 | target, | 294 | target, |
280 | source_change: Some(source_change), | 295 | source_change: None, |
281 | } | 296 | } |
282 | } | 297 | } |
283 | 298 | ||
@@ -299,7 +314,7 @@ mod tests { | |||
299 | 314 | ||
300 | let (analysis, file_position) = fixture::position(ra_fixture_before); | 315 | let (analysis, file_position) = fixture::position(ra_fixture_before); |
301 | let diagnostic = analysis | 316 | let diagnostic = analysis |
302 | .diagnostics(&DiagnosticsConfig::default(), file_position.file_id) | 317 | .diagnostics(&DiagnosticsConfig::default(), true, file_position.file_id) |
303 | .unwrap() | 318 | .unwrap() |
304 | .pop() | 319 | .pop() |
305 | .unwrap(); | 320 | .unwrap(); |
@@ -328,7 +343,7 @@ mod tests { | |||
328 | fn check_no_fix(ra_fixture: &str) { | 343 | fn check_no_fix(ra_fixture: &str) { |
329 | let (analysis, file_position) = fixture::position(ra_fixture); | 344 | let (analysis, file_position) = fixture::position(ra_fixture); |
330 | let diagnostic = analysis | 345 | let diagnostic = analysis |
331 | .diagnostics(&DiagnosticsConfig::default(), file_position.file_id) | 346 | .diagnostics(&DiagnosticsConfig::default(), true, file_position.file_id) |
332 | .unwrap() | 347 | .unwrap() |
333 | .pop() | 348 | .pop() |
334 | .unwrap(); | 349 | .unwrap(); |
@@ -342,7 +357,7 @@ mod tests { | |||
342 | let diagnostics = files | 357 | let diagnostics = files |
343 | .into_iter() | 358 | .into_iter() |
344 | .flat_map(|file_id| { | 359 | .flat_map(|file_id| { |
345 | analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap() | 360 | analysis.diagnostics(&DiagnosticsConfig::default(), true, file_id).unwrap() |
346 | }) | 361 | }) |
347 | .collect::<Vec<_>>(); | 362 | .collect::<Vec<_>>(); |
348 | assert_eq!(diagnostics.len(), 0, "unexpected diagnostics:\n{:#?}", diagnostics); | 363 | assert_eq!(diagnostics.len(), 0, "unexpected diagnostics:\n{:#?}", diagnostics); |
@@ -350,7 +365,8 @@ mod tests { | |||
350 | 365 | ||
351 | fn check_expect(ra_fixture: &str, expect: Expect) { | 366 | fn check_expect(ra_fixture: &str, expect: Expect) { |
352 | let (analysis, file_id) = fixture::file(ra_fixture); | 367 | let (analysis, file_id) = fixture::file(ra_fixture); |
353 | let diagnostics = analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap(); | 368 | let diagnostics = |
369 | analysis.diagnostics(&DiagnosticsConfig::default(), true, file_id).unwrap(); | ||
354 | expect.assert_debug_eq(&diagnostics) | 370 | expect.assert_debug_eq(&diagnostics) |
355 | } | 371 | } |
356 | 372 | ||
@@ -895,10 +911,11 @@ struct Foo { | |||
895 | 911 | ||
896 | let (analysis, file_id) = fixture::file(r#"mod foo;"#); | 912 | let (analysis, file_id) = fixture::file(r#"mod foo;"#); |
897 | 913 | ||
898 | let diagnostics = analysis.diagnostics(&config, file_id).unwrap(); | 914 | let diagnostics = analysis.diagnostics(&config, true, file_id).unwrap(); |
899 | assert!(diagnostics.is_empty()); | 915 | assert!(diagnostics.is_empty()); |
900 | 916 | ||
901 | let diagnostics = analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap(); | 917 | let diagnostics = |
918 | analysis.diagnostics(&DiagnosticsConfig::default(), true, file_id).unwrap(); | ||
902 | assert!(!diagnostics.is_empty()); | 919 | assert!(!diagnostics.is_empty()); |
903 | } | 920 | } |
904 | 921 | ||
@@ -1004,8 +1021,9 @@ impl TestStruct { | |||
1004 | let expected = r#"fn foo() {}"#; | 1021 | let expected = r#"fn foo() {}"#; |
1005 | 1022 | ||
1006 | let (analysis, file_position) = fixture::position(input); | 1023 | let (analysis, file_position) = fixture::position(input); |
1007 | let diagnostics = | 1024 | let diagnostics = analysis |
1008 | analysis.diagnostics(&DiagnosticsConfig::default(), file_position.file_id).unwrap(); | 1025 | .diagnostics(&DiagnosticsConfig::default(), true, file_position.file_id) |
1026 | .unwrap(); | ||
1009 | assert_eq!(diagnostics.len(), 1); | 1027 | assert_eq!(diagnostics.len(), 1); |
1010 | 1028 | ||
1011 | check_fix(input, expected); | 1029 | check_fix(input, expected); |
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs index 69cf5288c..7be8b3459 100644 --- a/crates/ide/src/diagnostics/fixes.rs +++ b/crates/ide/src/diagnostics/fixes.rs | |||
@@ -20,17 +20,26 @@ 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, Assist, FilePosition}; | 23 | use crate::{ |
24 | diagnostics::{fix, unresolved_fix}, | ||
25 | references::rename::rename_with_semantics, | ||
26 | Assist, FilePosition, | ||
27 | }; | ||
24 | 28 | ||
25 | /// A [Diagnostic] that potentially has a fix available. | 29 | /// A [Diagnostic] that potentially has a fix available. |
26 | /// | 30 | /// |
27 | /// [Diagnostic]: hir::diagnostics::Diagnostic | 31 | /// [Diagnostic]: hir::diagnostics::Diagnostic |
28 | pub(crate) trait DiagnosticWithFix: Diagnostic { | 32 | pub(crate) trait DiagnosticWithFix: Diagnostic { |
29 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Assist>; | 33 | /// `resolve` determines if the diagnostic should fill in the `edit` field |
34 | /// of the assist. | ||
35 | /// | ||
36 | /// If `resolve` is false, the edit will be computed later, on demand, and | ||
37 | /// can be omitted. | ||
38 | fn fix(&self, sema: &Semantics<RootDatabase>, _resolve: bool) -> Option<Assist>; | ||
30 | } | 39 | } |
31 | 40 | ||
32 | impl DiagnosticWithFix for UnresolvedModule { | 41 | impl DiagnosticWithFix for UnresolvedModule { |
33 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Assist> { | 42 | fn fix(&self, sema: &Semantics<RootDatabase>, _resolve: bool) -> Option<Assist> { |
34 | let root = sema.db.parse_or_expand(self.file)?; | 43 | let root = sema.db.parse_or_expand(self.file)?; |
35 | let unresolved_module = self.decl.to_node(&root); | 44 | let unresolved_module = self.decl.to_node(&root); |
36 | Some(fix( | 45 | Some(fix( |
@@ -50,7 +59,7 @@ impl DiagnosticWithFix for UnresolvedModule { | |||
50 | } | 59 | } |
51 | 60 | ||
52 | impl DiagnosticWithFix for NoSuchField { | 61 | impl DiagnosticWithFix for NoSuchField { |
53 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Assist> { | 62 | fn fix(&self, sema: &Semantics<RootDatabase>, _resolve: bool) -> Option<Assist> { |
54 | let root = sema.db.parse_or_expand(self.file)?; | 63 | let root = sema.db.parse_or_expand(self.file)?; |
55 | missing_record_expr_field_fix( | 64 | missing_record_expr_field_fix( |
56 | &sema, | 65 | &sema, |
@@ -61,7 +70,7 @@ impl DiagnosticWithFix for NoSuchField { | |||
61 | } | 70 | } |
62 | 71 | ||
63 | impl DiagnosticWithFix for MissingFields { | 72 | impl DiagnosticWithFix for MissingFields { |
64 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Assist> { | 73 | fn fix(&self, sema: &Semantics<RootDatabase>, _resolve: bool) -> Option<Assist> { |
65 | // Note that although we could add a diagnostics to | 74 | // Note that although we could add a diagnostics to |
66 | // fill the missing tuple field, e.g : | 75 | // fill the missing tuple field, e.g : |
67 | // `struct A(usize);` | 76 | // `struct A(usize);` |
@@ -97,7 +106,7 @@ impl DiagnosticWithFix for MissingFields { | |||
97 | } | 106 | } |
98 | 107 | ||
99 | impl DiagnosticWithFix for MissingOkOrSomeInTailExpr { | 108 | impl DiagnosticWithFix for MissingOkOrSomeInTailExpr { |
100 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Assist> { | 109 | fn fix(&self, sema: &Semantics<RootDatabase>, _resolve: bool) -> Option<Assist> { |
101 | let root = sema.db.parse_or_expand(self.file)?; | 110 | let root = sema.db.parse_or_expand(self.file)?; |
102 | let tail_expr = self.expr.to_node(&root); | 111 | let tail_expr = self.expr.to_node(&root); |
103 | let tail_expr_range = tail_expr.syntax().text_range(); | 112 | let tail_expr_range = tail_expr.syntax().text_range(); |
@@ -110,7 +119,7 @@ impl DiagnosticWithFix for MissingOkOrSomeInTailExpr { | |||
110 | } | 119 | } |
111 | 120 | ||
112 | impl DiagnosticWithFix for RemoveThisSemicolon { | 121 | impl DiagnosticWithFix for RemoveThisSemicolon { |
113 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Assist> { | 122 | fn fix(&self, sema: &Semantics<RootDatabase>, _resolve: bool) -> Option<Assist> { |
114 | let root = sema.db.parse_or_expand(self.file)?; | 123 | let root = sema.db.parse_or_expand(self.file)?; |
115 | 124 | ||
116 | let semicolon = self | 125 | let semicolon = self |
@@ -130,7 +139,7 @@ impl DiagnosticWithFix for RemoveThisSemicolon { | |||
130 | } | 139 | } |
131 | 140 | ||
132 | impl DiagnosticWithFix for IncorrectCase { | 141 | impl DiagnosticWithFix for IncorrectCase { |
133 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Assist> { | 142 | fn fix(&self, sema: &Semantics<RootDatabase>, resolve: bool) -> Option<Assist> { |
134 | let root = sema.db.parse_or_expand(self.file)?; | 143 | let root = sema.db.parse_or_expand(self.file)?; |
135 | let name_node = self.ident.to_node(&root); | 144 | let name_node = self.ident.to_node(&root); |
136 | 145 | ||
@@ -138,16 +147,19 @@ impl DiagnosticWithFix for IncorrectCase { | |||
138 | let frange = name_node.original_file_range(sema.db); | 147 | let frange = name_node.original_file_range(sema.db); |
139 | let file_position = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; | 148 | let file_position = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; |
140 | 149 | ||
141 | let rename_changes = | ||
142 | rename_with_semantics(sema, file_position, &self.suggested_text).ok()?; | ||
143 | |||
144 | let label = format!("Rename to {}", self.suggested_text); | 150 | let label = format!("Rename to {}", self.suggested_text); |
145 | Some(fix("change_case", &label, rename_changes, frange.range)) | 151 | let mut res = unresolved_fix("change_case", &label, frange.range); |
152 | if resolve { | ||
153 | let source_change = rename_with_semantics(sema, file_position, &self.suggested_text); | ||
154 | res.source_change = Some(source_change.ok().unwrap_or_default()); | ||
155 | } | ||
156 | |||
157 | Some(res) | ||
146 | } | 158 | } |
147 | } | 159 | } |
148 | 160 | ||
149 | impl DiagnosticWithFix for ReplaceFilterMapNextWithFindMap { | 161 | impl DiagnosticWithFix for ReplaceFilterMapNextWithFindMap { |
150 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Assist> { | 162 | fn fix(&self, sema: &Semantics<RootDatabase>, _resolve: bool) -> Option<Assist> { |
151 | let root = sema.db.parse_or_expand(self.file)?; | 163 | let root = sema.db.parse_or_expand(self.file)?; |
152 | let next_expr = self.next_expr.to_node(&root); | 164 | let next_expr = self.next_expr.to_node(&root); |
153 | let next_call = ast::MethodCallExpr::cast(next_expr.syntax().clone())?; | 165 | let next_call = ast::MethodCallExpr::cast(next_expr.syntax().clone())?; |
diff --git a/crates/ide/src/diagnostics/unlinked_file.rs b/crates/ide/src/diagnostics/unlinked_file.rs index 5482b7287..7d39f4fbe 100644 --- a/crates/ide/src/diagnostics/unlinked_file.rs +++ b/crates/ide/src/diagnostics/unlinked_file.rs | |||
@@ -50,7 +50,7 @@ impl Diagnostic for UnlinkedFile { | |||
50 | } | 50 | } |
51 | 51 | ||
52 | impl DiagnosticWithFix for UnlinkedFile { | 52 | impl DiagnosticWithFix for UnlinkedFile { |
53 | fn fix(&self, sema: &hir::Semantics<RootDatabase>) -> Option<Assist> { | 53 | fn fix(&self, sema: &hir::Semantics<RootDatabase>, _resolve: bool) -> Option<Assist> { |
54 | // 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, |
55 | // suggest that as a fix. | 55 | // suggest that as a fix. |
56 | 56 | ||
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 0615b26d3..d481be09d 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -526,9 +526,39 @@ impl Analysis { | |||
526 | pub fn diagnostics( | 526 | pub fn diagnostics( |
527 | &self, | 527 | &self, |
528 | config: &DiagnosticsConfig, | 528 | config: &DiagnosticsConfig, |
529 | resolve: bool, | ||
529 | file_id: FileId, | 530 | file_id: FileId, |
530 | ) -> Cancelable<Vec<Diagnostic>> { | 531 | ) -> Cancelable<Vec<Diagnostic>> { |
531 | self.with_db(|db| diagnostics::diagnostics(db, config, file_id)) | 532 | self.with_db(|db| diagnostics::diagnostics(db, config, resolve, file_id)) |
533 | } | ||
534 | |||
535 | /// Convenience function to return assists + quick fixes for diagnostics | ||
536 | pub fn assists_with_fixes( | ||
537 | &self, | ||
538 | assist_config: &AssistConfig, | ||
539 | diagnostics_config: &DiagnosticsConfig, | ||
540 | resolve: bool, | ||
541 | frange: FileRange, | ||
542 | ) -> Cancelable<Vec<Assist>> { | ||
543 | let include_fixes = match &assist_config.allowed { | ||
544 | Some(it) => it.iter().any(|&it| it == AssistKind::None || it == AssistKind::QuickFix), | ||
545 | None => true, | ||
546 | }; | ||
547 | |||
548 | self.with_db(|db| { | ||
549 | let mut res = Assist::get(db, assist_config, resolve, frange); | ||
550 | ssr::add_ssr_assist(db, &mut res, resolve, frange); | ||
551 | |||
552 | if include_fixes { | ||
553 | res.extend( | ||
554 | diagnostics::diagnostics(db, diagnostics_config, resolve, frange.file_id) | ||
555 | .into_iter() | ||
556 | .filter_map(|it| it.fix) | ||
557 | .filter(|it| it.target.intersect(frange.range).is_some()), | ||
558 | ); | ||
559 | } | ||
560 | res | ||
561 | }) | ||
532 | } | 562 | } |
533 | 563 | ||
534 | /// Returns the edit required to rename reference at the position to the new | 564 | /// Returns the edit required to rename reference at the position to the new |
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs index 0085d0e4d..74f784338 100644 --- a/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/crates/rust-analyzer/src/cli/diagnostics.rs | |||
@@ -57,7 +57,8 @@ pub fn diagnostics( | |||
57 | let crate_name = | 57 | let crate_name = |
58 | module.krate().display_name(db).as_deref().unwrap_or("unknown").to_string(); | 58 | module.krate().display_name(db).as_deref().unwrap_or("unknown").to_string(); |
59 | println!("processing crate: {}, module: {}", crate_name, _vfs.file_path(file_id)); | 59 | println!("processing crate: {}, module: {}", crate_name, _vfs.file_path(file_id)); |
60 | for diagnostic in analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap() | 60 | for diagnostic in |
61 | analysis.diagnostics(&DiagnosticsConfig::default(), false, file_id).unwrap() | ||
61 | { | 62 | { |
62 | if matches!(diagnostic.severity, Severity::Error) { | 63 | if matches!(diagnostic.severity, Severity::Error) { |
63 | found_error = true; | 64 | found_error = true; |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 85c70373a..4f0c9d23c 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -8,8 +8,8 @@ use std::{ | |||
8 | }; | 8 | }; |
9 | 9 | ||
10 | use ide::{ | 10 | use ide::{ |
11 | AnnotationConfig, AssistKind, FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, | 11 | AnnotationConfig, FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, Query, |
12 | Query, RangeInfo, Runnable, RunnableKind, SearchScope, SourceChange, TextEdit, | 12 | RangeInfo, Runnable, RunnableKind, SearchScope, SourceChange, TextEdit, |
13 | }; | 13 | }; |
14 | use ide_db::SymbolKind; | 14 | use ide_db::SymbolKind; |
15 | use itertools::Itertools; | 15 | use itertools::Itertools; |
@@ -1003,27 +1003,13 @@ pub(crate) fn handle_code_action( | |||
1003 | 1003 | ||
1004 | let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); | 1004 | let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); |
1005 | 1005 | ||
1006 | let include_quick_fixes = match &assists_config.allowed { | ||
1007 | Some(v) => v.iter().any(|it| it == &AssistKind::None || it == &AssistKind::QuickFix), | ||
1008 | None => true, | ||
1009 | }; | ||
1010 | let code_action_resolve_cap = snap.config.code_action_resolve(); | 1006 | let code_action_resolve_cap = snap.config.code_action_resolve(); |
1011 | 1007 | let assists = snap.analysis.assists_with_fixes( | |
1012 | let mut assists = Vec::new(); | 1008 | &assists_config, |
1013 | 1009 | &snap.config.diagnostics(), | |
1014 | // Fixes from native diagnostics. | 1010 | !code_action_resolve_cap, |
1015 | if include_quick_fixes { | 1011 | frange, |
1016 | let diagnostics = snap.analysis.diagnostics(&snap.config.diagnostics(), frange.file_id)?; | 1012 | )?; |
1017 | assists.extend( | ||
1018 | diagnostics | ||
1019 | .into_iter() | ||
1020 | .filter_map(|d| d.fix) | ||
1021 | .filter(|fix| fix.target.intersect(frange.range).is_some()), | ||
1022 | ) | ||
1023 | } | ||
1024 | |||
1025 | // Assists proper. | ||
1026 | assists.extend(snap.analysis.assists(&assists_config, !code_action_resolve_cap, frange)?); | ||
1027 | for (index, assist) in assists.into_iter().enumerate() { | 1013 | for (index, assist) in assists.into_iter().enumerate() { |
1028 | let resolve_data = | 1014 | let resolve_data = |
1029 | if code_action_resolve_cap { Some((index, params.clone())) } else { None }; | 1015 | if code_action_resolve_cap { Some((index, params.clone())) } else { None }; |
@@ -1066,7 +1052,13 @@ pub(crate) fn handle_code_action_resolve( | |||
1066 | .only | 1052 | .only |
1067 | .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()); | 1053 | .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()); |
1068 | 1054 | ||
1069 | let assists = snap.analysis.assists(&assists_config, true, frange)?; | 1055 | let assists = snap.analysis.assists_with_fixes( |
1056 | &assists_config, | ||
1057 | &snap.config.diagnostics(), | ||
1058 | true, | ||
1059 | frange, | ||
1060 | )?; | ||
1061 | |||
1070 | let (id, index) = split_once(¶ms.id, ':').unwrap(); | 1062 | let (id, index) = split_once(¶ms.id, ':').unwrap(); |
1071 | let index = index.parse::<usize>().unwrap(); | 1063 | let index = index.parse::<usize>().unwrap(); |
1072 | let assist = &assists[index]; | 1064 | let assist = &assists[index]; |
@@ -1190,7 +1182,7 @@ pub(crate) fn publish_diagnostics( | |||
1190 | 1182 | ||
1191 | let diagnostics: Vec<Diagnostic> = snap | 1183 | let diagnostics: Vec<Diagnostic> = snap |
1192 | .analysis | 1184 | .analysis |
1193 | .diagnostics(&snap.config.diagnostics(), file_id)? | 1185 | .diagnostics(&snap.config.diagnostics(), false, file_id)? |
1194 | .into_iter() | 1186 | .into_iter() |
1195 | .map(|d| Diagnostic { | 1187 | .map(|d| Diagnostic { |
1196 | range: to_proto::range(&line_index, d.range), | 1188 | range: to_proto::range(&line_index, d.range), |
diff --git a/crates/rust-analyzer/tests/rust-analyzer/support.rs b/crates/rust-analyzer/tests/rust-analyzer/support.rs index 5e388c0f0..75e677762 100644 --- a/crates/rust-analyzer/tests/rust-analyzer/support.rs +++ b/crates/rust-analyzer/tests/rust-analyzer/support.rs | |||
@@ -168,6 +168,7 @@ impl Server { | |||
168 | self.send_notification(r) | 168 | self.send_notification(r) |
169 | } | 169 | } |
170 | 170 | ||
171 | #[track_caller] | ||
171 | pub(crate) fn request<R>(&self, params: R::Params, expected_resp: Value) | 172 | pub(crate) fn request<R>(&self, params: R::Params, expected_resp: Value) |
172 | where | 173 | where |
173 | R: lsp_types::request::Request, | 174 | R: lsp_types::request::Request, |