Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #16617 - Veykril:rustc-tests-timeout, r=Veykril
internal: Attempt to add a timeout to rustc-tests Looks like some new test is stuck, this might help with figuring that out, though it unfortunately won't if its a chalk hang (which is the most likely)
bors 2024-02-21
parent 9f04957 · parent 16b15a2 · commit 4760d85
-rw-r--r--crates/ide-diagnostics/src/handlers/useless_braces.rs4
-rw-r--r--crates/ide-diagnostics/src/lib.rs20
-rw-r--r--crates/rust-analyzer/src/cli/rustc_tests.rs70
3 files changed, 71 insertions, 23 deletions
diff --git a/crates/ide-diagnostics/src/handlers/useless_braces.rs b/crates/ide-diagnostics/src/handlers/useless_braces.rs
index 863a7ab783..79bcaa0a9c 100644
--- a/crates/ide-diagnostics/src/handlers/useless_braces.rs
+++ b/crates/ide-diagnostics/src/handlers/useless_braces.rs
@@ -4,7 +4,7 @@ use ide_db::{
source_change::SourceChange,
};
use itertools::Itertools;
-use syntax::{ast, AstNode, SyntaxNode};
+use syntax::{ast, AstNode, SyntaxNode, SyntaxNodePtr};
use text_edit::TextEdit;
use crate::{fix, Diagnostic, DiagnosticCode};
@@ -43,7 +43,7 @@ pub(crate) fn useless_braces(
"Unnecessary braces in use statement".to_owned(),
FileRange { file_id, range: use_range },
)
- .with_main_node(InFile::new(file_id.into(), node.clone()))
+ .with_main_node(InFile::new(file_id.into(), SyntaxNodePtr::new(node)))
.with_fixes(Some(vec![fix(
"remove_braces",
"Remove unnecessary braces",
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index 4428b8baaf..9f4368b04e 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -142,7 +142,7 @@ pub struct Diagnostic {
pub experimental: bool,
pub fixes: Option<Vec<Assist>>,
// The node that will be affected by `#[allow]` and similar attributes.
- pub main_node: Option<InFile<SyntaxNode>>,
+ pub main_node: Option<InFile<SyntaxNodePtr>>,
}
impl Diagnostic {
@@ -174,9 +174,8 @@ impl Diagnostic {
message: impl Into<String>,
node: InFile<SyntaxNodePtr>,
) -> Diagnostic {
- let file_id = node.file_id;
Diagnostic::new(code, message, ctx.sema.diagnostics_display_range(node))
- .with_main_node(node.map(|x| x.to_node(&ctx.sema.parse_or_expand(file_id))))
+ .with_main_node(node)
}
fn experimental(mut self) -> Diagnostic {
@@ -184,7 +183,7 @@ impl Diagnostic {
self
}
- fn with_main_node(mut self, main_node: InFile<SyntaxNode>) -> Diagnostic {
+ fn with_main_node(mut self, main_node: InFile<SyntaxNodePtr>) -> Diagnostic {
self.main_node = Some(main_node);
self
}
@@ -394,8 +393,17 @@ pub fn diagnostics(
res.push(d)
}
- let mut diagnostics_of_range =
- res.iter_mut().filter_map(|x| Some((x.main_node.clone()?, x))).collect::<FxHashMap<_, _>>();
+ let mut diagnostics_of_range = res
+ .iter_mut()
+ .filter_map(|it| {
+ Some((
+ it.main_node
+ .map(|ptr| ptr.map(|node| node.to_node(&ctx.sema.parse_or_expand(ptr.file_id))))
+ .clone()?,
+ it,
+ ))
+ })
+ .collect::<FxHashMap<_, _>>();
let mut rustc_stack: FxHashMap<String, Vec<Severity>> = FxHashMap::default();
let mut clippy_stack: FxHashMap<String, Vec<Severity>> = FxHashMap::default();
diff --git a/crates/rust-analyzer/src/cli/rustc_tests.rs b/crates/rust-analyzer/src/cli/rustc_tests.rs
index 25f84d770b..b3b6da1f69 100644
--- a/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -1,9 +1,13 @@
//! Run all tests in a project, similar to `cargo test`, but using the mir interpreter.
+use std::convert::identity;
+use std::thread::Builder;
+use std::time::{Duration, Instant};
use std::{cell::RefCell, fs::read_to_string, panic::AssertUnwindSafe, path::PathBuf};
use hir::{Change, Crate};
use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig};
+use itertools::Either;
use profile::StopWatch;
use project_model::target_data_layout::RustcDataLayoutConfig;
use project_model::{target_data_layout, CargoConfig, ProjectWorkspace, RustLibSource, Sysroot};
@@ -100,6 +104,7 @@ impl Tester {
}
fn test(&mut self, p: PathBuf) {
+ println!("{}", p.display());
if p.parent().unwrap().file_name().unwrap() == "auxiliary" {
// These are not tests
return;
@@ -132,15 +137,44 @@ impl Tester {
self.host.apply_change(change);
let diagnostic_config = DiagnosticsConfig::test_sample();
+ let res = std::thread::scope(|s| {
+ let worker = Builder::new()
+ .stack_size(40 * 1024 * 1024)
+ .spawn_scoped(s, {
+ let diagnostic_config = &diagnostic_config;
+ let main = std::thread::current();
+ let analysis = self.host.analysis();
+ let root_file = self.root_file;
+ move || {
+ let res = std::panic::catch_unwind(move || {
+ analysis.diagnostics(
+ diagnostic_config,
+ ide::AssistResolveStrategy::None,
+ root_file,
+ )
+ });
+ main.unpark();
+ res
+ }
+ })
+ .unwrap();
+
+ let timeout = Duration::from_secs(5);
+ let now = Instant::now();
+ while now.elapsed() <= timeout && !worker.is_finished() {
+ std::thread::park_timeout(timeout - now.elapsed());
+ }
+
+ if !worker.is_finished() {
+ // attempt to cancel the worker, won't work for chalk hangs unfortunately
+ self.host.request_cancellation();
+ }
+ worker.join().and_then(identity)
+ });
let mut actual = FxHashMap::default();
- let panicked = match std::panic::catch_unwind(|| {
- self.host
- .analysis()
- .diagnostics(&diagnostic_config, ide::AssistResolveStrategy::None, self.root_file)
- .unwrap()
- }) {
- Err(e) => Some(e),
- Ok(diags) => {
+ let panicked = match res {
+ Err(e) => Some(Either::Left(e)),
+ Ok(Ok(diags)) => {
for diag in diags {
if !matches!(diag.code, DiagnosticCode::RustcHardError(_)) {
continue;
@@ -152,6 +186,7 @@ impl Tester {
}
None
}
+ Ok(Err(e)) => Some(Either::Right(e)),
};
// Ignore tests with diagnostics that we don't emit.
ignore_test |= expected.keys().any(|k| !SUPPORTED_DIAGNOSTICS.contains(k));
@@ -159,14 +194,19 @@ impl Tester {
println!("{p:?} IGNORE");
self.ignore_count += 1;
} else if let Some(panic) = panicked {
- if let Some(msg) = panic
- .downcast_ref::<String>()
- .map(String::as_str)
- .or_else(|| panic.downcast_ref::<&str>().copied())
- {
- println!("{msg:?} ")
+ match panic {
+ Either::Left(panic) => {
+ if let Some(msg) = panic
+ .downcast_ref::<String>()
+ .map(String::as_str)
+ .or_else(|| panic.downcast_ref::<&str>().copied())
+ {
+ println!("{msg:?} ")
+ }
+ println!("{p:?} PANIC");
+ }
+ Either::Right(_) => println!("{p:?} CANCELLED"),
}
- println!("PANIC");
self.fail_count += 1;
} else if actual == expected {
println!("{p:?} PASS");