Skip to content

Commit de79413

Browse files
committed
internal: Attempt to add a timeout to rustc-tests
1 parent 9dee352 commit de79413

File tree

3 files changed

+63
-23
lines changed

3 files changed

+63
-23
lines changed

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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 14 additions & 6 deletions
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

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
//! Run all tests in a project, similar to `cargo test`, but using the mir interpreter.
22
3+
use std::time::{Duration, Instant};
34
use std::{cell::RefCell, fs::read_to_string, panic::AssertUnwindSafe, path::PathBuf};
45

56
use hir::{Change, Crate};
67
use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig};
8+
use itertools::Either;
79
use profile::StopWatch;
810
use project_model::target_data_layout::RustcDataLayoutConfig;
911
use project_model::{target_data_layout, CargoConfig, ProjectWorkspace, RustLibSource, Sysroot};
@@ -132,15 +134,39 @@ impl Tester {
132134
self.host.apply_change(change);
133135
let diagnostic_config = DiagnosticsConfig::test_sample();
134136

137+
let res = std::thread::scope(|s| {
138+
let worker = s.spawn({
139+
let diagnostic_config = &diagnostic_config;
140+
let main = std::thread::current();
141+
let analysis = self.host.analysis();
142+
let root_file = self.root_file;
143+
move || {
144+
let res = analysis.diagnostics(
145+
diagnostic_config,
146+
ide::AssistResolveStrategy::None,
147+
root_file,
148+
);
149+
main.unpark();
150+
res
151+
}
152+
});
153+
154+
let timeout = Duration::from_secs(30);
155+
let now = Instant::now();
156+
while now.elapsed() <= timeout {
157+
std::thread::park_timeout(timeout - now.elapsed());
158+
}
159+
160+
if !worker.is_finished() {
161+
// attempt to cancel the worker, won't work for chalk hangs unfortunately
162+
self.host.request_cancellation();
163+
}
164+
worker.join()
165+
});
135166
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) => {
167+
let panicked = match res {
168+
Err(e) => Some(Either::Left(e)),
169+
Ok(Ok(diags)) => {
144170
for diag in diags {
145171
if !matches!(diag.code, DiagnosticCode::RustcHardError(_)) {
146172
continue;
@@ -152,21 +178,27 @@ impl Tester {
152178
}
153179
None
154180
}
181+
Ok(Err(e)) => Some(Either::Right(e)),
155182
};
156183
// Ignore tests with diagnostics that we don't emit.
157184
ignore_test |= expected.keys().any(|k| !SUPPORTED_DIAGNOSTICS.contains(k));
158185
if ignore_test {
159186
println!("{p:?} IGNORE");
160187
self.ignore_count += 1;
161188
} 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:?} ")
189+
match panic {
190+
Either::Left(panic) => {
191+
if let Some(msg) = panic
192+
.downcast_ref::<String>()
193+
.map(String::as_str)
194+
.or_else(|| panic.downcast_ref::<&str>().copied())
195+
{
196+
println!("{msg:?} ")
197+
}
198+
println!("{p:?} PANIC");
199+
}
200+
Either::Right(_) => println!("{p:?} CANCELLED"),
168201
}
169-
println!("PANIC");
170202
self.fail_count += 1;
171203
} else if actual == expected {
172204
println!("{p:?} PASS");

0 commit comments

Comments
 (0)