Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 19 additions & 15 deletions crates/rust-analyzer/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,21 +173,6 @@ pub(crate) fn fetch_native_diagnostics(
let _p = tracing::info_span!("fetch_native_diagnostics").entered();
let _ctx = stdx::panic_context::enter("fetch_native_diagnostics".to_owned());

let convert_diagnostic =
|line_index: &crate::line_index::LineIndex, d: ide::Diagnostic| lsp_types::Diagnostic {
range: lsp::to_proto::range(line_index, d.range.range),
severity: Some(lsp::to_proto::diagnostic_severity(d.severity)),
code: Some(lsp_types::NumberOrString::String(d.code.as_str().to_owned())),
code_description: Some(lsp_types::CodeDescription {
href: lsp_types::Url::parse(&d.code.url()).unwrap(),
}),
source: Some("rust-analyzer".to_owned()),
message: d.message,
related_information: None,
tags: d.unused.then(|| vec![lsp_types::DiagnosticTag::UNNECESSARY]),
data: None,
};

// the diagnostics produced may point to different files not requested by the concrete request,
// put those into here and filter later
let mut odd_ones = Vec::new();
Expand Down Expand Up @@ -246,3 +231,22 @@ pub(crate) fn fetch_native_diagnostics(
}
diagnostics
}

pub(crate) fn convert_diagnostic(
line_index: &crate::line_index::LineIndex,
d: ide::Diagnostic,
) -> lsp_types::Diagnostic {
lsp_types::Diagnostic {
range: lsp::to_proto::range(line_index, d.range.range),
severity: Some(lsp::to_proto::diagnostic_severity(d.severity)),
code: Some(lsp_types::NumberOrString::String(d.code.as_str().to_owned())),
code_description: Some(lsp_types::CodeDescription {
href: lsp_types::Url::parse(&d.code.url()).unwrap(),
}),
source: Some("rust-analyzer".to_owned()),
message: d.message,
related_information: None,
tags: d.unused.then(|| vec![lsp_types::DiagnosticTag::UNNECESSARY]),
data: None,
}
}
24 changes: 24 additions & 0 deletions crates/rust-analyzer/src/handlers/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,30 @@ impl RequestDispatcher<'_> {
self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(ThreadIntent::Worker, f)
}

/// Dispatches a non-latency-sensitive request onto the thread pool. When the VFS is marked not
/// ready this will return a default constructed [`R::Result`].
pub(crate) fn on_or<const ALLOW_RETRYING: bool, R>(
&mut self,
f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>,
default: impl FnOnce() -> R::Result,
) -> &mut Self
where
R: lsp_types::request::Request<
Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
Result: Serialize,
> + 'static,
{
if !self.global_state.vfs_done {
if let Some(lsp_server::Request { id, .. }) =
self.req.take_if(|it| it.method == R::METHOD)
{
self.global_state.respond(lsp_server::Response::new_ok(id, default()));
}
return self;
}
self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(ThreadIntent::Worker, f)
}

/// Dispatches a non-latency-sensitive request onto the thread pool. When the VFS is marked not
/// ready this will return the parameter as is.
pub(crate) fn on_identity<const ALLOW_RETRYING: bool, R, Params>(
Expand Down
66 changes: 65 additions & 1 deletion crates/rust-analyzer/src/handlers/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use std::{
fs,
io::Write as _,
ops::Not,
process::{self, Stdio},
};

Expand All @@ -14,7 +15,7 @@ use ide::{
FilePosition, FileRange, HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query,
RangeInfo, ReferenceCategory, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit,
};
use ide_db::SymbolKind;
use ide_db::{FxHashMap, SymbolKind};
use itertools::Itertools;
use lsp_server::ErrorCode;
use lsp_types::{
Expand All @@ -36,6 +37,7 @@ use vfs::{AbsPath, AbsPathBuf, FileId, VfsPath};

use crate::{
config::{Config, RustfmtConfig, WorkspaceSymbolConfig},
diagnostics::convert_diagnostic,
global_state::{FetchWorkspaceRequest, GlobalState, GlobalStateSnapshot},
hack_recover_crate_name,
line_index::LineEndings,
Expand Down Expand Up @@ -473,6 +475,68 @@ pub(crate) fn handle_on_type_formatting(
Ok(Some(change))
}

pub(crate) fn handle_document_diagnostics(
snap: GlobalStateSnapshot,
params: lsp_types::DocumentDiagnosticParams,
) -> anyhow::Result<lsp_types::DocumentDiagnosticReportResult> {
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let source_root = snap.analysis.source_root_id(file_id)?;
let line_index = snap.file_line_index(file_id)?;
let config = snap.config.diagnostics(Some(source_root));
if !config.enabled {
return Ok(lsp_types::DocumentDiagnosticReportResult::Report(
lsp_types::DocumentDiagnosticReport::Full(
lsp_types::RelatedFullDocumentDiagnosticReport {
related_documents: None,
full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
result_id: None,
items: vec![],
},
},
),
));
}
let supports_related = snap.config.text_document_diagnostic_related_document_support();

let mut related_documents = FxHashMap::default();
let diagnostics = snap
.analysis
.full_diagnostics(&config, AssistResolveStrategy::None, file_id)?
.into_iter()
.filter_map(|d| {
let file = d.range.file_id;
let diagnostic = convert_diagnostic(&line_index, d);
if file == file_id {
return Some(diagnostic);
}
if supports_related {
related_documents.entry(file).or_insert_with(Vec::new).push(diagnostic);
}
None
});
Ok(lsp_types::DocumentDiagnosticReportResult::Report(
lsp_types::DocumentDiagnosticReport::Full(lsp_types::RelatedFullDocumentDiagnosticReport {
full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
result_id: None,
items: diagnostics.collect(),
},
related_documents: related_documents.is_empty().not().then(|| {
related_documents
.into_iter()
.map(|(id, items)| {
(
to_proto::url(&snap, id),
lsp_types::DocumentDiagnosticReportKind::Full(
lsp_types::FullDocumentDiagnosticReport { result_id: None, items },
),
)
})
.collect()
}),
}),
))
}

pub(crate) fn handle_document_symbol(
snap: GlobalStateSnapshot,
params: lsp_types::DocumentSymbolParams,
Expand Down
19 changes: 18 additions & 1 deletion crates/rust-analyzer/src/lsp/capabilities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,15 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
"ssr": true,
"workspaceSymbolScopeKindFiltering": true,
})),
diagnostic_provider: None,
diagnostic_provider: Some(lsp_types::DiagnosticServerCapabilities::Options(
lsp_types::DiagnosticOptions {
identifier: None,
inter_file_dependencies: true,
// FIXME
workspace_diagnostics: false,
work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
},
)),
inline_completion_provider: None,
}
}
Expand Down Expand Up @@ -380,6 +388,15 @@ impl ClientCapabilities {
.unwrap_or_default()
}

pub fn text_document_diagnostic(&self) -> bool {
(|| -> _ { self.0.text_document.as_ref()?.diagnostic.as_ref() })().is_some()
}

pub fn text_document_diagnostic_related_document_support(&self) -> bool {
(|| -> _ { self.0.text_document.as_ref()?.diagnostic.as_ref()?.related_document_support })()
== Some(true)
}

pub fn code_action_group(&self) -> bool {
self.experimental_bool("codeActionGroup")
}
Expand Down
25 changes: 24 additions & 1 deletion crates/rust-analyzer/src/main_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,8 @@ impl GlobalState {
}
}

let supports_diagnostic_pull_model = self.config.text_document_diagnostic();

let client_refresh = became_quiescent || state_changed;
if client_refresh {
// Refresh semantic tokens if the client supports it.
Expand All @@ -434,11 +436,21 @@ impl GlobalState {
if self.config.inlay_hints_refresh() {
self.send_request::<lsp_types::request::InlayHintRefreshRequest>((), |_, _| ());
}

if supports_diagnostic_pull_model {
self.send_request::<lsp_types::request::WorkspaceDiagnosticRefresh>(
(),
|_, _| (),
);
}
}

let project_or_mem_docs_changed =
became_quiescent || state_changed || memdocs_added_or_removed;
if project_or_mem_docs_changed && self.config.publish_diagnostics(None) {
if project_or_mem_docs_changed
&& !supports_diagnostic_pull_model
&& self.config.publish_diagnostics(None)
{
self.update_diagnostics();
}
if project_or_mem_docs_changed && self.config.test_explorer() {
Expand Down Expand Up @@ -1080,6 +1092,17 @@ impl GlobalState {
.on_latency_sensitive::<NO_RETRY, lsp_request::SemanticTokensRangeRequest>(handlers::handle_semantic_tokens_range)
// FIXME: Some of these NO_RETRY could be retries if the file they are interested didn't change.
// All other request handlers
.on_or::<NO_RETRY, lsp_request::DocumentDiagnosticRequest>(handlers::handle_document_diagnostics, || lsp_types::DocumentDiagnosticReportResult::Report(
lsp_types::DocumentDiagnosticReport::Full(
lsp_types::RelatedFullDocumentDiagnosticReport {
related_documents: None,
full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
result_id: None,
items: vec![],
},
},
),
))
.on::<RETRY, lsp_request::DocumentSymbolRequest>(handlers::handle_document_symbol)
.on::<RETRY, lsp_request::FoldingRangeRequest>(handlers::handle_folding_range)
.on::<NO_RETRY, lsp_request::SignatureHelpRequest>(handlers::handle_signature_help)
Expand Down