Skip to content

Commit 9fbff41

Browse files
committed
Run flycheck for workspace if target is binary
Since querying for a crate's target is a salsa db and therefore blocking, flycheck task is now deferred out of main thread by using `GlobalState`s `deferred_task_queue`
1 parent e71a14c commit 9fbff41

File tree

3 files changed

+10
-219
lines changed

3 files changed

+10
-219
lines changed

crates/rust-analyzer/src/handlers/notification.rs

Lines changed: 5 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! This module is responsible for implementing handlers for Language Server
22
//! Protocol. This module specifically handles notifications.
33
4-
use std::ops::{Deref, Not as _};
4+
use std::ops::Not as _;
55

66
use itertools::Itertools;
77
use lsp_types::{
@@ -11,13 +11,14 @@ use lsp_types::{
1111
};
1212
use paths::Utf8PathBuf;
1313
use triomphe::Arc;
14-
use vfs::{AbsPathBuf, ChangeKind, VfsPath};
14+
use vfs::{AbsPathBuf, ChangeKind};
1515

1616
use crate::{
1717
config::{Config, ConfigChange},
1818
global_state::{FetchWorkspaceRequest, GlobalState},
1919
lsp::{from_proto, utils::apply_document_changes},
2020
lsp_ext::{self, RunFlycheckParams},
21+
main_loop::QueuedTask,
2122
mem_docs::DocumentData,
2223
reload,
2324
};
@@ -282,100 +283,6 @@ pub(crate) fn handle_did_change_watched_files(
282283
Ok(())
283284
}
284285

285-
fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
286-
let _p = tracing::info_span!("run_flycheck").entered();
287-
288-
let file_id = state.vfs.read().0.file_id(&vfs_path);
289-
if let Some(file_id) = file_id {
290-
let world = state.snapshot();
291-
let mut updated = false;
292-
let task = move || -> std::result::Result<(), ide::Cancelled> {
293-
// Trigger flychecks for all workspaces that depend on the saved file
294-
// Crates containing or depending on the saved file
295-
let crate_ids: Vec<_> = world
296-
.analysis
297-
.crates_for(file_id)?
298-
.into_iter()
299-
.flat_map(|id| world.analysis.transitive_rev_deps(id))
300-
.flatten()
301-
.unique()
302-
.collect();
303-
304-
let crate_root_paths: Vec<_> = crate_ids
305-
.iter()
306-
.filter_map(|&crate_id| {
307-
world
308-
.analysis
309-
.crate_root(crate_id)
310-
.map(|file_id| {
311-
world.file_id_to_file_path(file_id).as_path().map(ToOwned::to_owned)
312-
})
313-
.transpose()
314-
})
315-
.collect::<ide::Cancellable<_>>()?;
316-
let crate_root_paths: Vec<_> = crate_root_paths.iter().map(Deref::deref).collect();
317-
318-
// Find all workspaces that have at least one target containing the saved file
319-
let workspace_ids = world.workspaces.iter().enumerate().filter_map(|(idx, ws)| {
320-
let package = match &ws.kind {
321-
project_model::ProjectWorkspaceKind::Cargo { cargo, .. }
322-
| project_model::ProjectWorkspaceKind::DetachedFile {
323-
cargo: Some((cargo, _)),
324-
..
325-
} => cargo.packages().find_map(|pkg| {
326-
let has_target_with_root = cargo[pkg]
327-
.targets
328-
.iter()
329-
.any(|&it| crate_root_paths.contains(&cargo[it].root.as_path()));
330-
has_target_with_root.then(|| cargo[pkg].name.clone())
331-
}),
332-
project_model::ProjectWorkspaceKind::Json(project) => {
333-
if !project.crates().any(|(_, krate)| {
334-
crate_root_paths.contains(&krate.root_module.as_path())
335-
}) {
336-
return None;
337-
}
338-
None
339-
}
340-
project_model::ProjectWorkspaceKind::DetachedFile { .. } => return None,
341-
};
342-
Some((idx, package))
343-
});
344-
345-
let saved_file = vfs_path.as_path().map(|p| p.to_owned());
346-
347-
// Find and trigger corresponding flychecks
348-
for flycheck in world.flycheck.iter() {
349-
for (id, package) in workspace_ids.clone() {
350-
if id == flycheck.id() {
351-
updated = true;
352-
match package.filter(|_| !world.config.flycheck_workspace()) {
353-
Some(package) => flycheck.restart_for_package(package),
354-
None => flycheck.restart_workspace(saved_file.clone()),
355-
}
356-
continue;
357-
}
358-
}
359-
}
360-
// No specific flycheck was triggered, so let's trigger all of them.
361-
if !updated {
362-
for flycheck in world.flycheck.iter() {
363-
flycheck.restart_workspace(saved_file.clone());
364-
}
365-
}
366-
Ok(())
367-
};
368-
state.task_pool.handle.spawn_with_sender(stdx::thread::ThreadIntent::Worker, move |_| {
369-
if let Err(e) = std::panic::catch_unwind(task) {
370-
tracing::error!("flycheck task panicked: {e:?}")
371-
}
372-
});
373-
true
374-
} else {
375-
false
376-
}
377-
}
378-
379286
pub(crate) fn handle_cancel_flycheck(state: &mut GlobalState, _: ()) -> anyhow::Result<()> {
380287
let _p = tracing::info_span!("handle_cancel_flycheck").entered();
381288
state.flycheck.iter().for_each(|flycheck| flycheck.cancel());
@@ -395,9 +302,8 @@ pub(crate) fn handle_run_flycheck(
395302
let _p = tracing::info_span!("handle_run_flycheck").entered();
396303
if let Some(text_document) = params.text_document {
397304
if let Ok(vfs_path) = from_proto::vfs_path(&text_document.uri) {
398-
if run_flycheck(state, vfs_path) {
399-
return Ok(());
400-
}
305+
let _ = state.deferred_task_queue.sender.send(QueuedTask::Flycheck(vfs_path));
306+
return Ok(());
401307
}
402308
}
403309
// No specific flycheck was triggered, so let's trigger all of them.

crates/rust-analyzer/src/main_loop.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -856,10 +856,9 @@ impl GlobalState {
856856
let world = self.snapshot();
857857
let mut updated = false;
858858
let task = move || -> std::result::Result<(), ide::Cancelled> {
859-
// Is the target binary? If so we let flycheck trigger only for the workspace that contains it.
859+
// Is the target binary? If so we let flycheck run only for the workspace that contains the crate.
860860
let target_is_bin = TargetSpec::for_file(&world, file_id)?
861861
.is_some_and(|x| x.target_kind() == project_model::TargetKind::Bin);
862-
863862
let crate_ids = if target_is_bin {
864863
// Trigger flychecks for the only workspace which the binary crate belongs to
865864
world

crates/rust-analyzer/tests/slow-tests/main.rs

Lines changed: 4 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,15 @@ mod testdir;
1717
use std::{collections::HashMap, path::PathBuf, time::Instant};
1818

1919
use lsp_types::{
20-
notification::{DidOpenTextDocument, DidSaveTextDocument},
20+
notification::DidOpenTextDocument,
2121
request::{
2222
CodeActionRequest, Completion, Formatting, GotoTypeDefinition, HoverRequest,
2323
InlayHintRequest, InlayHintResolveRequest, WillRenameFiles, WorkspaceSymbolRequest,
2424
},
2525
CodeActionContext, CodeActionParams, CompletionParams, DidOpenTextDocumentParams,
26-
DidSaveTextDocumentParams, DocumentFormattingParams, FileRename, FormattingOptions,
27-
GotoDefinitionParams, HoverParams, InlayHint, InlayHintLabel, InlayHintParams,
28-
PartialResultParams, Position, Range, RenameFilesParams, TextDocumentIdentifier,
29-
TextDocumentItem, TextDocumentPositionParams, Url, WorkDoneProgressParams,
26+
DocumentFormattingParams, FileRename, FormattingOptions, GotoDefinitionParams, HoverParams,
27+
InlayHint, InlayHintLabel, InlayHintParams, PartialResultParams, Position, Range,
28+
RenameFilesParams, TextDocumentItem, TextDocumentPositionParams, WorkDoneProgressParams,
3029
};
3130
use rust_analyzer::lsp::ext::{OnEnter, Runnables, RunnablesParams};
3231
use serde_json::json;
@@ -1395,116 +1394,3 @@ version = "0.0.0"
13951394

13961395
server.request::<WorkspaceSymbolRequest>(Default::default(), json!([]));
13971396
}
1398-
1399-
#[test]
1400-
/// When flycheck is run on a binary, only the binary crate
1401-
/// should be taken in consideration.
1402-
fn flycheck_only_for_single_crate() {
1403-
if skip_slow_tests() {
1404-
return;
1405-
}
1406-
1407-
let tmp_dir = TestDir::new();
1408-
let path_str = tmp_dir.path().to_owned();
1409-
1410-
let server = Project::with_fixture(
1411-
r#"
1412-
//- /foo/Cargo.toml
1413-
[workspace]
1414-
members = ["crates/*"]
1415-
resolver = "2"
1416-
1417-
1418-
[workspace.dependencies]
1419-
luib = { version = "0.1.0" , path = "./crates/luib" }
1420-
luib2 = { version = "0.1.0" , path = "./crates/luib2" }
1421-
1422-
1423-
1424-
//- /foo/crates/luib/Cargo.toml
1425-
[package]
1426-
name = "luib"
1427-
version = "0.1.0"
1428-
edition = "2021"
1429-
1430-
[dependencies]
1431-
luib2.workspace = true
1432-
1433-
//- /foo/crates/luib/src/lib.rs
1434-
pub fn add(left: u64, right: u64) -> u64 {
1435-
left + right
1436-
}
1437-
1438-
#[cfg(test)]
1439-
mod tests {
1440-
use super::*;
1441-
1442-
#[test]
1443-
fn it_works() {
1444-
let result = add(2, 2);
1445-
assert_eq!(result, 4);
1446-
}
1447-
}
1448-
1449-
//- /foo/crates/buin/Cargo.toml
1450-
[package]
1451-
name = "buin"
1452-
version = "0.1.0"
1453-
edition = "2021"
1454-
1455-
[dependencies]
1456-
luib.workspace = true
1457-
luib2.workspace = true
1458-
1459-
//- /foo/crates/buin/src/main.rs
1460-
use luib;
1461-
fn main() {
1462-
luib::add(3, 4);
1463-
println!("Hello, world!");
1464-
}
1465-
1466-
//- /foo/crates/luib2/Cargo.toml
1467-
[package]
1468-
name = "luib2"
1469-
version = "0.1.0"
1470-
edition = "2021"
1471-
1472-
[dependencies]
1473-
1474-
//- /foo/crates/luib2/src/lib.rs
1475-
pub fn add(left: u64, right: u64) -> u64 {
1476-
left + right
1477-
}
1478-
1479-
#[cfg(test)]
1480-
mod tests {
1481-
use super::*;
1482-
1483-
#[test]
1484-
fn it_works() {
1485-
let result = add(2, 2);
1486-
assert_eq!(result, 4);
1487-
}
1488-
}
1489-
"#,
1490-
)
1491-
.root("foo")
1492-
.server()
1493-
.wait_until_workspace_is_loaded();
1494-
1495-
let mut path_to_file = path_str;
1496-
path_to_file.push("foo");
1497-
path_to_file.push("crates");
1498-
path_to_file.push("buin");
1499-
path_to_file.push("src");
1500-
path_to_file.push("main.rs");
1501-
1502-
dbg!(&path_to_file);
1503-
1504-
server.notification::<DidSaveTextDocument>(DidSaveTextDocumentParams {
1505-
text_document: TextDocumentIdentifier {
1506-
uri: Url::parse(&format!("file://{}", path_to_file)).unwrap(),
1507-
},
1508-
text: None,
1509-
});
1510-
}

0 commit comments

Comments
 (0)