aboutsummaryrefslogtreecommitdiff
path: root/crates/ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide')
-rw-r--r--crates/ide/src/diagnostics.rs74
-rw-r--r--crates/ide/src/lib.rs13
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
7use std::{cell::RefCell, collections::HashSet}; 7mod diagnostics_with_fix;
8
9use std::cell::RefCell;
8 10
9use base_db::SourceDatabase; 11use base_db::SourceDatabase;
10use hir::{diagnostics::DiagnosticSinkBuilder, Semantics}; 12use hir::{diagnostics::DiagnosticSinkBuilder, Semantics};
11use ide_db::RootDatabase; 13use ide_db::RootDatabase;
12use itertools::Itertools; 14use itertools::Itertools;
15use rustc_hash::FxHashSet;
13use syntax::{ 16use 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
19use crate::{Diagnostic, FileId, Fix, SourceFileEdit}; 22use crate::{Diagnostic, FileId, Fix, SourceFileEdit};
20 23
21mod diagnostics_with_fix; 24use self::diagnostics_with_fix::DiagnosticWithFix;
22use diagnostics_with_fix::DiagnosticWithFix;
23 25
24#[derive(Debug, Copy, Clone)] 26#[derive(Debug, Copy, Clone)]
25pub enum Severity { 27pub enum Severity {
@@ -27,11 +29,16 @@ pub enum Severity {
27 WeakWarning, 29 WeakWarning,
28} 30}
29 31
32#[derive(Default, Debug, Clone)]
33pub struct DiagnosticsConfig {
34 pub disable_experimental: bool,
35 pub disabled: FxHashSet<String>,
36}
37
30pub(crate) fn diagnostics( 38pub(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)]
189mod tests { 192mod 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;
44mod syntax_tree; 44mod syntax_tree;
45mod typing; 45mod typing;
46 46
47use std::{collections::HashSet, sync::Arc}; 47use std::sync::Arc;
48 48
49use base_db::{ 49use 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
150impl AnalysisHost { 150impl 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