about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-02-20 17:06:17 +0000
committerbors <bors@rust-lang.org>2024-02-20 17:06:17 +0000
commit4760d856bc8e97747364054a456c96252f134875 (patch)
treeb4925c6b1b8a26e0592c9d805f9de7c5efbbe508
parent9f0495761a26dac47bd32e5b6bd7280ea5701af7 (diff)
parent16b15a203ec888714ffbcc7168a259d18555caae (diff)
downloadrust-4760d856bc8e97747364054a456c96252f134875.tar.gz
rust-4760d856bc8e97747364054a456c96252f134875.zip
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)
-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 863a7ab783e..79bcaa0a9c4 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 4428b8baafb..9f4368b04e7 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 25f84d770bf..b3b6da1f698 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");