From 0d1910c6fb5539330b2464778a1db823aae35aa0 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 4 Dec 2021 20:59:26 -0800 Subject: [PATCH] Handle multiple cargo check quick fix spans --- crates/rust-analyzer/src/diagnostics.rs | 10 +++--- .../rust-analyzer/src/diagnostics/to_proto.rs | 36 +++++++++++-------- crates/rust-analyzer/src/handlers.rs | 9 +++-- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs index c0dab458893..56b3afce98a 100644 --- a/crates/rust-analyzer/src/diagnostics.rs +++ b/crates/rust-analyzer/src/diagnostics.rs @@ -29,7 +29,8 @@ pub(crate) struct DiagnosticCollection { #[derive(Debug, Clone)] pub(crate) struct Fix { - pub(crate) range: lsp_types::Range, + // Fixes may be triggerable from multiple ranges. + pub(crate) ranges: Vec, pub(crate) action: lsp_ext::CodeAction, } @@ -43,7 +44,7 @@ pub(crate) fn add_check_diagnostic( &mut self, file_id: FileId, diagnostic: lsp_types::Diagnostic, - fix: Option, + fix: Option, ) { let diagnostics = self.check.entry(file_id).or_default(); for existing_diagnostic in diagnostics.iter() { @@ -53,10 +54,7 @@ pub(crate) fn add_check_diagnostic( } let check_fixes = Arc::make_mut(&mut self.check_fixes); - check_fixes - .entry(file_id) - .or_default() - .extend(fix.into_iter().map(|action| Fix { range: diagnostic.range, action })); + check_fixes.entry(file_id).or_default().extend(fix); diagnostics.push(diagnostic); self.changes.insert(file_id); } diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index 48af9c186dc..51dbc1939bf 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -9,7 +9,7 @@ use crate::{lsp_ext, to_proto::url_from_abs_path}; -use super::DiagnosticsMapConfig; +use super::{DiagnosticsMapConfig, Fix}; /// Determines the LSP severity from a diagnostic fn diagnostic_severity( @@ -114,7 +114,7 @@ fn resolve_path( struct SubDiagnostic { related: lsp_types::DiagnosticRelatedInformation, - suggested_fix: Option, + suggested_fix: Option, } enum MappedRustChildDiagnostic { @@ -171,18 +171,24 @@ fn map_rust_child_diagnostic( location: location(config, workspace_root, spans[0]), message: message.clone(), }, - suggested_fix: Some(lsp_ext::CodeAction { - title: message, - group: None, - kind: Some(lsp_types::CodeActionKind::QUICKFIX), - edit: Some(lsp_ext::SnippetWorkspaceEdit { - // FIXME: there's no good reason to use edit_map here.... - changes: Some(edit_map), - document_changes: None, - change_annotations: None, - }), - is_preferred: Some(true), - data: None, + suggested_fix: Some(Fix { + ranges: spans + .iter() + .map(|&span| location(config, workspace_root, span).range) + .collect(), + action: lsp_ext::CodeAction { + title: message, + group: None, + kind: Some(lsp_types::CodeActionKind::QUICKFIX), + edit: Some(lsp_ext::SnippetWorkspaceEdit { + // FIXME: there's no good reason to use edit_map here.... + changes: Some(edit_map), + document_changes: None, + change_annotations: None, + }), + is_preferred: Some(true), + data: None, + }, }), }) } @@ -192,7 +198,7 @@ fn map_rust_child_diagnostic( pub(crate) struct MappedRustDiagnostic { pub(crate) url: lsp_types::Url, pub(crate) diagnostic: lsp_types::Diagnostic, - pub(crate) fix: Option, + pub(crate) fix: Option, } /// Converts a Rust root diagnostic to LSP form diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index c3583df713d..6bc2afc6fec 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -1019,8 +1019,13 @@ pub(crate) fn handle_code_action( for fix in snap.check_fixes.get(&frange.file_id).into_iter().flatten() { // FIXME: this mapping is awkward and shouldn't exist. Refactor // `snap.check_fixes` to not convert to LSP prematurely. - let fix_range = from_proto::text_range(&line_index, fix.range); - if fix_range.intersect(frange.range).is_some() { + let intersect_fix_range = fix + .ranges + .iter() + .copied() + .map(|range| from_proto::text_range(&line_index, range)) + .any(|fix_range| fix_range.intersect(frange.range).is_some()); + if intersect_fix_range { res.push(fix.action.clone()); } }