Skip to content

Commit

Permalink
fix(lsp): remove Sources mutex
Browse files Browse the repository at this point in the history
The mutex was used to hide the fact that the Sources object mutates
itself when it's queried. Be honest about that and mark everything that
directly or indirectly mutates it as `mut`.

This is a follow-up to commit 2828690
from last month ("fix(lsp): fix deadlocks, use one big mutex (denoland#9271)")
  • Loading branch information
bnoordhuis committed Feb 8, 2021
1 parent 0cac243 commit be10db1
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 182 deletions.
40 changes: 12 additions & 28 deletions cli/lsp/analysis.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.

use super::text::LineIndex;
use super::language_server;
use super::tsc;

use crate::ast;
Expand All @@ -13,7 +13,6 @@ use crate::tools::lint::create_linter;

use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::futures::Future;
use deno_core::serde::Deserialize;
use deno_core::serde::Serialize;
use deno_core::serde_json::json;
Expand Down Expand Up @@ -353,21 +352,14 @@ fn is_preferred(

/// Convert changes returned from a TypeScript quick fix action into edits
/// for an LSP CodeAction.
pub async fn ts_changes_to_edit<F, Fut, V>(
pub(crate) async fn ts_changes_to_edit(
changes: &[tsc::FileTextChanges],
index_provider: &F,
version_provider: &V,
) -> Result<Option<lsp::WorkspaceEdit>, AnyError>
where
F: Fn(ModuleSpecifier) -> Fut + Clone,
Fut: Future<Output = Result<LineIndex, AnyError>>,
V: Fn(ModuleSpecifier) -> Option<i32>,
{
language_server: &mut language_server::Inner,
) -> Result<Option<lsp::WorkspaceEdit>, AnyError> {
let mut text_document_edits = Vec::new();
for change in changes {
let text_document_edit = change
.to_text_document_edit(index_provider, version_provider)
.await?;
let text_document_edit =
change.to_text_document_edit(language_server).await?;
text_document_edits.push(text_document_edit);
}
Ok(Some(lsp::WorkspaceEdit {
Expand All @@ -392,18 +384,12 @@ pub struct CodeActionCollection {

impl CodeActionCollection {
/// Add a TypeScript code fix action to the code actions collection.
pub async fn add_ts_fix_action<F, Fut, V>(
pub(crate) async fn add_ts_fix_action(
&mut self,
action: &tsc::CodeFixAction,
diagnostic: &lsp::Diagnostic,
index_provider: &F,
version_provider: &V,
) -> Result<(), AnyError>
where
F: Fn(ModuleSpecifier) -> Fut + Clone,
Fut: Future<Output = Result<LineIndex, AnyError>>,
V: Fn(ModuleSpecifier) -> Option<i32>,
{
language_server: &mut language_server::Inner,
) -> Result<(), AnyError> {
if action.commands.is_some() {
// In theory, tsc can return actions that require "commands" to be applied
// back into TypeScript. Currently there is only one command, `install
Expand All @@ -417,9 +403,7 @@ impl CodeActionCollection {
"The action returned from TypeScript is unsupported.",
));
}
let edit =
ts_changes_to_edit(&action.changes, index_provider, version_provider)
.await?;
let edit = ts_changes_to_edit(&action.changes, language_server).await?;
let code_action = lsp::CodeAction {
title: action.description.clone(),
kind: Some(lsp::CodeActionKind::QUICKFIX),
Expand Down Expand Up @@ -502,7 +486,7 @@ impl CodeActionCollection {
&self,
action: &tsc::CodeFixAction,
diagnostic: &lsp::Diagnostic,
file_diagnostics: &[&lsp::Diagnostic],
file_diagnostics: &[lsp::Diagnostic],
) -> bool {
// If the action does not have a fix id (indicating it can be "bundled up")
// or if the collection already contains a "bundled" action return false
Expand All @@ -517,7 +501,7 @@ impl CodeActionCollection {
// other diagnostics that could be bundled together in a "fix all" code
// action
file_diagnostics.iter().any(|d| {
if d == &diagnostic || d.code.is_none() || diagnostic.code.is_none() {
if d == diagnostic || d.code.is_none() || diagnostic.code.is_none() {
false
} else {
d.code == diagnostic.code
Expand Down
73 changes: 32 additions & 41 deletions cli/lsp/language_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ pub struct StateSnapshot {
}

#[derive(Debug)]
struct Inner {
pub(crate) struct Inner {
/// Cached versions of "fixed" assets that can either be inlined in Rust or
/// are part of the TypeScript snapshot and have to be fetched out.
assets: HashMap<ModuleSpecifier, Option<AssetDocument>>,
Expand Down Expand Up @@ -132,8 +132,8 @@ impl Inner {
/// Searches assets, open documents and external sources for a line_index,
/// which might be performed asynchronously, hydrating in memory caches for
/// subsequent requests.
async fn get_line_index(
&self,
pub(crate) async fn get_line_index(
&mut self,
specifier: ModuleSpecifier,
) -> Result<LineIndex, AnyError> {
let mark = self.performance.mark("get_line_index");
Expand Down Expand Up @@ -170,7 +170,7 @@ impl Inner {
/// Only searches already cached assets and documents for a line index. If
/// the line index cannot be found, `None` is returned.
fn get_line_index_sync(
&self,
&mut self,
specifier: &ModuleSpecifier,
) -> Option<LineIndex> {
let mark = self.performance.mark("get_line_index_sync");
Expand Down Expand Up @@ -501,6 +501,13 @@ impl Inner {
self.performance.measure(mark);
Ok(())
}

pub(crate) fn document_version(
&mut self,
specifier: ModuleSpecifier,
) -> Option<i32> {
self.documents.version(&specifier)
}
}

// lspower::LanguageServer methods. This file's LanguageServer delegates to us.
Expand Down Expand Up @@ -826,7 +833,7 @@ impl Inner {
}
}

async fn hover(&self, params: HoverParams) -> LspResult<Option<Hover>> {
async fn hover(&mut self, params: HoverParams) -> LspResult<Option<Hover>> {
if !self.enabled() {
return Ok(None);
}
Expand Down Expand Up @@ -898,9 +905,10 @@ impl Inner {
return Ok(None);
}
let line_index = self.get_line_index_sync(&specifier).unwrap();
let file_diagnostics: Vec<&Diagnostic> = self
let file_diagnostics: Vec<Diagnostic> = self
.diagnostics
.diagnostics_for(&specifier, &DiagnosticSource::TypeScript)
.cloned()
.collect();
let mut code_actions = CodeActionCollection::default();
for diagnostic in &fixable_diagnostics {
Expand Down Expand Up @@ -931,12 +939,7 @@ impl Inner {
})?;
for action in actions {
code_actions
.add_ts_fix_action(
&action,
diagnostic,
&|s| self.get_line_index(s),
&|s| self.documents.version(&s),
)
.add_ts_fix_action(&action, diagnostic, self)
.await
.map_err(|err| {
error!("Unable to convert fix: {}", err);
Expand All @@ -958,7 +961,7 @@ impl Inner {
}

async fn code_action_resolve(
&self,
&mut self,
params: CodeAction,
) -> LspResult<CodeAction> {
let mark = self.performance.mark("code_action_resolve");
Expand Down Expand Up @@ -989,16 +992,13 @@ impl Inner {
Err(LspError::invalid_request())
} else {
let mut code_action = params.clone();
code_action.edit = ts_changes_to_edit(
&combined_code_actions.changes,
&|s| self.get_line_index(s),
&|s| self.documents.version(&s),
)
.await
.map_err(|err| {
error!("Unable to convert changes to edits: {}", err);
LspError::internal_error()
})?;
code_action.edit =
ts_changes_to_edit(&combined_code_actions.changes, self)
.await
.map_err(|err| {
error!("Unable to convert changes to edits: {}", err);
LspError::internal_error()
})?;
Ok(code_action)
}
} else {
Expand Down Expand Up @@ -1214,7 +1214,7 @@ impl Inner {
}

async fn document_highlight(
&self,
&mut self,
params: DocumentHighlightParams,
) -> LspResult<Option<Vec<DocumentHighlight>>> {
if !self.enabled() {
Expand Down Expand Up @@ -1342,9 +1342,7 @@ impl Inner {
serde_json::from_value(res).unwrap();

if let Some(definition) = maybe_definition {
let results = definition
.to_definition(&line_index, |s| self.get_line_index(s))
.await;
let results = definition.to_definition(&line_index, self).await;
self.performance.measure(mark);
Ok(results)
} else {
Expand All @@ -1354,7 +1352,7 @@ impl Inner {
}

async fn completion(
&self,
&mut self,
params: CompletionParams,
) -> LspResult<Option<CompletionResponse>> {
if !self.enabled() {
Expand Down Expand Up @@ -1399,7 +1397,7 @@ impl Inner {
}

async fn goto_implementation(
&self,
&mut self,
params: GotoImplementationParams,
) -> LspResult<Option<GotoImplementationResponse>> {
if !self.enabled() {
Expand Down Expand Up @@ -1447,10 +1445,7 @@ impl Inner {
ModuleSpecifier::resolve_url(&document_span.file_name).unwrap();
let impl_line_index =
&self.get_line_index(impl_specifier).await.unwrap();
if let Some(link) = document_span
.to_link(impl_line_index, |s| self.get_line_index(s))
.await
{
if let Some(link) = document_span.to_link(impl_line_index, self).await {
results.push(link);
}
}
Expand All @@ -1463,13 +1458,13 @@ impl Inner {
}

async fn rename(
&self,
&mut self,
params: RenameParams,
) -> LspResult<Option<WorkspaceEdit>> {
if !self.enabled() {
return Ok(None);
}
let mark = self.performance.mark("goto_implementation");
let mark = self.performance.mark("rename");
let specifier =
utils::normalize_url(params.text_document_position.text_document.uri);

Expand Down Expand Up @@ -1515,11 +1510,7 @@ impl Inner {
if let Some(locations) = maybe_locations {
let rename_locations = tsc::RenameLocations { locations };
let workspace_edits = rename_locations
.into_workspace_edit(
&params.new_name,
|s| self.get_line_index(s),
|s| self.documents.version(&s),
)
.into_workspace_edit(&params.new_name, self)
.await
.map_err(|err| {
error!("Failed to get workspace edits: {:#?}", err);
Expand Down Expand Up @@ -1747,7 +1738,7 @@ impl Inner {
}

async fn virtual_text_document(
&self,
&mut self,
params: VirtualTextDocumentParams,
) -> LspResult<Option<String>> {
let mark = self.performance.mark("virtual_text_document");
Expand Down
Loading

0 comments on commit be10db1

Please sign in to comment.