diff options
Diffstat (limited to 'crates/ide')
-rw-r--r-- | crates/ide/src/diagnostics.rs | 74 | ||||
-rw-r--r-- | crates/ide/src/lib.rs | 13 |
2 files changed, 51 insertions, 36 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 606a6064b..89ff55490 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -4,12 +4,15 @@ | |||
4 | //! macro-expanded files, but we need to present them to the users in terms of | 4 | //! macro-expanded files, but we need to present them to the users in terms of |
5 | //! original files. So we need to map the ranges. | 5 | //! original files. So we need to map the ranges. |
6 | 6 | ||
7 | use std::{cell::RefCell, collections::HashSet}; | 7 | mod diagnostics_with_fix; |
8 | |||
9 | use std::cell::RefCell; | ||
8 | 10 | ||
9 | use base_db::SourceDatabase; | 11 | use base_db::SourceDatabase; |
10 | use hir::{diagnostics::DiagnosticSinkBuilder, Semantics}; | 12 | use hir::{diagnostics::DiagnosticSinkBuilder, Semantics}; |
11 | use ide_db::RootDatabase; | 13 | use ide_db::RootDatabase; |
12 | use itertools::Itertools; | 14 | use itertools::Itertools; |
15 | use rustc_hash::FxHashSet; | ||
13 | use syntax::{ | 16 | use syntax::{ |
14 | ast::{self, AstNode}, | 17 | ast::{self, AstNode}, |
15 | SyntaxNode, TextRange, T, | 18 | SyntaxNode, TextRange, T, |
@@ -18,8 +21,7 @@ use text_edit::TextEdit; | |||
18 | 21 | ||
19 | use crate::{Diagnostic, FileId, Fix, SourceFileEdit}; | 22 | use crate::{Diagnostic, FileId, Fix, SourceFileEdit}; |
20 | 23 | ||
21 | mod diagnostics_with_fix; | 24 | use self::diagnostics_with_fix::DiagnosticWithFix; |
22 | use diagnostics_with_fix::DiagnosticWithFix; | ||
23 | 25 | ||
24 | #[derive(Debug, Copy, Clone)] | 26 | #[derive(Debug, Copy, Clone)] |
25 | pub enum Severity { | 27 | pub enum Severity { |
@@ -27,11 +29,16 @@ pub enum Severity { | |||
27 | WeakWarning, | 29 | WeakWarning, |
28 | } | 30 | } |
29 | 31 | ||
32 | #[derive(Default, Debug, Clone)] | ||
33 | pub struct DiagnosticsConfig { | ||
34 | pub disable_experimental: bool, | ||
35 | pub disabled: FxHashSet<String>, | ||
36 | } | ||
37 | |||
30 | pub(crate) fn diagnostics( | 38 | pub(crate) fn diagnostics( |
31 | db: &RootDatabase, | 39 | db: &RootDatabase, |
40 | config: &DiagnosticsConfig, | ||
32 | file_id: FileId, | 41 | file_id: FileId, |
33 | enable_experimental: bool, | ||
34 | disabled_diagnostics: Option<HashSet<String>>, | ||
35 | ) -> Vec<Diagnostic> { | 42 | ) -> Vec<Diagnostic> { |
36 | let _p = profile::span("diagnostics"); | 43 | let _p = profile::span("diagnostics"); |
37 | let sema = Semantics::new(db); | 44 | let sema = Semantics::new(db); |
@@ -52,7 +59,7 @@ pub(crate) fn diagnostics( | |||
52 | check_struct_shorthand_initialization(&mut res, file_id, &node); | 59 | check_struct_shorthand_initialization(&mut res, file_id, &node); |
53 | } | 60 | } |
54 | let res = RefCell::new(res); | 61 | let res = RefCell::new(res); |
55 | let mut sink_builder = DiagnosticSinkBuilder::new() | 62 | let sink_builder = DiagnosticSinkBuilder::new() |
56 | .on::<hir::diagnostics::UnresolvedModule, _>(|d| { | 63 | .on::<hir::diagnostics::UnresolvedModule, _>(|d| { |
57 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); | 64 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); |
58 | }) | 65 | }) |
@@ -66,12 +73,8 @@ pub(crate) fn diagnostics( | |||
66 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); | 73 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); |
67 | }) | 74 | }) |
68 | // Only collect experimental diagnostics when they're enabled. | 75 | // Only collect experimental diagnostics when they're enabled. |
69 | .filter(|diag| !diag.is_experimental() || enable_experimental); | 76 | .filter(|diag| !(diag.is_experimental() && config.disable_experimental)) |
70 | 77 | .filter(|diag| !config.disabled.contains(diag.name())); | |
71 | if let Some(disabled_diagnostics) = disabled_diagnostics { | ||
72 | // Do not collect disabled diagnostics. | ||
73 | sink_builder = sink_builder.filter(move |diag| !disabled_diagnostics.contains(diag.name())); | ||
74 | } | ||
75 | 78 | ||
76 | // Finalize the `DiagnosticSink` building process. | 79 | // Finalize the `DiagnosticSink` building process. |
77 | let mut sink = sink_builder | 80 | let mut sink = sink_builder |
@@ -187,12 +190,14 @@ fn check_struct_shorthand_initialization( | |||
187 | 190 | ||
188 | #[cfg(test)] | 191 | #[cfg(test)] |
189 | mod tests { | 192 | mod tests { |
190 | use std::collections::HashSet; | 193 | use expect::{expect, Expect}; |
191 | use stdx::trim_indent; | 194 | use stdx::trim_indent; |
192 | use test_utils::assert_eq_text; | 195 | use test_utils::assert_eq_text; |
193 | 196 | ||
194 | use crate::mock_analysis::{analysis_and_position, single_file, MockAnalysis}; | 197 | use crate::{ |
195 | use expect::{expect, Expect}; | 198 | mock_analysis::{analysis_and_position, single_file, MockAnalysis}, |
199 | DiagnosticsConfig, | ||
200 | }; | ||
196 | 201 | ||
197 | /// Takes a multi-file input fixture with annotated cursor positions, | 202 | /// Takes a multi-file input fixture with annotated cursor positions, |
198 | /// and checks that: | 203 | /// and checks that: |
@@ -203,8 +208,11 @@ mod tests { | |||
203 | let after = trim_indent(ra_fixture_after); | 208 | let after = trim_indent(ra_fixture_after); |
204 | 209 | ||
205 | let (analysis, file_position) = analysis_and_position(ra_fixture_before); | 210 | let (analysis, file_position) = analysis_and_position(ra_fixture_before); |
206 | let diagnostic = | 211 | let diagnostic = analysis |
207 | analysis.diagnostics(file_position.file_id, true, None).unwrap().pop().unwrap(); | 212 | .diagnostics(&DiagnosticsConfig::default(), file_position.file_id) |
213 | .unwrap() | ||
214 | .pop() | ||
215 | .unwrap(); | ||
208 | let mut fix = diagnostic.fix.unwrap(); | 216 | let mut fix = diagnostic.fix.unwrap(); |
209 | let edit = fix.source_change.source_file_edits.pop().unwrap().edit; | 217 | let edit = fix.source_change.source_file_edits.pop().unwrap().edit; |
210 | let target_file_contents = analysis.file_text(file_position.file_id).unwrap(); | 218 | let target_file_contents = analysis.file_text(file_position.file_id).unwrap(); |
@@ -230,7 +238,11 @@ mod tests { | |||
230 | let ra_fixture_after = &trim_indent(ra_fixture_after); | 238 | let ra_fixture_after = &trim_indent(ra_fixture_after); |
231 | let (analysis, file_pos) = analysis_and_position(ra_fixture_before); | 239 | let (analysis, file_pos) = analysis_and_position(ra_fixture_before); |
232 | let current_file_id = file_pos.file_id; | 240 | let current_file_id = file_pos.file_id; |
233 | let diagnostic = analysis.diagnostics(current_file_id, true, None).unwrap().pop().unwrap(); | 241 | let diagnostic = analysis |
242 | .diagnostics(&DiagnosticsConfig::default(), current_file_id) | ||
243 | .unwrap() | ||
244 | .pop() | ||
245 | .unwrap(); | ||
234 | let mut fix = diagnostic.fix.unwrap(); | 246 | let mut fix = diagnostic.fix.unwrap(); |
235 | let edit = fix.source_change.source_file_edits.pop().unwrap(); | 247 | let edit = fix.source_change.source_file_edits.pop().unwrap(); |
236 | let changed_file_id = edit.file_id; | 248 | let changed_file_id = edit.file_id; |
@@ -251,7 +263,9 @@ mod tests { | |||
251 | let analysis = mock.analysis(); | 263 | let analysis = mock.analysis(); |
252 | let diagnostics = files | 264 | let diagnostics = files |
253 | .into_iter() | 265 | .into_iter() |
254 | .flat_map(|file_id| analysis.diagnostics(file_id, true, None).unwrap()) | 266 | .flat_map(|file_id| { |
267 | analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap() | ||
268 | }) | ||
255 | .collect::<Vec<_>>(); | 269 | .collect::<Vec<_>>(); |
256 | assert_eq!(diagnostics.len(), 0, "unexpected diagnostics:\n{:#?}", diagnostics); | 270 | assert_eq!(diagnostics.len(), 0, "unexpected diagnostics:\n{:#?}", diagnostics); |
257 | } | 271 | } |
@@ -259,8 +273,8 @@ mod tests { | |||
259 | /// Takes a multi-file input fixture with annotated cursor position and the list of disabled diagnostics, | 273 | /// Takes a multi-file input fixture with annotated cursor position and the list of disabled diagnostics, |
260 | /// and checks that provided diagnostics aren't spawned during analysis. | 274 | /// and checks that provided diagnostics aren't spawned during analysis. |
261 | fn check_disabled_diagnostics(ra_fixture: &str, disabled_diagnostics: &[&'static str]) { | 275 | fn check_disabled_diagnostics(ra_fixture: &str, disabled_diagnostics: &[&'static str]) { |
262 | let disabled_diagnostics: HashSet<_> = | 276 | let mut config = DiagnosticsConfig::default(); |
263 | disabled_diagnostics.into_iter().map(|diag| diag.to_string()).collect(); | 277 | config.disabled = disabled_diagnostics.into_iter().map(|diag| diag.to_string()).collect(); |
264 | 278 | ||
265 | let mock = MockAnalysis::with_files(ra_fixture); | 279 | let mock = MockAnalysis::with_files(ra_fixture); |
266 | let files = mock.files().map(|(it, _)| it).collect::<Vec<_>>(); | 280 | let files = mock.files().map(|(it, _)| it).collect::<Vec<_>>(); |
@@ -269,15 +283,17 @@ mod tests { | |||
269 | let diagnostics = files | 283 | let diagnostics = files |
270 | .clone() | 284 | .clone() |
271 | .into_iter() | 285 | .into_iter() |
272 | .flat_map(|file_id| { | 286 | .flat_map(|file_id| analysis.diagnostics(&config, file_id).unwrap()) |
273 | analysis.diagnostics(file_id, true, Some(disabled_diagnostics.clone())).unwrap() | ||
274 | }) | ||
275 | .collect::<Vec<_>>(); | 287 | .collect::<Vec<_>>(); |
276 | 288 | ||
277 | // First, we have to check that diagnostic is not emitted when it's added to the disabled diagnostics list. | 289 | // First, we have to check that diagnostic is not emitted when it's added to the disabled diagnostics list. |
278 | for diagnostic in diagnostics { | 290 | for diagnostic in diagnostics { |
279 | if let Some(name) = diagnostic.name { | 291 | if let Some(name) = diagnostic.name { |
280 | assert!(!disabled_diagnostics.contains(&name), "Diagnostic {} is disabled", name); | 292 | assert!( |
293 | !disabled_diagnostics.contains(&name.as_str()), | ||
294 | "Diagnostic {} is disabled", | ||
295 | name | ||
296 | ); | ||
281 | } | 297 | } |
282 | } | 298 | } |
283 | 299 | ||
@@ -288,21 +304,23 @@ mod tests { | |||
288 | // will no longer exist. | 304 | // will no longer exist. |
289 | let diagnostics = files | 305 | let diagnostics = files |
290 | .into_iter() | 306 | .into_iter() |
291 | .flat_map(|file_id| analysis.diagnostics(file_id, true, None).unwrap()) | 307 | .flat_map(|file_id| { |
308 | analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap() | ||
309 | }) | ||
292 | .collect::<Vec<_>>(); | 310 | .collect::<Vec<_>>(); |
293 | 311 | ||
294 | assert!( | 312 | assert!( |
295 | diagnostics | 313 | diagnostics |
296 | .into_iter() | 314 | .into_iter() |
297 | .filter_map(|diag| diag.name) | 315 | .filter_map(|diag| diag.name) |
298 | .any(|name| disabled_diagnostics.contains(&name)), | 316 | .any(|name| disabled_diagnostics.contains(&name.as_str())), |
299 | "At least one of the diagnostics was not emitted even without config; are the diagnostics names correct?" | 317 | "At least one of the diagnostics was not emitted even without config; are the diagnostics names correct?" |
300 | ); | 318 | ); |
301 | } | 319 | } |
302 | 320 | ||
303 | fn check_expect(ra_fixture: &str, expect: Expect) { | 321 | fn check_expect(ra_fixture: &str, expect: Expect) { |
304 | let (analysis, file_id) = single_file(ra_fixture); | 322 | let (analysis, file_id) = single_file(ra_fixture); |
305 | let diagnostics = analysis.diagnostics(file_id, true, None).unwrap(); | 323 | let diagnostics = analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap(); |
306 | expect.assert_debug_eq(&diagnostics) | 324 | expect.assert_debug_eq(&diagnostics) |
307 | } | 325 | } |
308 | 326 | ||
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 4b797f374..2a73abba2 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -44,7 +44,7 @@ mod syntax_highlighting; | |||
44 | mod syntax_tree; | 44 | mod syntax_tree; |
45 | mod typing; | 45 | mod typing; |
46 | 46 | ||
47 | use std::{collections::HashSet, sync::Arc}; | 47 | use std::sync::Arc; |
48 | 48 | ||
49 | use base_db::{ | 49 | use base_db::{ |
50 | salsa::{self, ParallelDatabase}, | 50 | salsa::{self, ParallelDatabase}, |
@@ -65,7 +65,7 @@ pub use crate::{ | |||
65 | completion::{ | 65 | completion::{ |
66 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat, | 66 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat, |
67 | }, | 67 | }, |
68 | diagnostics::Severity, | 68 | diagnostics::{DiagnosticsConfig, Severity}, |
69 | display::NavigationTarget, | 69 | display::NavigationTarget, |
70 | expand_macro::ExpandedMacro, | 70 | expand_macro::ExpandedMacro, |
71 | file_structure::StructureNode, | 71 | file_structure::StructureNode, |
@@ -148,7 +148,7 @@ pub struct AnalysisHost { | |||
148 | } | 148 | } |
149 | 149 | ||
150 | impl AnalysisHost { | 150 | impl AnalysisHost { |
151 | pub fn new(lru_capacity: Option<usize>) -> Self { | 151 | pub fn new(lru_capacity: Option<usize>) -> AnalysisHost { |
152 | AnalysisHost { db: RootDatabase::new(lru_capacity) } | 152 | AnalysisHost { db: RootDatabase::new(lru_capacity) } |
153 | } | 153 | } |
154 | 154 | ||
@@ -495,13 +495,10 @@ impl Analysis { | |||
495 | /// Computes the set of diagnostics for the given file. | 495 | /// Computes the set of diagnostics for the given file. |
496 | pub fn diagnostics( | 496 | pub fn diagnostics( |
497 | &self, | 497 | &self, |
498 | config: &DiagnosticsConfig, | ||
498 | file_id: FileId, | 499 | file_id: FileId, |
499 | enable_experimental: bool, | ||
500 | disabled_diagnostics: Option<HashSet<String>>, | ||
501 | ) -> Cancelable<Vec<Diagnostic>> { | 500 | ) -> Cancelable<Vec<Diagnostic>> { |
502 | self.with_db(|db| { | 501 | self.with_db(|db| diagnostics::diagnostics(db, config, file_id)) |
503 | diagnostics::diagnostics(db, file_id, enable_experimental, disabled_diagnostics) | ||
504 | }) | ||
505 | } | 502 | } |
506 | 503 | ||
507 | /// Returns the edit required to rename reference at the position to the new | 504 | /// Returns the edit required to rename reference at the position to the new |