From cf214ac4e76413bdfd2676edf834505306edc9c6 Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Mon, 27 May 2019 14:20:11 +0300
Subject: [PATCH 1/3] enable profiling in tests

---
 .../ra_lsp_server/tests/heavy_tests/main.rs   | 70 ++++++++++++++++++-
 .../tests/heavy_tests/support.rs              | 14 ++++
 2 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs
index 6f37a980db6..3c2dc08ed05 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/main.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs
@@ -6,10 +6,11 @@ use std::{
 };
 
 use lsp_types::{
-    CodeActionContext, DocumentFormattingParams, FormattingOptions, Position, Range,
+    CodeActionContext, DocumentFormattingParams, FormattingOptions, Position, Range, DidOpenTextDocumentParams, TextDocumentItem, TextDocumentPositionParams
 };
 use ra_lsp_server::req::{
     CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams, CompletionParams, Completion,
+    DidOpenTextDocument, OnEnter,
 };
 use serde_json::json;
 use tempfile::TempDir;
@@ -17,6 +18,7 @@ use tempfile::TempDir;
 use crate::support::{project, Project};
 
 const LOG: &'static str = "";
+const PROFILE: &'static str = "*@3>100";
 
 #[test]
 fn completes_items_from_standard_library() {
@@ -341,3 +343,69 @@ fn main() {{}}
         json!([]),
     );
 }
+
+#[test]
+fn diagnostics_dont_block_typing() {
+    let librs: String = (0..10).map(|i| format!("mod m{};", i)).collect();
+    let libs: String = (0..10).map(|i| format!("//- src/m{}.rs\nfn foo() {{}}\n\n", i)).collect();
+    let server = project(&format!(
+        r#"
+//- Cargo.toml
+[package]
+name = "foo"
+version = "0.0.0"
+
+//- src/lib.rs
+{}
+
+{}
+
+fn main() {{}}
+"#,
+        librs, libs
+    ));
+    server.wait_until_workspace_is_loaded();
+    eprintln!("workspace loaded");
+    for i in 0..10 {
+        server.notification::<DidOpenTextDocument>(DidOpenTextDocumentParams {
+            text_document: TextDocumentItem {
+                uri: server.doc_id(&format!("src/m{}.rs", i)).uri,
+                language_id: "rust".to_string(),
+                version: 0,
+                text: "/// Docs\nfn foo() {}".to_string(),
+            },
+        });
+    }
+    eprintln!("docs opened");
+    let start = std::time::Instant::now();
+    server.request::<OnEnter>(
+        TextDocumentPositionParams {
+            text_document: server.doc_id("src/m0.rs"),
+            position: Position { line: 0, character: 5 },
+        },
+        json!({
+          "cursorPosition": {
+            "position": { "character": 4, "line": 1 },
+            "textDocument": { "uri": "file:///[..]src/m0.rs" }
+          },
+          "label": "on enter",
+          "workspaceEdit": {
+            "documentChanges": [
+              {
+                "edits": [
+                  {
+                    "newText": "\n/// ",
+                    "range": {
+                      "end": { "character": 5, "line": 0 },
+                      "start": { "character": 5, "line": 0 }
+                    }
+                  }
+                ],
+                "textDocument": { "uri": "file:///[..]src/m0.rs", "version": null }
+              }
+            ]
+          }
+        }),
+    );
+    eprintln!("handled: {:?}", start.elapsed());
+}
diff --git a/crates/ra_lsp_server/tests/heavy_tests/support.rs b/crates/ra_lsp_server/tests/heavy_tests/support.rs
index d68182174b3..729067395fc 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/support.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/support.rs
@@ -52,6 +52,11 @@ impl<'a> Project<'a> {
         static INIT: Once = Once::new();
         INIT.call_once(|| {
             let _ = Logger::with_env_or_str(crate::LOG).start().unwrap();
+            ra_prof::set_filter(if crate::PROFILE.is_empty() {
+                ra_prof::Filter::disabled()
+            } else {
+                ra_prof::Filter::from_spec(&crate::PROFILE)
+            });
         });
 
         let mut paths = vec![];
@@ -121,6 +126,15 @@ impl Server {
         TextDocumentIdentifier { uri: Url::from_file_path(path).unwrap() }
     }
 
+    pub fn notification<N>(&self, params: N::Params)
+    where
+        N: Notification,
+        N::Params: Serialize,
+    {
+        let r = RawNotification::new::<N>(&params);
+        self.send_notification(r)
+    }
+
     pub fn request<R>(&self, params: R::Params, expected_resp: Value)
     where
         R: Request,

From 0d2f97e83eaf8cd5d313affca1a0f52a2db6b54b Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Mon, 27 May 2019 14:27:05 +0300
Subject: [PATCH 2/3] specifically profile cancellation

---
 crates/ra_ide_api/src/change.rs | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs
index 2434f428f6b..0e64abdbd49 100644
--- a/crates/ra_ide_api/src/change.rs
+++ b/crates/ra_ide_api/src/change.rs
@@ -156,6 +156,10 @@ impl RootDatabase {
     pub(crate) fn apply_change(&mut self, change: AnalysisChange) {
         let _p = profile("RootDatabase::apply_change");
         log::info!("apply_change {:?}", change);
+        {
+            let _p = profile("RootDatabase::apply_change/cancellation");
+            self.salsa_runtime().next_revision();
+        }
         if !change.new_roots.is_empty() {
             let mut local_roots = Vec::clone(&self.local_roots());
             for (root_id, is_local) in change.new_roots {

From a2845bb1f59e5f3d9f41012ace70037b783468ce Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Mon, 27 May 2019 14:41:14 +0300
Subject: [PATCH 3/3] check cancellation when expanding macros

---
 crates/ra_hir/src/ids.rs                       | 1 +
 crates/ra_lsp_server/tests/heavy_tests/main.rs | 5 ++---
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 2eb7f0da013..5c3799e95b7 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -61,6 +61,7 @@ impl HirFileId {
         db: &impl DefDatabase,
         file_id: HirFileId,
     ) -> Option<TreeArc<SyntaxNode>> {
+        db.check_canceled();
         let _p = profile("parse_or_expand_query");
         match file_id.0 {
             HirFileIdRepr::File(file_id) => Some(db.parse(file_id).syntax().to_owned()),
diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs
index 3c2dc08ed05..f61048aaf09 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/main.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs
@@ -365,7 +365,6 @@ fn main() {{}}
         librs, libs
     ));
     server.wait_until_workspace_is_loaded();
-    eprintln!("workspace loaded");
     for i in 0..10 {
         server.notification::<DidOpenTextDocument>(DidOpenTextDocumentParams {
             text_document: TextDocumentItem {
@@ -376,7 +375,6 @@ fn main() {{}}
             },
         });
     }
-    eprintln!("docs opened");
     let start = std::time::Instant::now();
     server.request::<OnEnter>(
         TextDocumentPositionParams {
@@ -407,5 +405,6 @@ fn main() {{}}
           }
         }),
     );
-    eprintln!("handled: {:?}", start.elapsed());
+    let elapsed = start.elapsed();
+    assert!(elapsed.as_millis() < 2000, "typing enter took {:?}", elapsed);
 }