diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-07-22 14:04:30 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-07-22 14:04:30 +0100 |
commit | 1c7d5f513cc583413a717fa14c2a394c182d69d6 (patch) | |
tree | 82baf4c0467509dd52c873ea47fb26e1d482ea8f | |
parent | dba534a103dc9fb374bc313ac96d54d331cbd54a (diff) | |
parent | 4f4582a6ad263d8c9051c75a3a38ecfe41695316 (diff) |
Merge #5481
5481: Track document versions in the server r=kjeremy a=kjeremy
This also pushes diagnostics for the correct file version on close so that when it is reopened stale diagnostics are not shown.
Closes #5452
Co-authored-by: kjeremy <[email protected]>
Co-authored-by: Jeremy Kolb <[email protected]>
-rw-r--r-- | crates/rust-analyzer/src/global_state.rs | 13 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 35 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 7 |
3 files changed, 40 insertions, 15 deletions
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 94973b90a..80937dbc4 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs | |||
@@ -12,7 +12,7 @@ use parking_lot::RwLock; | |||
12 | use ra_db::{CrateId, VfsPath}; | 12 | use ra_db::{CrateId, VfsPath}; |
13 | use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FileId}; | 13 | use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FileId}; |
14 | use ra_project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target}; | 14 | use ra_project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target}; |
15 | use rustc_hash::{FxHashMap, FxHashSet}; | 15 | use rustc_hash::FxHashMap; |
16 | 16 | ||
17 | use crate::{ | 17 | use crate::{ |
18 | config::Config, | 18 | config::Config, |
@@ -69,7 +69,7 @@ pub(crate) struct GlobalState { | |||
69 | pub(crate) config: Config, | 69 | pub(crate) config: Config, |
70 | pub(crate) analysis_host: AnalysisHost, | 70 | pub(crate) analysis_host: AnalysisHost, |
71 | pub(crate) diagnostics: DiagnosticCollection, | 71 | pub(crate) diagnostics: DiagnosticCollection, |
72 | pub(crate) mem_docs: FxHashSet<VfsPath>, | 72 | pub(crate) mem_docs: FxHashMap<VfsPath, Option<i64>>, |
73 | pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>, | 73 | pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>, |
74 | pub(crate) status: Status, | 74 | pub(crate) status: Status, |
75 | pub(crate) source_root_config: SourceRootConfig, | 75 | pub(crate) source_root_config: SourceRootConfig, |
@@ -84,6 +84,7 @@ pub(crate) struct GlobalStateSnapshot { | |||
84 | pub(crate) analysis: Analysis, | 84 | pub(crate) analysis: Analysis, |
85 | pub(crate) check_fixes: CheckFixes, | 85 | pub(crate) check_fixes: CheckFixes, |
86 | pub(crate) latest_requests: Arc<RwLock<LatestRequests>>, | 86 | pub(crate) latest_requests: Arc<RwLock<LatestRequests>>, |
87 | mem_docs: FxHashMap<VfsPath, Option<i64>>, | ||
87 | vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>, | 88 | vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>, |
88 | pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>, | 89 | pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>, |
89 | } | 90 | } |
@@ -117,7 +118,7 @@ impl GlobalState { | |||
117 | config, | 118 | config, |
118 | analysis_host, | 119 | analysis_host, |
119 | diagnostics: Default::default(), | 120 | diagnostics: Default::default(), |
120 | mem_docs: FxHashSet::default(), | 121 | mem_docs: FxHashMap::default(), |
121 | vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), | 122 | vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), |
122 | status: Status::default(), | 123 | status: Status::default(), |
123 | source_root_config: SourceRootConfig::default(), | 124 | source_root_config: SourceRootConfig::default(), |
@@ -183,6 +184,7 @@ impl GlobalState { | |||
183 | vfs: Arc::clone(&self.vfs), | 184 | vfs: Arc::clone(&self.vfs), |
184 | latest_requests: Arc::clone(&self.latest_requests), | 185 | latest_requests: Arc::clone(&self.latest_requests), |
185 | check_fixes: Arc::clone(&self.diagnostics.check_fixes), | 186 | check_fixes: Arc::clone(&self.diagnostics.check_fixes), |
187 | mem_docs: self.mem_docs.clone(), | ||
186 | } | 188 | } |
187 | } | 189 | } |
188 | 190 | ||
@@ -255,6 +257,11 @@ impl GlobalStateSnapshot { | |||
255 | self.vfs.read().1[&id] | 257 | self.vfs.read().1[&id] |
256 | } | 258 | } |
257 | 259 | ||
260 | pub(crate) fn url_file_version(&self, url: &Url) -> Option<i64> { | ||
261 | let path = from_proto::vfs_path(&url).ok()?; | ||
262 | self.mem_docs.get(&path).copied()? | ||
263 | } | ||
264 | |||
258 | pub(crate) fn anchored_path(&self, file_id: FileId, path: &str) -> Url { | 265 | pub(crate) fn anchored_path(&self, file_id: FileId, path: &str) -> Url { |
259 | let mut base = self.vfs.read().0.file_path(file_id); | 266 | let mut base = self.vfs.read().0.file_path(file_id); |
260 | base.pop(); | 267 | base.pop(); |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index bb7c4c0c6..f6d8daeed 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -210,7 +210,7 @@ impl GlobalState { | |||
210 | let vfs = &mut self.vfs.write().0; | 210 | let vfs = &mut self.vfs.write().0; |
211 | for (path, contents) in files { | 211 | for (path, contents) in files { |
212 | let path = VfsPath::from(path); | 212 | let path = VfsPath::from(path); |
213 | if !self.mem_docs.contains(&path) { | 213 | if !self.mem_docs.contains_key(&path) { |
214 | vfs.set_file_contents(path, contents) | 214 | vfs.set_file_contents(path, contents) |
215 | } | 215 | } |
216 | } | 216 | } |
@@ -299,7 +299,7 @@ impl GlobalState { | |||
299 | if self.status == Status::Ready && (state_changed || prev_status == Status::Loading) { | 299 | if self.status == Status::Ready && (state_changed || prev_status == Status::Loading) { |
300 | let subscriptions = self | 300 | let subscriptions = self |
301 | .mem_docs | 301 | .mem_docs |
302 | .iter() | 302 | .keys() |
303 | .map(|path| self.vfs.read().0.file_id(&path).unwrap()) | 303 | .map(|path| self.vfs.read().0.file_id(&path).unwrap()) |
304 | .collect::<Vec<_>>(); | 304 | .collect::<Vec<_>>(); |
305 | 305 | ||
@@ -310,8 +310,12 @@ impl GlobalState { | |||
310 | for file_id in diagnostic_changes { | 310 | for file_id in diagnostic_changes { |
311 | let url = file_id_to_url(&self.vfs.read().0, file_id); | 311 | let url = file_id_to_url(&self.vfs.read().0, file_id); |
312 | let diagnostics = self.diagnostics.diagnostics_for(file_id).cloned().collect(); | 312 | let diagnostics = self.diagnostics.diagnostics_for(file_id).cloned().collect(); |
313 | let version = from_proto::vfs_path(&url) | ||
314 | .map(|path| self.mem_docs.get(&path).copied().flatten()) | ||
315 | .unwrap_or_default(); | ||
316 | |||
313 | self.send_notification::<lsp_types::notification::PublishDiagnostics>( | 317 | self.send_notification::<lsp_types::notification::PublishDiagnostics>( |
314 | lsp_types::PublishDiagnosticsParams { uri: url, diagnostics, version: None }, | 318 | lsp_types::PublishDiagnosticsParams { uri: url, diagnostics, version }, |
315 | ); | 319 | ); |
316 | } | 320 | } |
317 | } | 321 | } |
@@ -400,7 +404,11 @@ impl GlobalState { | |||
400 | })? | 404 | })? |
401 | .on::<lsp_types::notification::DidOpenTextDocument>(|this, params| { | 405 | .on::<lsp_types::notification::DidOpenTextDocument>(|this, params| { |
402 | if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { | 406 | if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { |
403 | if !this.mem_docs.insert(path.clone()) { | 407 | if this |
408 | .mem_docs | ||
409 | .insert(path.clone(), Some(params.text_document.version)) | ||
410 | .is_some() | ||
411 | { | ||
404 | log::error!("duplicate DidOpenTextDocument: {}", path) | 412 | log::error!("duplicate DidOpenTextDocument: {}", path) |
405 | } | 413 | } |
406 | this.vfs | 414 | this.vfs |
@@ -412,29 +420,38 @@ impl GlobalState { | |||
412 | })? | 420 | })? |
413 | .on::<lsp_types::notification::DidChangeTextDocument>(|this, params| { | 421 | .on::<lsp_types::notification::DidChangeTextDocument>(|this, params| { |
414 | if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { | 422 | if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { |
415 | assert!(this.mem_docs.contains(&path)); | 423 | *this.mem_docs.get_mut(&path).unwrap() = params.text_document.version; |
416 | let vfs = &mut this.vfs.write().0; | 424 | let vfs = &mut this.vfs.write().0; |
417 | let file_id = vfs.file_id(&path).unwrap(); | 425 | let file_id = vfs.file_id(&path).unwrap(); |
418 | let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec()).unwrap(); | 426 | let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec()).unwrap(); |
419 | apply_document_changes(&mut text, params.content_changes); | 427 | apply_document_changes(&mut text, params.content_changes); |
420 | vfs.set_file_contents(path, Some(text.into_bytes())) | 428 | vfs.set_file_contents(path.clone(), Some(text.into_bytes())); |
429 | |||
430 | this.mem_docs.insert(path, params.text_document.version); | ||
421 | } | 431 | } |
422 | Ok(()) | 432 | Ok(()) |
423 | })? | 433 | })? |
424 | .on::<lsp_types::notification::DidCloseTextDocument>(|this, params| { | 434 | .on::<lsp_types::notification::DidCloseTextDocument>(|this, params| { |
435 | let mut version = None; | ||
425 | if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { | 436 | if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { |
426 | if !this.mem_docs.remove(&path) { | 437 | match this.mem_docs.remove(&path) { |
427 | log::error!("orphan DidCloseTextDocument: {}", path) | 438 | Some(entry) => version = entry, |
439 | None => log::error!("orphan DidCloseTextDocument: {}", path), | ||
428 | } | 440 | } |
441 | |||
429 | if let Some(path) = path.as_path() { | 442 | if let Some(path) = path.as_path() { |
430 | this.loader.handle.invalidate(path.to_path_buf()); | 443 | this.loader.handle.invalidate(path.to_path_buf()); |
431 | } | 444 | } |
432 | } | 445 | } |
446 | |||
447 | // Clear the diagnostics for the previously known version of the file. | ||
448 | // This prevents stale "cargo check" diagnostics if the file is | ||
449 | // closed, "cargo check" is run and then the file is reopened. | ||
433 | this.send_notification::<lsp_types::notification::PublishDiagnostics>( | 450 | this.send_notification::<lsp_types::notification::PublishDiagnostics>( |
434 | lsp_types::PublishDiagnosticsParams { | 451 | lsp_types::PublishDiagnosticsParams { |
435 | uri: params.text_document.uri, | 452 | uri: params.text_document.uri, |
436 | diagnostics: Vec::new(), | 453 | diagnostics: Vec::new(), |
437 | version: None, | 454 | version, |
438 | }, | 455 | }, |
439 | ); | 456 | ); |
440 | Ok(()) | 457 | Ok(()) |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index fc94f28b9..c6935c029 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -480,9 +480,10 @@ pub(crate) fn url_from_abs_path(path: &Path) -> lsp_types::Url { | |||
480 | pub(crate) fn versioned_text_document_identifier( | 480 | pub(crate) fn versioned_text_document_identifier( |
481 | snap: &GlobalStateSnapshot, | 481 | snap: &GlobalStateSnapshot, |
482 | file_id: FileId, | 482 | file_id: FileId, |
483 | version: Option<i64>, | ||
484 | ) -> lsp_types::VersionedTextDocumentIdentifier { | 483 | ) -> lsp_types::VersionedTextDocumentIdentifier { |
485 | lsp_types::VersionedTextDocumentIdentifier { uri: url(snap, file_id), version } | 484 | let url = url(snap, file_id); |
485 | let version = snap.url_file_version(&url); | ||
486 | lsp_types::VersionedTextDocumentIdentifier { uri: url, version } | ||
486 | } | 487 | } |
487 | 488 | ||
488 | pub(crate) fn location( | 489 | pub(crate) fn location( |
@@ -571,7 +572,7 @@ pub(crate) fn snippet_text_document_edit( | |||
571 | is_snippet: bool, | 572 | is_snippet: bool, |
572 | source_file_edit: SourceFileEdit, | 573 | source_file_edit: SourceFileEdit, |
573 | ) -> Result<lsp_ext::SnippetTextDocumentEdit> { | 574 | ) -> Result<lsp_ext::SnippetTextDocumentEdit> { |
574 | let text_document = versioned_text_document_identifier(snap, source_file_edit.file_id, None); | 575 | let text_document = versioned_text_document_identifier(snap, source_file_edit.file_id); |
575 | let line_index = snap.analysis.file_line_index(source_file_edit.file_id)?; | 576 | let line_index = snap.analysis.file_line_index(source_file_edit.file_id)?; |
576 | let line_endings = snap.file_line_endings(source_file_edit.file_id); | 577 | let line_endings = snap.file_line_endings(source_file_edit.file_id); |
577 | let edits = source_file_edit | 578 | let edits = source_file_edit |