aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-07-22 14:04:30 +0100
committerGitHub <[email protected]>2020-07-22 14:04:30 +0100
commit1c7d5f513cc583413a717fa14c2a394c182d69d6 (patch)
tree82baf4c0467509dd52c873ea47fb26e1d482ea8f
parentdba534a103dc9fb374bc313ac96d54d331cbd54a (diff)
parent4f4582a6ad263d8c9051c75a3a38ecfe41695316 (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.rs13
-rw-r--r--crates/rust-analyzer/src/main_loop.rs35
-rw-r--r--crates/rust-analyzer/src/to_proto.rs7
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;
12use ra_db::{CrateId, VfsPath}; 12use ra_db::{CrateId, VfsPath};
13use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FileId}; 13use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FileId};
14use ra_project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target}; 14use ra_project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target};
15use rustc_hash::{FxHashMap, FxHashSet}; 15use rustc_hash::FxHashMap;
16 16
17use crate::{ 17use 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(&params.text_document.uri) { 406 if let Ok(path) = from_proto::vfs_path(&params.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(&params.text_document.uri) { 422 if let Ok(path) = from_proto::vfs_path(&params.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(&params.text_document.uri) { 436 if let Ok(path) = from_proto::vfs_path(&params.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 {
480pub(crate) fn versioned_text_document_identifier( 480pub(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
488pub(crate) fn location( 489pub(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