Skip to content

Commit 4760d85

Browse files
committed
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)
2 parents 9f04957 + 16b15a2 commit 4760d85

File tree

3 files changed

+71
-23
lines changed

3 files changed

+71
-23
lines changed

crates/ide-diagnostics/src/handlers/useless_braces.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use ide_db::{
44
source_change::SourceChange,
55
};
66
use itertools::Itertools;
7-
use syntax::{ast, AstNode, SyntaxNode};
7+
use syntax::{ast, AstNode, SyntaxNode, SyntaxNodePtr};
88
use text_edit::TextEdit;
99

1010
use crate::{fix, Diagnostic, DiagnosticCode};
@@ -43,7 +43,7 @@ pub(crate) fn useless_braces(
4343
"Unnecessary braces in use statement".to_owned(),
4444
FileRange { file_id, range: use_range },
4545
)
46-
.with_main_node(InFile::new(file_id.into(), node.clone()))
46+
.with_main_node(InFile::new(file_id.into(), SyntaxNodePtr::new(node)))
4747
.with_fixes(Some(vec![fix(
4848
"remove_braces",
4949
"Remove unnecessary braces",

crates/ide-diagnostics/src/lib.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ pub struct Diagnostic {
142142
pub experimental: bool,
143143
pub fixes: Option<Vec<Assist>>,
144144
// The node that will be affected by `#[allow]` and similar attributes.
145-
pub main_node: Option<InFile<SyntaxNode>>,
145+
pub main_node: Option<InFile<SyntaxNodePtr>>,
146146
}
147147

148148
impl Diagnostic {
@@ -174,17 +174,16 @@ impl Diagnostic {
174174
message: impl Into<String>,
175175
node: InFile<SyntaxNodePtr>,
176176
) -> Diagnostic {
177-
let file_id = node.file_id;
178177
Diagnostic::new(code, message, ctx.sema.diagnostics_display_range(node))
179-
.with_main_node(node.map(|x| x.to_node(&ctx.sema.parse_or_expand(file_id))))
178+
.with_main_node(node)
180179
}
181180

182181
fn experimental(mut self) -> Diagnostic {
183182
self.experimental = true;
184183
self
185184
}
186185

187-
fn with_main_node(mut self, main_node: InFile<SyntaxNode>) -> Diagnostic {
186+
fn with_main_node(mut self, main_node: InFile<SyntaxNodePtr>) -> Diagnostic {
188187
self.main_node = Some(main_node);
189188
self
190189
}
@@ -394,8 +393,17 @@ pub fn diagnostics(
394393
res.push(d)
395394
}
396395

397-
let mut diagnostics_of_range =
398-
res.iter_mut().filter_map(|x| Some((x.main_node.clone()?, x))).collect::<FxHashMap<_, _>>();
396+
let mut diagnostics_of_range = res
397+
.iter_mut()
398+
.filter_map(|it| {
399+
Some((
400+
it.main_node
401+
.map(|ptr| ptr.map(|node| node.to_node(&ctx.sema.parse_or_expand(ptr.file_id))))
402+
.clone()?,
403+
it,
404+
))
405+
})
406+
.collect::<FxHashMap<_, _>>();
399407

400408
let mut rustc_stack: FxHashMap<String, Vec<Severity>> = FxHashMap::default();
401409
let mut clippy_stack: FxHashMap<String, Vec<Severity>> = FxHashMap::default();

crates/rust-analyzer/src/cli/rustc_tests.rs

+55-15
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
//! Run all tests in a project, similar to `cargo test`, but using the mir interpreter.
22
3+
use std::convert::identity;
4+
use std::thread::Builder;
5+
use std::time::{Duration, Instant};
36
use std::{cell::RefCell, fs::read_to_string, panic::AssertUnwindSafe, path::PathBuf};
47

58
use hir::{Change, Crate};
69
use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig};
10+
use itertools::Either;
711
use profile::StopWatch;
812
use project_model::target_data_layout::RustcDataLayoutConfig;
913
use project_model::{target_data_layout, CargoConfig, ProjectWorkspace, RustLibSource, Sysroot};
@@ -100,6 +104,7 @@ impl Tester {
100104
}
101105

102106
fn test(&mut self, p: PathBuf) {
107+
println!("{}", p.display());
103108
if p.parent().unwrap().file_name().unwrap() == "auxiliary" {
104109
// These are not tests
105110
return;
@@ -132,15 +137,44 @@ impl Tester {
132137
self.host.apply_change(change);
133138
let diagnostic_config = DiagnosticsConfig::test_sample();
134139

140+
let res = std::thread::scope(|s| {
141+
let worker = Builder::new()
142+
.stack_size(40 * 1024 * 1024)
143+
.spawn_scoped(s, {
144+
let diagnostic_config = &diagnostic_config;
145+
let main = std::thread::current();
146+
let analysis = self.host.analysis();
147+
let root_file = self.root_file;
148+
move || {
149+
let res = std::panic::catch_unwind(move || {
150+
analysis.diagnostics(
151+
diagnostic_config,
152+
ide::AssistResolveStrategy::None,
153+
root_file,
154+
)
155+
});
156+
main.unpark();
157+
res
158+
}
159+
})
160+
.unwrap();
161+
162+
let timeout = Duration::from_secs(5);
163+
let now = Instant::now();
164+
while now.elapsed() <= timeout && !worker.is_finished() {
165+
std::thread::park_timeout(timeout - now.elapsed());
166+
}
167+
168+
if !worker.is_finished() {
169+
// attempt to cancel the worker, won't work for chalk hangs unfortunately
170+
self.host.request_cancellation();
171+
}
172+
worker.join().and_then(identity)
173+
});
135174
let mut actual = FxHashMap::default();
136-
let panicked = match std::panic::catch_unwind(|| {
137-
self.host
138-
.analysis()
139-
.diagnostics(&diagnostic_config, ide::AssistResolveStrategy::None, self.root_file)
140-
.unwrap()
141-
}) {
142-
Err(e) => Some(e),
143-
Ok(diags) => {
175+
let panicked = match res {
176+
Err(e) => Some(Either::Left(e)),
177+
Ok(Ok(diags)) => {
144178
for diag in diags {
145179
if !matches!(diag.code, DiagnosticCode::RustcHardError(_)) {
146180
continue;
@@ -152,21 +186,27 @@ impl Tester {
152186
}
153187
None
154188
}
189+
Ok(Err(e)) => Some(Either::Right(e)),
155190
};
156191
// Ignore tests with diagnostics that we don't emit.
157192
ignore_test |= expected.keys().any(|k| !SUPPORTED_DIAGNOSTICS.contains(k));
158193
if ignore_test {
159194
println!("{p:?} IGNORE");
160195
self.ignore_count += 1;
161196
} else if let Some(panic) = panicked {
162-
if let Some(msg) = panic
163-
.downcast_ref::<String>()
164-
.map(String::as_str)
165-
.or_else(|| panic.downcast_ref::<&str>().copied())
166-
{
167-
println!("{msg:?} ")
197+
match panic {
198+
Either::Left(panic) => {
199+
if let Some(msg) = panic
200+
.downcast_ref::<String>()
201+
.map(String::as_str)
202+
.or_else(|| panic.downcast_ref::<&str>().copied())
203+
{
204+
println!("{msg:?} ")
205+
}
206+
println!("{p:?} PANIC");
207+
}
208+
Either::Right(_) => println!("{p:?} CANCELLED"),
168209
}
169-
println!("PANIC");
170210
self.fail_count += 1;
171211
} else if actual == expected {
172212
println!("{p:?} PASS");

0 commit comments

Comments
 (0)