aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/diagnostics.rs4
-rw-r--r--crates/ra_hir_expand/src/diagnostics.rs60
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs7
-rw-r--r--crates/ra_ide/src/diagnostics.rs156
-rw-r--r--crates/ra_ide/src/lib.rs8
-rw-r--r--crates/rust-analyzer/src/cli/analysis_bench.rs2
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs2
-rw-r--r--crates/rust-analyzer/src/config.rs4
-rw-r--r--crates/rust-analyzer/src/handlers.rs4
-rw-r--r--editors/code/package.json15
10 files changed, 159 insertions, 103 deletions
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs
index 11a0ecb8b..266b513dc 100644
--- a/crates/ra_hir/src/diagnostics.rs
+++ b/crates/ra_hir/src/diagnostics.rs
@@ -1,6 +1,8 @@
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::{AstDiagnostic, Diagnostic, DiagnosticSink}; 3pub use hir_expand::diagnostics::{
4 AstDiagnostic, Diagnostic, DiagnosticSink, DiagnosticSinkBuilder,
5};
4pub use hir_ty::diagnostics::{ 6pub use hir_ty::diagnostics::{
5 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField, 7 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField,
6}; 8};
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs
index 545cff9bd..84ba97b14 100644
--- a/crates/ra_hir_expand/src/diagnostics.rs
+++ b/crates/ra_hir_expand/src/diagnostics.rs
@@ -24,6 +24,9 @@ pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
24 fn message(&self) -> String; 24 fn message(&self) -> String;
25 fn source(&self) -> InFile<SyntaxNodePtr>; 25 fn source(&self) -> InFile<SyntaxNodePtr>;
26 fn as_any(&self) -> &(dyn Any + Send + 'static); 26 fn as_any(&self) -> &(dyn Any + Send + 'static);
27 fn is_experimental(&self) -> bool {
28 false
29 }
27} 30}
28 31
29pub trait AstDiagnostic { 32pub trait AstDiagnostic {
@@ -44,16 +47,48 @@ impl dyn Diagnostic {
44 47
45pub struct DiagnosticSink<'a> { 48pub struct DiagnosticSink<'a> {
46 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>, 49 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
50 filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>,
47 default_callback: Box<dyn FnMut(&dyn Diagnostic) + 'a>, 51 default_callback: Box<dyn FnMut(&dyn Diagnostic) + 'a>,
48} 52}
49 53
50impl<'a> DiagnosticSink<'a> { 54impl<'a> DiagnosticSink<'a> {
51 /// FIXME: split `new` and `on` into a separate builder type 55 pub fn push(&mut self, d: impl Diagnostic) {
52 pub fn new(cb: impl FnMut(&dyn Diagnostic) + 'a) -> DiagnosticSink<'a> { 56 let d: &dyn Diagnostic = &d;
53 DiagnosticSink { callbacks: Vec::new(), default_callback: Box::new(cb) } 57 self._push(d);
58 }
59
60 fn _push(&mut self, d: &dyn Diagnostic) {
61 for filter in &mut self.filters {
62 if !filter(d) {
63 return;
64 }
65 }
66 for cb in &mut self.callbacks {
67 match cb(d) {
68 Ok(()) => return,
69 Err(()) => (),
70 }
71 }
72 (self.default_callback)(d)
54 } 73 }
74}
55 75
56 pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> DiagnosticSink<'a> { 76pub struct DiagnosticSinkBuilder<'a> {
77 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
78 filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>,
79}
80
81impl<'a> DiagnosticSinkBuilder<'a> {
82 pub fn new() -> Self {
83 Self { callbacks: Vec::new(), filters: Vec::new() }
84 }
85
86 pub fn filter<F: FnMut(&dyn Diagnostic) -> bool + 'a>(mut self, cb: F) -> Self {
87 self.filters.push(Box::new(cb));
88 self
89 }
90
91 pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> Self {
57 let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() { 92 let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() {
58 Some(d) => { 93 Some(d) => {
59 cb(d); 94 cb(d);
@@ -65,18 +100,11 @@ impl<'a> DiagnosticSink<'a> {
65 self 100 self
66 } 101 }
67 102
68 pub fn push(&mut self, d: impl Diagnostic) { 103 pub fn build<F: FnMut(&dyn Diagnostic) + 'a>(self, default_callback: F) -> DiagnosticSink<'a> {
69 let d: &dyn Diagnostic = &d; 104 DiagnosticSink {
70 self._push(d); 105 callbacks: self.callbacks,
71 } 106 filters: self.filters,
72 107 default_callback: Box::new(default_callback),
73 fn _push(&mut self, d: &dyn Diagnostic) {
74 for cb in self.callbacks.iter_mut() {
75 match cb(d) {
76 Ok(()) => return,
77 Err(()) => (),
78 }
79 } 108 }
80 (self.default_callback)(d)
81 } 109 }
82} 110}
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index d3ee9cf55..885abbaf2 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -234,6 +234,9 @@ impl Diagnostic for MismatchedArgCount {
234 fn as_any(&self) -> &(dyn Any + Send + 'static) { 234 fn as_any(&self) -> &(dyn Any + Send + 'static) {
235 self 235 self
236 } 236 }
237 fn is_experimental(&self) -> bool {
238 true
239 }
237} 240}
238 241
239impl AstDiagnostic for MismatchedArgCount { 242impl AstDiagnostic for MismatchedArgCount {
@@ -248,7 +251,7 @@ impl AstDiagnostic for MismatchedArgCount {
248#[cfg(test)] 251#[cfg(test)]
249mod tests { 252mod tests {
250 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId}; 253 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId};
251 use hir_expand::diagnostics::{Diagnostic, DiagnosticSink}; 254 use hir_expand::diagnostics::{Diagnostic, DiagnosticSinkBuilder};
252 use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; 255 use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt};
253 use ra_syntax::{TextRange, TextSize}; 256 use ra_syntax::{TextRange, TextSize};
254 use rustc_hash::FxHashMap; 257 use rustc_hash::FxHashMap;
@@ -280,7 +283,7 @@ mod tests {
280 } 283 }
281 284
282 for f in fns { 285 for f in fns {
283 let mut sink = DiagnosticSink::new(&mut cb); 286 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
284 validate_body(self, f.into(), &mut sink); 287 validate_body(self, f.into(), &mut sink);
285 } 288 }
286 } 289 }
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs
index e029af0dc..897177d05 100644
--- a/crates/ra_ide/src/diagnostics.rs
+++ b/crates/ra_ide/src/diagnostics.rs
@@ -7,7 +7,7 @@
7use std::cell::RefCell; 7use std::cell::RefCell;
8 8
9use hir::{ 9use hir::{
10 diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSink}, 10 diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSinkBuilder},
11 HasSource, HirDisplay, Semantics, VariantDef, 11 HasSource, HirDisplay, Semantics, VariantDef,
12}; 12};
13use itertools::Itertools; 13use itertools::Itertools;
@@ -29,7 +29,11 @@ pub enum Severity {
29 WeakWarning, 29 WeakWarning,
30} 30}
31 31
32pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> { 32pub(crate) fn diagnostics(
33 db: &RootDatabase,
34 file_id: FileId,
35 enable_experimental: bool,
36) -> Vec<Diagnostic> {
33 let _p = profile("diagnostics"); 37 let _p = profile("diagnostics");
34 let sema = Semantics::new(db); 38 let sema = Semantics::new(db);
35 let parse = db.parse(file_id); 39 let parse = db.parse(file_id);
@@ -48,79 +52,85 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
48 check_struct_shorthand_initialization(&mut res, file_id, &node); 52 check_struct_shorthand_initialization(&mut res, file_id, &node);
49 } 53 }
50 let res = RefCell::new(res); 54 let res = RefCell::new(res);
51 let mut sink = DiagnosticSink::new(|d| { 55 let mut sink = DiagnosticSinkBuilder::new()
52 res.borrow_mut().push(Diagnostic { 56 .on::<hir::diagnostics::UnresolvedModule, _>(|d| {
53 message: d.message(), 57 let original_file = d.source().file_id.original_file(db);
54 range: sema.diagnostics_range(d).range, 58 let fix = Fix::new(
55 severity: Severity::Error, 59 "Create module",
56 fix: None, 60 FileSystemEdit::CreateFile { anchor: original_file, dst: d.candidate.clone() }
57 }) 61 .into(),
58 }) 62 );
59 .on::<hir::diagnostics::UnresolvedModule, _>(|d| { 63 res.borrow_mut().push(Diagnostic {
60 let original_file = d.source().file_id.original_file(db); 64 range: sema.diagnostics_range(d).range,
61 let fix = Fix::new( 65 message: d.message(),
62 "Create module", 66 severity: Severity::Error,
63 FileSystemEdit::CreateFile { anchor: original_file, dst: d.candidate.clone() }.into(), 67 fix: Some(fix),
64 ); 68 })
65 res.borrow_mut().push(Diagnostic {
66 range: sema.diagnostics_range(d).range,
67 message: d.message(),
68 severity: Severity::Error,
69 fix: Some(fix),
70 }) 69 })
71 }) 70 .on::<hir::diagnostics::MissingFields, _>(|d| {
72 .on::<hir::diagnostics::MissingFields, _>(|d| { 71 // Note that although we could add a diagnostics to
73 // Note that although we could add a diagnostics to 72 // fill the missing tuple field, e.g :
74 // fill the missing tuple field, e.g : 73 // `struct A(usize);`
75 // `struct A(usize);` 74 // `let a = A { 0: () }`
76 // `let a = A { 0: () }` 75 // but it is uncommon usage and it should not be encouraged.
77 // but it is uncommon usage and it should not be encouraged. 76 let fix = if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
78 let fix = if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) { 77 None
79 None 78 } else {
80 } else { 79 let mut field_list = d.ast(db);
81 let mut field_list = d.ast(db); 80 for f in d.missed_fields.iter() {
82 for f in d.missed_fields.iter() { 81 let field =
83 let field = 82 make::record_field(make::name_ref(&f.to_string()), Some(make::expr_unit()));
84 make::record_field(make::name_ref(&f.to_string()), Some(make::expr_unit())); 83 field_list = field_list.append_field(&field);
85 field_list = field_list.append_field(&field); 84 }
86 } 85
87 86 let edit = {
88 let edit = { 87 let mut builder = TextEditBuilder::default();
89 let mut builder = TextEditBuilder::default(); 88 algo::diff(&d.ast(db).syntax(), &field_list.syntax())
90 algo::diff(&d.ast(db).syntax(), &field_list.syntax()).into_text_edit(&mut builder); 89 .into_text_edit(&mut builder);
91 builder.finish() 90 builder.finish()
91 };
92 Some(Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into()))
92 }; 93 };
93 Some(Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into()))
94 };
95 94
96 res.borrow_mut().push(Diagnostic { 95 res.borrow_mut().push(Diagnostic {
97 range: sema.diagnostics_range(d).range, 96 range: sema.diagnostics_range(d).range,
98 message: d.message(), 97 message: d.message(),
99 severity: Severity::Error, 98 severity: Severity::Error,
100 fix, 99 fix,
100 })
101 }) 101 })
102 }) 102 .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| {
103 .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| { 103 let node = d.ast(db);
104 let node = d.ast(db); 104 let replacement = format!("Ok({})", node.syntax());
105 let replacement = format!("Ok({})", node.syntax()); 105 let edit = TextEdit::replace(node.syntax().text_range(), replacement);
106 let edit = TextEdit::replace(node.syntax().text_range(), replacement); 106 let source_change = SourceFileEdit { file_id, edit }.into();
107 let source_change = SourceFileEdit { file_id, edit }.into(); 107 let fix = Fix::new("Wrap with ok", source_change);
108 let fix = Fix::new("Wrap with ok", source_change); 108 res.borrow_mut().push(Diagnostic {
109 res.borrow_mut().push(Diagnostic { 109 range: sema.diagnostics_range(d).range,
110 range: sema.diagnostics_range(d).range, 110 message: d.message(),
111 message: d.message(), 111 severity: Severity::Error,
112 severity: Severity::Error, 112 fix: Some(fix),
113 fix: Some(fix), 113 })
114 }) 114 })
115 }) 115 .on::<hir::diagnostics::NoSuchField, _>(|d| {
116 .on::<hir::diagnostics::NoSuchField, _>(|d| { 116 res.borrow_mut().push(Diagnostic {
117 res.borrow_mut().push(Diagnostic { 117 range: sema.diagnostics_range(d).range,
118 range: sema.diagnostics_range(d).range, 118 message: d.message(),
119 message: d.message(), 119 severity: Severity::Error,
120 severity: Severity::Error, 120 fix: missing_struct_field_fix(&sema, file_id, d),
121 fix: missing_struct_field_fix(&sema, file_id, d), 121 })
122 }) 122 })
123 }); 123 // Only collect experimental diagnostics when they're enabled.
124 .filter(|diag| !diag.is_experimental() || enable_experimental)
125 // Diagnostics not handled above get no fix and default treatment.
126 .build(|d| {
127 res.borrow_mut().push(Diagnostic {
128 message: d.message(),
129 range: sema.diagnostics_range(d).range,
130 severity: Severity::Error,
131 fix: None,
132 })
133 });
124 134
125 if let Some(m) = sema.to_module_def(file_id) { 135 if let Some(m) = sema.to_module_def(file_id) {
126 m.diagnostics(db, &mut sink); 136 m.diagnostics(db, &mut sink);
@@ -298,7 +308,7 @@ mod tests {
298 let after = trim_indent(ra_fixture_after); 308 let after = trim_indent(ra_fixture_after);
299 309
300 let (analysis, file_position) = analysis_and_position(ra_fixture_before); 310 let (analysis, file_position) = analysis_and_position(ra_fixture_before);
301 let diagnostic = analysis.diagnostics(file_position.file_id).unwrap().pop().unwrap(); 311 let diagnostic = analysis.diagnostics(file_position.file_id, true).unwrap().pop().unwrap();
302 let mut fix = diagnostic.fix.unwrap(); 312 let mut fix = diagnostic.fix.unwrap();
303 let edit = fix.source_change.source_file_edits.pop().unwrap().edit; 313 let edit = fix.source_change.source_file_edits.pop().unwrap().edit;
304 let target_file_contents = analysis.file_text(file_position.file_id).unwrap(); 314 let target_file_contents = analysis.file_text(file_position.file_id).unwrap();
@@ -324,7 +334,7 @@ mod tests {
324 let ra_fixture_after = &trim_indent(ra_fixture_after); 334 let ra_fixture_after = &trim_indent(ra_fixture_after);
325 let (analysis, file_pos) = analysis_and_position(ra_fixture_before); 335 let (analysis, file_pos) = analysis_and_position(ra_fixture_before);
326 let current_file_id = file_pos.file_id; 336 let current_file_id = file_pos.file_id;
327 let diagnostic = analysis.diagnostics(current_file_id).unwrap().pop().unwrap(); 337 let diagnostic = analysis.diagnostics(current_file_id, true).unwrap().pop().unwrap();
328 let mut fix = diagnostic.fix.unwrap(); 338 let mut fix = diagnostic.fix.unwrap();
329 let edit = fix.source_change.source_file_edits.pop().unwrap(); 339 let edit = fix.source_change.source_file_edits.pop().unwrap();
330 let changed_file_id = edit.file_id; 340 let changed_file_id = edit.file_id;
@@ -345,14 +355,14 @@ mod tests {
345 let analysis = mock.analysis(); 355 let analysis = mock.analysis();
346 let diagnostics = files 356 let diagnostics = files
347 .into_iter() 357 .into_iter()
348 .flat_map(|file_id| analysis.diagnostics(file_id).unwrap()) 358 .flat_map(|file_id| analysis.diagnostics(file_id, true).unwrap())
349 .collect::<Vec<_>>(); 359 .collect::<Vec<_>>();
350 assert_eq!(diagnostics.len(), 0, "unexpected diagnostics:\n{:#?}", diagnostics); 360 assert_eq!(diagnostics.len(), 0, "unexpected diagnostics:\n{:#?}", diagnostics);
351 } 361 }
352 362
353 fn check_expect(ra_fixture: &str, expect: Expect) { 363 fn check_expect(ra_fixture: &str, expect: Expect) {
354 let (analysis, file_id) = single_file(ra_fixture); 364 let (analysis, file_id) = single_file(ra_fixture);
355 let diagnostics = analysis.diagnostics(file_id).unwrap(); 365 let diagnostics = analysis.diagnostics(file_id, true).unwrap();
356 expect.assert_debug_eq(&diagnostics) 366 expect.assert_debug_eq(&diagnostics)
357 } 367 }
358 368
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 7356e947b..4c4d9f6fa 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -487,8 +487,12 @@ impl Analysis {
487 } 487 }
488 488
489 /// Computes the set of diagnostics for the given file. 489 /// Computes the set of diagnostics for the given file.
490 pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { 490 pub fn diagnostics(
491 self.with_db(|db| diagnostics::diagnostics(db, file_id)) 491 &self,
492 file_id: FileId,
493 enable_experimental: bool,
494 ) -> Cancelable<Vec<Diagnostic>> {
495 self.with_db(|db| diagnostics::diagnostics(db, file_id, enable_experimental))
492 } 496 }
493 497
494 /// Returns the edit required to rename reference at the position to the new 498 /// Returns the edit required to rename reference at the position to the new
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs
index 9299879b7..076184ad6 100644
--- a/crates/rust-analyzer/src/cli/analysis_bench.rs
+++ b/crates/rust-analyzer/src/cli/analysis_bench.rs
@@ -70,7 +70,7 @@ pub fn analysis_bench(
70 match &what { 70 match &what {
71 BenchWhat::Highlight { .. } => { 71 BenchWhat::Highlight { .. } => {
72 let res = do_work(&mut host, file_id, |analysis| { 72 let res = do_work(&mut host, file_id, |analysis| {
73 analysis.diagnostics(file_id).unwrap(); 73 analysis.diagnostics(file_id, true).unwrap();
74 analysis.highlight_as_html(file_id, false).unwrap() 74 analysis.highlight_as_html(file_id, false).unwrap()
75 }); 75 });
76 if verbosity.is_verbose() { 76 if verbosity.is_verbose() {
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs
index 6f3c1c1f9..4ac8c8772 100644
--- a/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -47,7 +47,7 @@ pub fn diagnostics(
47 String::from("unknown") 47 String::from("unknown")
48 }; 48 };
49 println!("processing crate: {}, module: {}", crate_name, _vfs.file_path(file_id)); 49 println!("processing crate: {}, module: {}", crate_name, _vfs.file_path(file_id));
50 for diagnostic in analysis.diagnostics(file_id).unwrap() { 50 for diagnostic in analysis.diagnostics(file_id, true).unwrap() {
51 if matches!(diagnostic.severity, Severity::Error) { 51 if matches!(diagnostic.severity, Severity::Error) {
52 found_error = true; 52 found_error = true;
53 } 53 }
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 8947ccf07..e11c8b909 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -23,6 +23,7 @@ pub struct Config {
23 pub client_caps: ClientCapsConfig, 23 pub client_caps: ClientCapsConfig,
24 24
25 pub publish_diagnostics: bool, 25 pub publish_diagnostics: bool,
26 pub experimental_diagnostics: bool,
26 pub diagnostics: DiagnosticsConfig, 27 pub diagnostics: DiagnosticsConfig,
27 pub lru_capacity: Option<usize>, 28 pub lru_capacity: Option<usize>,
28 pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>, 29 pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>,
@@ -137,6 +138,7 @@ impl Config {
137 138
138 with_sysroot: true, 139 with_sysroot: true,
139 publish_diagnostics: true, 140 publish_diagnostics: true,
141 experimental_diagnostics: true,
140 diagnostics: DiagnosticsConfig::default(), 142 diagnostics: DiagnosticsConfig::default(),
141 lru_capacity: None, 143 lru_capacity: None,
142 proc_macro_srv: None, 144 proc_macro_srv: None,
@@ -187,6 +189,7 @@ impl Config {
187 189
188 self.with_sysroot = data.withSysroot; 190 self.with_sysroot = data.withSysroot;
189 self.publish_diagnostics = data.diagnostics_enable; 191 self.publish_diagnostics = data.diagnostics_enable;
192 self.experimental_diagnostics = data.diagnostics_enableExperimental;
190 self.diagnostics = DiagnosticsConfig { 193 self.diagnostics = DiagnosticsConfig {
191 warnings_as_info: data.diagnostics_warningsAsInfo, 194 warnings_as_info: data.diagnostics_warningsAsInfo,
192 warnings_as_hint: data.diagnostics_warningsAsHint, 195 warnings_as_hint: data.diagnostics_warningsAsHint,
@@ -405,6 +408,7 @@ config_data! {
405 completion_postfix_enable: bool = true, 408 completion_postfix_enable: bool = true,
406 409
407 diagnostics_enable: bool = true, 410 diagnostics_enable: bool = true,
411 diagnostics_enableExperimental: bool = true,
408 diagnostics_warningsAsHint: Vec<String> = Vec::new(), 412 diagnostics_warningsAsHint: Vec<String> = Vec::new(),
409 diagnostics_warningsAsInfo: Vec<String> = Vec::new(), 413 diagnostics_warningsAsInfo: Vec<String> = Vec::new(),
410 414
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index cad92c444..cd309ed74 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -774,7 +774,7 @@ fn handle_fixes(
774 None => {} 774 None => {}
775 }; 775 };
776 776
777 let diagnostics = snap.analysis.diagnostics(file_id)?; 777 let diagnostics = snap.analysis.diagnostics(file_id, snap.config.experimental_diagnostics)?;
778 778
779 let fixes_from_diagnostics = diagnostics 779 let fixes_from_diagnostics = diagnostics
780 .into_iter() 780 .into_iter()
@@ -1040,7 +1040,7 @@ pub(crate) fn publish_diagnostics(
1040 let line_index = snap.analysis.file_line_index(file_id)?; 1040 let line_index = snap.analysis.file_line_index(file_id)?;
1041 let diagnostics: Vec<Diagnostic> = snap 1041 let diagnostics: Vec<Diagnostic> = snap
1042 .analysis 1042 .analysis
1043 .diagnostics(file_id)? 1043 .diagnostics(file_id, snap.config.experimental_diagnostics)?
1044 .into_iter() 1044 .into_iter()
1045 .map(|d| Diagnostic { 1045 .map(|d| Diagnostic {
1046 range: to_proto::range(&line_index, d.range), 1046 range: to_proto::range(&line_index, d.range),
diff --git a/editors/code/package.json b/editors/code/package.json
index 448e2269f..658c913fd 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -200,11 +200,6 @@
200 "type": "object", 200 "type": "object",
201 "title": "Rust Analyzer", 201 "title": "Rust Analyzer",
202 "properties": { 202 "properties": {
203 "rust-analyzer.diagnostics.enable": {
204 "type": "boolean",
205 "default": true,
206 "markdownDescription": "Whether to show native rust-analyzer diagnostics."
207 },
208 "rust-analyzer.lruCapacity": { 203 "rust-analyzer.lruCapacity": {
209 "type": [ 204 "type": [
210 "null", 205 "null",
@@ -579,6 +574,16 @@
579 "type": "boolean", 574 "type": "boolean",
580 "default": true 575 "default": true
581 }, 576 },
577 "rust-analyzer.diagnostics.enable": {
578 "type": "boolean",
579 "default": true,
580 "markdownDescription": "Whether to show native rust-analyzer diagnostics."
581 },
582 "rust-analyzer.diagnostics.enableExperimental": {
583 "type": "boolean",
584 "default": true,
585 "markdownDescription": "Whether to show experimental rust-analyzer diagnostics that might have more false positives than usual."
586 },
582 "rust-analyzer.diagnostics.warningsAsInfo": { 587 "rust-analyzer.diagnostics.warningsAsInfo": {
583 "type": "array", 588 "type": "array",
584 "uniqueItems": true, 589 "uniqueItems": true,