Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/ide-diagnostics/src/lib.rs78
-rw-r--r--crates/ide-diagnostics/src/tests.rs146
-rw-r--r--crates/ide/src/lib.rs27
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs2
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs2
-rw-r--r--crates/rust-analyzer/src/cli/rustc_tests.rs2
-rw-r--r--crates/rust-analyzer/src/diagnostics.rs95
-rw-r--r--crates/rust-analyzer/src/integrated_benchmarks.rs4
-rw-r--r--crates/rust-analyzer/src/main_loop.rs45
9 files changed, 255 insertions, 146 deletions
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index 263ab74755..5db0c9a91a 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -96,6 +96,7 @@ use syntax::{
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum DiagnosticCode {
RustcHardError(&'static str),
+ SyntaxError,
RustcLint(&'static str),
Clippy(&'static str),
Ra(&'static str, Severity),
@@ -107,6 +108,9 @@ impl DiagnosticCode {
DiagnosticCode::RustcHardError(e) => {
format!("https://doc.rust-lang.org/stable/error_codes/{e}.html")
}
+ DiagnosticCode::SyntaxError => {
+ String::from("https://doc.rust-lang.org/stable/reference/")
+ }
DiagnosticCode::RustcLint(e) => {
format!("https://doc.rust-lang.org/rustc/?search={e}")
}
@@ -125,6 +129,7 @@ impl DiagnosticCode {
| DiagnosticCode::RustcLint(r)
| DiagnosticCode::Clippy(r)
| DiagnosticCode::Ra(r, _) => r,
+ DiagnosticCode::SyntaxError => "syntax-error",
}
}
}
@@ -154,7 +159,7 @@ impl Diagnostic {
message,
range: range.into(),
severity: match code {
- DiagnosticCode::RustcHardError(_) => Severity::Error,
+ DiagnosticCode::RustcHardError(_) | DiagnosticCode::SyntaxError => Severity::Error,
// FIXME: Rustc lints are not always warning, but the ones that are currently implemented are all warnings.
DiagnosticCode::RustcLint(_) => Severity::Warning,
// FIXME: We can make this configurable, and if the user uses `cargo clippy` on flycheck, we can
@@ -297,31 +302,54 @@ impl DiagnosticsContext<'_> {
}
}
-/// Request diagnostics for the given [`FileId`]. The produced diagnostics may point to other files
+/// Request parser level diagnostics for the given [`FileId`].
+pub fn syntax_diagnostics(
+ db: &RootDatabase,
+ config: &DiagnosticsConfig,
+ file_id: FileId,
+) -> Vec<Diagnostic> {
+ let _p = tracing::info_span!("syntax_diagnostics").entered();
+
+ if config.disabled.contains("syntax-error") {
+ return Vec::new();
+ }
+
+ let sema = Semantics::new(db);
+ let file_id = sema
+ .attach_first_edition(file_id)
+ .unwrap_or_else(|| EditionedFileId::current_edition(file_id));
+
+ // [#3434] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
+ db.parse_errors(file_id)
+ .as_deref()
+ .into_iter()
+ .flatten()
+ .take(128)
+ .map(|err| {
+ Diagnostic::new(
+ DiagnosticCode::SyntaxError,
+ format!("Syntax Error: {err}"),
+ FileRange { file_id: file_id.into(), range: err.range() },
+ )
+ })
+ .collect()
+}
+
+/// Request semantic diagnostics for the given [`FileId`]. The produced diagnostics may point to other files
/// due to macros.
-pub fn diagnostics(
+pub fn semantic_diagnostics(
db: &RootDatabase,
config: &DiagnosticsConfig,
resolve: &AssistResolveStrategy,
file_id: FileId,
) -> Vec<Diagnostic> {
- let _p = tracing::info_span!("diagnostics").entered();
+ let _p = tracing::info_span!("semantic_diagnostics").entered();
let sema = Semantics::new(db);
let file_id = sema
.attach_first_edition(file_id)
.unwrap_or_else(|| EditionedFileId::current_edition(file_id));
let mut res = Vec::new();
- // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
- res.extend(db.parse_errors(file_id).as_deref().into_iter().flatten().take(128).map(|err| {
- Diagnostic::new(
- DiagnosticCode::RustcHardError("syntax-error"),
- format!("Syntax Error: {err}"),
- FileRange { file_id: file_id.into(), range: err.range() },
- )
- }));
- let parse_errors = res.len();
-
let parse = sema.parse(file_id);
// FIXME: This iterates the entire file which is a rather expensive operation.
@@ -341,8 +369,11 @@ pub fn diagnostics(
match module {
// A bunch of parse errors in a file indicate some bigger structural parse changes in the
// file, so we skip semantic diagnostics so we can show these faster.
- Some(m) if parse_errors < 16 => m.diagnostics(db, &mut diags, config.style_lints),
- Some(_) => (),
+ Some(m) => {
+ if !db.parse_errors(file_id).as_deref().is_some_and(|es| es.len() >= 16) {
+ m.diagnostics(db, &mut diags, config.style_lints);
+ }
+ }
None => handlers::unlinked_file::unlinked_file(&ctx, &mut res, file_id.file_id()),
}
@@ -363,7 +394,7 @@ pub fn diagnostics(
res.extend(d.errors.iter().take(16).map(|err| {
{
Diagnostic::new(
- DiagnosticCode::RustcHardError("syntax-error"),
+ DiagnosticCode::SyntaxError,
format!("Syntax Error in Expansion: {err}"),
ctx.resolve_precise_location(&d.node.clone(), d.precise_location),
)
@@ -464,6 +495,19 @@ pub fn diagnostics(
res
}
+/// Request both syntax and semantic diagnostics for the given [`FileId`].
+pub fn full_diagnostics(
+ db: &RootDatabase,
+ config: &DiagnosticsConfig,
+ resolve: &AssistResolveStrategy,
+ file_id: FileId,
+) -> Vec<Diagnostic> {
+ let mut res = syntax_diagnostics(db, config, file_id);
+ let sema = semantic_diagnostics(db, config, resolve, file_id);
+ res.extend(sema);
+ res
+}
+
// `__RA_EVERY_LINT` is a fake lint group to allow every lint in proc macros
static RUSTC_LINT_GROUPS_DICT: Lazy<FxHashMap<&str, Vec<&str>>> =
diff --git a/crates/ide-diagnostics/src/tests.rs b/crates/ide-diagnostics/src/tests.rs
index e56fca1e50..bd0f29c257 100644
--- a/crates/ide-diagnostics/src/tests.rs
+++ b/crates/ide-diagnostics/src/tests.rs
@@ -59,10 +59,14 @@ fn check_nth_fix_with_config(
let after = trim_indent(ra_fixture_after);
let (db, file_position) = RootDatabase::with_position(ra_fixture_before);
- let diagnostic =
- super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_position.file_id.into())
- .pop()
- .expect("no diagnostics");
+ let diagnostic = super::full_diagnostics(
+ &db,
+ &config,
+ &AssistResolveStrategy::All,
+ file_position.file_id.into(),
+ )
+ .pop()
+ .expect("no diagnostics");
let fix = &diagnostic
.fixes
.unwrap_or_else(|| panic!("{:?} diagnostic misses fixes", diagnostic.code))[nth];
@@ -102,37 +106,39 @@ pub(crate) fn check_has_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
let (db, file_position) = RootDatabase::with_position(ra_fixture_before);
let mut conf = DiagnosticsConfig::test_sample();
conf.expr_fill_default = ExprFillDefaultMode::Default;
- let fix =
- super::diagnostics(&db, &conf, &AssistResolveStrategy::All, file_position.file_id.into())
- .into_iter()
- .find(|d| {
- d.fixes
- .as_ref()
- .and_then(|fixes| {
- fixes.iter().find(|fix| {
- if !fix.target.contains_inclusive(file_position.offset) {
- return false;
- }
- let actual = {
- let source_change = fix.source_change.as_ref().unwrap();
- let file_id =
- *source_change.source_file_edits.keys().next().unwrap();
- let mut actual = db.file_text(file_id).to_string();
+ let fix = super::full_diagnostics(
+ &db,
+ &conf,
+ &AssistResolveStrategy::All,
+ file_position.file_id.into(),
+ )
+ .into_iter()
+ .find(|d| {
+ d.fixes
+ .as_ref()
+ .and_then(|fixes| {
+ fixes.iter().find(|fix| {
+ if !fix.target.contains_inclusive(file_position.offset) {
+ return false;
+ }
+ let actual = {
+ let source_change = fix.source_change.as_ref().unwrap();
+ let file_id = *source_change.source_file_edits.keys().next().unwrap();
+ let mut actual = db.file_text(file_id).to_string();
- for (edit, snippet_edit) in source_change.source_file_edits.values()
- {
- edit.apply(&mut actual);
- if let Some(snippet_edit) = snippet_edit {
- snippet_edit.apply(&mut actual);
- }
- }
- actual
- };
- after == actual
- })
- })
- .is_some()
- });
+ for (edit, snippet_edit) in source_change.source_file_edits.values() {
+ edit.apply(&mut actual);
+ if let Some(snippet_edit) = snippet_edit {
+ snippet_edit.apply(&mut actual);
+ }
+ }
+ actual
+ };
+ after == actual
+ })
+ })
+ .is_some()
+ });
assert!(fix.is_some(), "no diagnostic with desired fix");
}
@@ -144,38 +150,40 @@ pub(crate) fn check_has_single_fix(ra_fixture_before: &str, ra_fixture_after: &s
let mut conf = DiagnosticsConfig::test_sample();
conf.expr_fill_default = ExprFillDefaultMode::Default;
let mut n_fixes = 0;
- let fix =
- super::diagnostics(&db, &conf, &AssistResolveStrategy::All, file_position.file_id.into())
- .into_iter()
- .find(|d| {
- d.fixes
- .as_ref()
- .and_then(|fixes| {
- n_fixes += fixes.len();
- fixes.iter().find(|fix| {
- if !fix.target.contains_inclusive(file_position.offset) {
- return false;
- }
- let actual = {
- let source_change = fix.source_change.as_ref().unwrap();
- let file_id =
- *source_change.source_file_edits.keys().next().unwrap();
- let mut actual = db.file_text(file_id).to_string();
+ let fix = super::full_diagnostics(
+ &db,
+ &conf,
+ &AssistResolveStrategy::All,
+ file_position.file_id.into(),
+ )
+ .into_iter()
+ .find(|d| {
+ d.fixes
+ .as_ref()
+ .and_then(|fixes| {
+ n_fixes += fixes.len();
+ fixes.iter().find(|fix| {
+ if !fix.target.contains_inclusive(file_position.offset) {
+ return false;
+ }
+ let actual = {
+ let source_change = fix.source_change.as_ref().unwrap();
+ let file_id = *source_change.source_file_edits.keys().next().unwrap();
+ let mut actual = db.file_text(file_id).to_string();
- for (edit, snippet_edit) in source_change.source_file_edits.values()
- {
- edit.apply(&mut actual);
- if let Some(snippet_edit) = snippet_edit {
- snippet_edit.apply(&mut actual);
- }
- }
- actual
- };
- after == actual
- })
- })
- .is_some()
- });
+ for (edit, snippet_edit) in source_change.source_file_edits.values() {
+ edit.apply(&mut actual);
+ if let Some(snippet_edit) = snippet_edit {
+ snippet_edit.apply(&mut actual);
+ }
+ }
+ actual
+ };
+ after == actual
+ })
+ })
+ .is_some()
+ });
assert!(fix.is_some(), "no diagnostic with desired fix");
assert!(n_fixes == 1, "Too many fixes suggested");
}
@@ -183,7 +191,7 @@ pub(crate) fn check_has_single_fix(ra_fixture_before: &str, ra_fixture_after: &s
/// Checks that there's a diagnostic *without* fix at `$0`.
pub(crate) fn check_no_fix(ra_fixture: &str) {
let (db, file_position) = RootDatabase::with_position(ra_fixture);
- let diagnostic = super::diagnostics(
+ let diagnostic = super::full_diagnostics(
&db,
&DiagnosticsConfig::test_sample(),
&AssistResolveStrategy::All,
@@ -215,7 +223,7 @@ pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixtur
.iter()
.copied()
.flat_map(|file_id| {
- super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id.into())
+ super::full_diagnostics(&db, &config, &AssistResolveStrategy::All, file_id.into())
.into_iter()
.map(|d| {
let mut annotation = String::new();
@@ -277,10 +285,10 @@ fn test_disabled_diagnostics() {
let (db, file_id) = RootDatabase::with_single_file(r#"mod foo;"#);
let file_id = file_id.into();
- let diagnostics = super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id);
+ let diagnostics = super::full_diagnostics(&db, &config, &AssistResolveStrategy::All, file_id);
assert!(diagnostics.is_empty());
- let diagnostics = super::diagnostics(
+ let diagnostics = super::full_diagnostics(
&db,
&DiagnosticsConfig::test_sample(),
&AssistResolveStrategy::All,
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 8cb81a9cc4..9f25fd6e4a 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -672,14 +672,33 @@ impl Analysis {
.unwrap_or_default())
}
- /// Computes the set of diagnostics for the given file.
- pub fn diagnostics(
+ /// Computes the set of parser level diagnostics for the given file.
+ pub fn syntax_diagnostics(
+ &self,
+ config: &DiagnosticsConfig,
+ file_id: FileId,
+ ) -> Cancellable<Vec<Diagnostic>> {
+ self.with_db(|db| ide_diagnostics::syntax_diagnostics(db, config, file_id))
+ }
+
+ /// Computes the set of semantic diagnostics for the given file.
+ pub fn semantic_diagnostics(
+ &self,
+ config: &DiagnosticsConfig,
+ resolve: AssistResolveStrategy,
+ file_id: FileId,
+ ) -> Cancellable<Vec<Diagnostic>> {
+ self.with_db(|db| ide_diagnostics::semantic_diagnostics(db, config, &resolve, file_id))
+ }
+
+ /// Computes the set of both syntax and semantic diagnostics for the given file.
+ pub fn full_diagnostics(
&self,
config: &DiagnosticsConfig,
resolve: AssistResolveStrategy,
file_id: FileId,
) -> Cancellable<Vec<Diagnostic>> {
- self.with_db(|db| ide_diagnostics::diagnostics(db, config, &resolve, file_id))
+ self.with_db(|db| ide_diagnostics::full_diagnostics(db, config, &resolve, file_id))
}
/// Convenience function to return assists + quick fixes for diagnostics
@@ -697,7 +716,7 @@ impl Analysis {
self.with_db(|db| {
let diagnostic_assists = if diagnostics_config.enabled && include_fixes {
- ide_diagnostics::diagnostics(db, diagnostics_config, &resolve, frange.file_id)
+ ide_diagnostics::full_diagnostics(db, diagnostics_config, &resolve, frange.file_id)
.into_iter()
.flat_map(|it| it.fixes.unwrap_or_default())
.filter(|it| it.target.intersect(frange.range).is_some())
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 380105d2c2..fa08b8a5ab 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -977,7 +977,7 @@ impl flags::AnalysisStats {
let mut sw = self.stop_watch();
for &file_id in &file_ids {
- _ = analysis.diagnostics(
+ _ = analysis.full_diagnostics(
&DiagnosticsConfig {
enabled: true,
proc_macros_enabled: true,
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs
index 4ddeb4ab1b..c03a298c2b 100644
--- a/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -63,7 +63,7 @@ impl flags::Diagnostics {
_vfs.file_path(file_id.into())
);
for diagnostic in analysis
- .diagnostics(
+ .full_diagnostics(
&DiagnosticsConfig::test_sample(),
AssistResolveStrategy::None,
file_id.into(),
diff --git a/crates/rust-analyzer/src/cli/rustc_tests.rs b/crates/rust-analyzer/src/cli/rustc_tests.rs
index fddc790e69..3932db00bb 100644
--- a/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -155,7 +155,7 @@ impl Tester {
let root_file = self.root_file;
move || {
let res = std::panic::catch_unwind(move || {
- analysis.diagnostics(
+ analysis.full_diagnostics(
diagnostic_config,
ide::AssistResolveStrategy::None,
root_file,
diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs
index b23e7b7e98..b99a8de2fc 100644
--- a/crates/rust-analyzer/src/diagnostics.rs
+++ b/crates/rust-analyzer/src/diagnostics.rs
@@ -11,7 +11,7 @@ use rustc_hash::FxHashSet;
use stdx::iter_eq_by;
use triomphe::Arc;
-use crate::{global_state::GlobalStateSnapshot, lsp, lsp_ext};
+use crate::{global_state::GlobalStateSnapshot, lsp, lsp_ext, main_loop::DiagnosticsTaskKind};
pub(crate) type CheckFixes = Arc<IntMap<usize, IntMap<FileId, Vec<Fix>>>>;
@@ -28,7 +28,8 @@ pub(crate) type DiagnosticsGeneration = usize;
#[derive(Debug, Default, Clone)]
pub(crate) struct DiagnosticCollection {
// FIXME: should be IntMap<FileId, Vec<ra_id::Diagnostic>>
- pub(crate) native: IntMap<FileId, (DiagnosticsGeneration, Vec<lsp_types::Diagnostic>)>,
+ pub(crate) native_syntax: IntMap<FileId, (DiagnosticsGeneration, Vec<lsp_types::Diagnostic>)>,
+ pub(crate) native_semantic: IntMap<FileId, (DiagnosticsGeneration, Vec<lsp_types::Diagnostic>)>,
// FIXME: should be Vec<flycheck::Diagnostic>
pub(crate) check: IntMap<usize, IntMap<FileId, Vec<lsp_types::Diagnostic>>>,
pub(crate) check_fixes: CheckFixes,
@@ -64,7 +65,8 @@ impl DiagnosticCollection {
}
pub(crate) fn clear_native_for(&mut self, file_id: FileId) {
- self.native.remove(&file_id);
+ self.native_syntax.remove(&file_id);
+ self.native_semantic.remove(&file_id);
self.changes.insert(file_id);
}
@@ -88,43 +90,51 @@ impl DiagnosticCollection {
self.changes.insert(file_id);
}
- pub(crate) fn set_native_diagnostics(
- &mut self,
- generation: DiagnosticsGeneration,
- file_id: FileId,
- mut diagnostics: Vec<lsp_types::Diagnostic>,
- ) {
- diagnostics.sort_by_key(|it| (it.range.start, it.range.end));
- if let Some((old_gen, existing_diagnostics)) = self.native.get_mut(&file_id) {
- if existing_diagnostics.len() == diagnostics.len()
- && iter_eq_by(&diagnostics, &*existing_diagnostics, |new, existing| {
- are_diagnostics_equal(new, existing)
- })
- {
- // don't signal an update if the diagnostics are the same
- return;
+ pub(crate) fn set_native_diagnostics(&mut self, kind: DiagnosticsTaskKind) {
+ let (generation, diagnostics, target) = match kind {
+ DiagnosticsTaskKind::Syntax(generation, diagnostics) => {
+ (generation, diagnostics, &mut self.native_syntax)
+ }
+ DiagnosticsTaskKind::Semantic(generation, diagnostics) => {
+ (generation, diagnostics, &mut self.native_semantic)
}
- if *old_gen < generation || generation == 0 {
- self.native.insert(file_id, (generation, diagnostics));
+ };
+
+ for (file_id, mut diagnostics) in diagnostics {
+ diagnostics.sort_by_key(|it| (it.range.start, it.range.end));
+
+ if let Some((old_gen, existing_diagnostics)) = target.get_mut(&file_id) {
+ if existing_diagnostics.len() == diagnostics.len()
+ && iter_eq_by(&diagnostics, &*existing_diagnostics, |new, existing| {
+ are_diagnostics_equal(new, existing)
+ })
+ {
+ // don't signal an update if the diagnostics are the same
+ return;
+ }
+ if *old_gen < generation || generation == 0 {
+ target.insert(file_id, (generation, diagnostics));
+ } else {
+ existing_diagnostics.extend(diagnostics);
+ // FIXME: Doing the merge step of a merge sort here would be a bit more performant
+ // but eh
+ existing_diagnostics.sort_by_key(|it| (it.range.start, it.range.end))
+ }
} else {
- existing_diagnostics.extend(diagnostics);
- // FIXME: Doing the merge step of a merge sort here would be a bit more performant
- // but eh
- existing_diagnostics.sort_by_key(|it| (it.range.start, it.range.end))
+ target.insert(file_id, (generation, diagnostics));
}
- } else {
- self.native.insert(file_id, (generation, diagnostics));
+ self.changes.insert(file_id);
}
- self.changes.insert(file_id);
}
pub(crate) fn diagnostics_for(
&self,
file_id: FileId,
) -> impl Iterator<Item = &lsp_types::Diagnostic> {
- let native = self.native.get(&file_id).into_iter().flat_map(|(_, d)| d);
+ let native_syntax = self.native_syntax.get(&file_id).into_iter().flat_map(|(_, d)| d);
+ let native_semantic = self.native_semantic.get(&file_id).into_iter().flat_map(|(_, d)| d);
let check = self.check.values().filter_map(move |it| it.get(&file_id)).flatten();
- native.chain(check)
+ native_syntax.chain(native_semantic).chain(check)
}
pub(crate) fn take_changes(&mut self) -> Option<IntSet<FileId>> {
@@ -147,10 +157,16 @@ fn are_diagnostics_equal(left: &lsp_types::Diagnostic, right: &lsp_types::Diagno
&& left.message == right.message
}
+pub(crate) enum NativeDiagnosticsFetchKind {
+ Syntax,
+ Semantic,
+}
+
pub(crate) fn fetch_native_diagnostics(
- snapshot: GlobalStateSnapshot,
+ snapshot: &GlobalStateSnapshot,
subscriptions: std::sync::Arc<[FileId]>,
slice: std::ops::Range<usize>,
+ kind: NativeDiagnosticsFetchKind,
) -> Vec<(FileId, Vec<lsp_types::Diagnostic>)> {
let _p = tracing::info_span!("fetch_native_diagnostics").entered();
let _ctx = stdx::panic_context::enter("fetch_native_diagnostics".to_owned());
@@ -180,14 +196,17 @@ pub(crate) fn fetch_native_diagnostics(
let line_index = snapshot.file_line_index(file_id).ok()?;
let source_root = snapshot.analysis.source_root_id(file_id).ok()?;
- let diagnostics = snapshot
- .analysis
- .diagnostics(
- &snapshot.config.diagnostics(Some(source_root)),
- ide::AssistResolveStrategy::None,
- file_id,
- )
- .ok()?
+ let config = &snapshot.config.diagnostics(Some(source_root));
+ let diagnostics = match kind {
+ NativeDiagnosticsFetchKind::Syntax => {
+ snapshot.analysis.syntax_diagnostics(config, file_id).ok()?
+ }
+ NativeDiagnosticsFetchKind::Semantic => snapshot
+ .analysis
+ .semantic_diagnostics(config, ide::AssistResolveStrategy::None, file_id)
+ .ok()?,
+ };
+ let diagnostics = diagnostics
.into_iter()
.filter_map(|d| {
if d.range.file_id == file_id {
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index f6543a82e5..28f4b809d6 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -325,7 +325,7 @@ fn integrated_diagnostics_benchmark() {
term_search_borrowck: true,
};
host.analysis()
- .diagnostics(&diagnostics_config, ide::AssistResolveStrategy::None, file_id)
+ .full_diagnostics(&diagnostics_config, ide::AssistResolveStrategy::None, file_id)
.unwrap();
let _g = crate::tracing::hprof::init("*");
@@ -343,7 +343,7 @@ fn integrated_diagnostics_benchmark() {
let _p = tracing::info_span!("diagnostics").entered();
let _span = profile::cpu_span();
host.analysis()
- .diagnostics(&diagnostics_config, ide::AssistResolveStrategy::None, file_id)
+ .full_diagnostics(&diagnostics_config, ide::AssistResolveStrategy::None, file_id)
.unwrap();
}
}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 9c820749ec..b0c12c8b78 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -19,7 +19,7 @@ use vfs::{AbsPathBuf, FileId};
use crate::{
config::Config,
- diagnostics::{fetch_native_diagnostics, DiagnosticsGeneration},
+ diagnostics::{fetch_native_diagnostics, DiagnosticsGeneration, NativeDiagnosticsFetchKind},
dispatch::{NotificationDispatcher, RequestDispatcher},
global_state::{file_id_to_url, url_to_file_id, FetchWorkspaceRequest, GlobalState},
hack_recover_crate_name,
@@ -87,11 +87,17 @@ pub(crate) enum QueuedTask {
}
#[derive(Debug)]
+pub(crate) enum DiagnosticsTaskKind {
+ Syntax(DiagnosticsGeneration, Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
+ Semantic(DiagnosticsGeneration, Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
+}
+
+#[derive(Debug)]
pub(crate) enum Task {
Response(lsp_server::Response),
DiscoverLinkedProjects(DiscoverProjectParam),
Retry(lsp_server::Request),
- Diagnostics(DiagnosticsGeneration, Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
+ Diagnostics(DiagnosticsTaskKind),
DiscoverTest(lsp_ext::DiscoverTestResults),
PrimeCaches(PrimeCachesProgress),
FetchWorkspace(ProjectWorkspaceProgress),
@@ -549,14 +555,29 @@ impl GlobalState {
}
// Diagnostics are triggered by the user typing
// so we run them on a latency sensitive thread.
- self.task_pool.handle.spawn(ThreadIntent::LatencySensitive, {
- let snapshot = self.snapshot();
+ let snapshot = self.snapshot();
+ self.task_pool.handle.spawn_with_sender(ThreadIntent::LatencySensitive, {
let subscriptions = subscriptions.clone();
- move || {
- Task::Diagnostics(
- generation,
- fetch_native_diagnostics(snapshot, subscriptions, slice),
- )
+ move |sender| {
+ let diags = fetch_native_diagnostics(
+ &snapshot,
+ subscriptions.clone(),
+ slice.clone(),
+ NativeDiagnosticsFetchKind::Syntax,
+ );
+ sender
+ .send(Task::Diagnostics(DiagnosticsTaskKind::Syntax(generation, diags)))
+ .unwrap();
+
+ let diags = fetch_native_diagnostics(
+ &snapshot,
+ subscriptions,
+ slice,
+ NativeDiagnosticsFetchKind::Semantic,
+ );
+ sender
+ .send(Task::Diagnostics(DiagnosticsTaskKind::Semantic(generation, diags)))
+ .unwrap();
}
});
start = end;
@@ -644,10 +665,8 @@ impl GlobalState {
// Only retry requests that haven't been cancelled. Otherwise we do unnecessary work.
Task::Retry(req) if !self.is_completed(&req) => self.on_request(req),
Task::Retry(_) => (),
- Task::Diagnostics(generation, diagnostics_per_file) => {
- for (file_id, diagnostics) in diagnostics_per_file {
- self.diagnostics.set_native_diagnostics(generation, file_id, diagnostics)
- }
+ Task::Diagnostics(kind) => {
+ self.diagnostics.set_native_diagnostics(kind);
}
Task::PrimeCaches(progress) => match progress {
PrimeCachesProgress::Begin => prime_caches_progress.push(progress),