mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 12:54:58 +00:00
Merge #10902
10902: Handle multiple cargo check quick fix spans r=Veykril a=brandondong Resolves https://github.com/rust-analyzer/rust-analyzer/issues/10705. **Cause:** - For a cargo check diagnostic with multiple spans, only a single quick fix action would be created at the location of `spans[0]`. Additionally, the hover window details would only show the location of `spans[0]` next to the message. **Fix:** - Allow cargo check quick fix actions to be triggerable from multiple selection ranges. Specifically, if the selection intersects with any of the replacement spans, the quick fix action is shown. - No change in behavior for the hover window details. It's pretty minor and I think showing multiple locations next to the message may be more confusing anyways. Co-authored-by: Brandon <brandondong604@hotmail.com>
This commit is contained in:
commit
8a084e6aca
14 changed files with 384 additions and 295 deletions
|
@ -29,7 +29,8 @@ pub(crate) struct DiagnosticCollection {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct Fix {
|
pub(crate) struct Fix {
|
||||||
pub(crate) range: lsp_types::Range,
|
// Fixes may be triggerable from multiple ranges.
|
||||||
|
pub(crate) ranges: Vec<lsp_types::Range>,
|
||||||
pub(crate) action: lsp_ext::CodeAction,
|
pub(crate) action: lsp_ext::CodeAction,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ impl DiagnosticCollection {
|
||||||
&mut self,
|
&mut self,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
diagnostic: lsp_types::Diagnostic,
|
diagnostic: lsp_types::Diagnostic,
|
||||||
fixes: Vec<lsp_ext::CodeAction>,
|
fix: Option<Fix>,
|
||||||
) {
|
) {
|
||||||
let diagnostics = self.check.entry(file_id).or_default();
|
let diagnostics = self.check.entry(file_id).or_default();
|
||||||
for existing_diagnostic in diagnostics.iter() {
|
for existing_diagnostic in diagnostics.iter() {
|
||||||
|
@ -53,10 +54,7 @@ impl DiagnosticCollection {
|
||||||
}
|
}
|
||||||
|
|
||||||
let check_fixes = Arc::make_mut(&mut self.check_fixes);
|
let check_fixes = Arc::make_mut(&mut self.check_fixes);
|
||||||
check_fixes
|
check_fixes.entry(file_id).or_default().extend(fix);
|
||||||
.entry(file_id)
|
|
||||||
.or_default()
|
|
||||||
.extend(fixes.into_iter().map(|action| Fix { range: diagnostic.range, action }));
|
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
self.changes.insert(file_id);
|
self.changes.insert(file_id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@
|
||||||
tags: None,
|
tags: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [],
|
fix: None,
|
||||||
},
|
},
|
||||||
MappedRustDiagnostic {
|
MappedRustDiagnostic {
|
||||||
url: Url {
|
url: Url {
|
||||||
|
@ -205,7 +205,7 @@
|
||||||
tags: None,
|
tags: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [],
|
fix: None,
|
||||||
},
|
},
|
||||||
MappedRustDiagnostic {
|
MappedRustDiagnostic {
|
||||||
url: Url {
|
url: Url {
|
||||||
|
@ -296,8 +296,21 @@
|
||||||
tags: None,
|
tags: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [
|
fix: Some(
|
||||||
CodeAction {
|
Fix {
|
||||||
|
ranges: [
|
||||||
|
Range {
|
||||||
|
start: Position {
|
||||||
|
line: 41,
|
||||||
|
character: 23,
|
||||||
|
},
|
||||||
|
end: Position {
|
||||||
|
line: 41,
|
||||||
|
character: 28,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
action: CodeAction {
|
||||||
title: "consider passing by value instead: `self`",
|
title: "consider passing by value instead: `self`",
|
||||||
group: None,
|
group: None,
|
||||||
kind: Some(
|
kind: Some(
|
||||||
|
@ -345,6 +358,7 @@
|
||||||
),
|
),
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
|
),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -59,6 +59,6 @@
|
||||||
tags: None,
|
tags: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [],
|
fix: None,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -64,7 +64,7 @@
|
||||||
tags: None,
|
tags: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [],
|
fix: None,
|
||||||
},
|
},
|
||||||
MappedRustDiagnostic {
|
MappedRustDiagnostic {
|
||||||
url: Url {
|
url: Url {
|
||||||
|
@ -131,7 +131,7 @@
|
||||||
tags: None,
|
tags: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [],
|
fix: None,
|
||||||
},
|
},
|
||||||
MappedRustDiagnostic {
|
MappedRustDiagnostic {
|
||||||
url: Url {
|
url: Url {
|
||||||
|
@ -224,6 +224,6 @@
|
||||||
tags: None,
|
tags: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [],
|
fix: None,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -59,6 +59,6 @@
|
||||||
tags: None,
|
tags: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [],
|
fix: None,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -59,6 +59,6 @@
|
||||||
tags: None,
|
tags: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [],
|
fix: None,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
),
|
),
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [],
|
fix: None,
|
||||||
},
|
},
|
||||||
MappedRustDiagnostic {
|
MappedRustDiagnostic {
|
||||||
url: Url {
|
url: Url {
|
||||||
|
@ -143,8 +143,21 @@
|
||||||
tags: None,
|
tags: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [
|
fix: Some(
|
||||||
CodeAction {
|
Fix {
|
||||||
|
ranges: [
|
||||||
|
Range {
|
||||||
|
start: Position {
|
||||||
|
line: 290,
|
||||||
|
character: 8,
|
||||||
|
},
|
||||||
|
end: Position {
|
||||||
|
line: 290,
|
||||||
|
character: 11,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
action: CodeAction {
|
||||||
title: "consider prefixing with an underscore: `_foo`",
|
title: "consider prefixing with an underscore: `_foo`",
|
||||||
group: None,
|
group: None,
|
||||||
kind: Some(
|
kind: Some(
|
||||||
|
@ -192,6 +205,7 @@
|
||||||
),
|
),
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
|
),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
),
|
),
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [],
|
fix: None,
|
||||||
},
|
},
|
||||||
MappedRustDiagnostic {
|
MappedRustDiagnostic {
|
||||||
url: Url {
|
url: Url {
|
||||||
|
@ -143,8 +143,21 @@
|
||||||
tags: None,
|
tags: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [
|
fix: Some(
|
||||||
CodeAction {
|
Fix {
|
||||||
|
ranges: [
|
||||||
|
Range {
|
||||||
|
start: Position {
|
||||||
|
line: 290,
|
||||||
|
character: 8,
|
||||||
|
},
|
||||||
|
end: Position {
|
||||||
|
line: 290,
|
||||||
|
character: 11,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
action: CodeAction {
|
||||||
title: "consider prefixing with an underscore: `_foo`",
|
title: "consider prefixing with an underscore: `_foo`",
|
||||||
group: None,
|
group: None,
|
||||||
kind: Some(
|
kind: Some(
|
||||||
|
@ -192,6 +205,7 @@
|
||||||
),
|
),
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
|
),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
),
|
),
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [],
|
fix: None,
|
||||||
},
|
},
|
||||||
MappedRustDiagnostic {
|
MappedRustDiagnostic {
|
||||||
url: Url {
|
url: Url {
|
||||||
|
@ -143,8 +143,21 @@
|
||||||
tags: None,
|
tags: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [
|
fix: Some(
|
||||||
CodeAction {
|
Fix {
|
||||||
|
ranges: [
|
||||||
|
Range {
|
||||||
|
start: Position {
|
||||||
|
line: 290,
|
||||||
|
character: 8,
|
||||||
|
},
|
||||||
|
end: Position {
|
||||||
|
line: 290,
|
||||||
|
character: 11,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
action: CodeAction {
|
||||||
title: "consider prefixing with an underscore: `_foo`",
|
title: "consider prefixing with an underscore: `_foo`",
|
||||||
group: None,
|
group: None,
|
||||||
kind: Some(
|
kind: Some(
|
||||||
|
@ -192,6 +205,7 @@
|
||||||
),
|
),
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
|
),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -88,7 +88,7 @@
|
||||||
tags: None,
|
tags: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [],
|
fix: None,
|
||||||
},
|
},
|
||||||
MappedRustDiagnostic {
|
MappedRustDiagnostic {
|
||||||
url: Url {
|
url: Url {
|
||||||
|
@ -179,6 +179,6 @@
|
||||||
tags: None,
|
tags: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [],
|
fix: None,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -114,7 +114,7 @@
|
||||||
tags: None,
|
tags: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [],
|
fix: None,
|
||||||
},
|
},
|
||||||
MappedRustDiagnostic {
|
MappedRustDiagnostic {
|
||||||
url: Url {
|
url: Url {
|
||||||
|
@ -205,7 +205,7 @@
|
||||||
tags: None,
|
tags: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [],
|
fix: None,
|
||||||
},
|
},
|
||||||
MappedRustDiagnostic {
|
MappedRustDiagnostic {
|
||||||
url: Url {
|
url: Url {
|
||||||
|
@ -296,8 +296,31 @@
|
||||||
tags: None,
|
tags: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: [
|
fix: Some(
|
||||||
CodeAction {
|
Fix {
|
||||||
|
ranges: [
|
||||||
|
Range {
|
||||||
|
start: Position {
|
||||||
|
line: 2,
|
||||||
|
character: 4,
|
||||||
|
},
|
||||||
|
end: Position {
|
||||||
|
line: 2,
|
||||||
|
character: 30,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Range {
|
||||||
|
start: Position {
|
||||||
|
line: 3,
|
||||||
|
character: 4,
|
||||||
|
},
|
||||||
|
end: Position {
|
||||||
|
line: 3,
|
||||||
|
character: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
action: CodeAction {
|
||||||
title: "return the expression directly: `(0..10).collect()`",
|
title: "return the expression directly: `(0..10).collect()`",
|
||||||
group: None,
|
group: None,
|
||||||
kind: Some(
|
kind: Some(
|
||||||
|
@ -358,6 +381,7 @@
|
||||||
),
|
),
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
|
),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -9,7 +9,7 @@ use vfs::{AbsPath, AbsPathBuf};
|
||||||
|
|
||||||
use crate::{lsp_ext, to_proto::url_from_abs_path};
|
use crate::{lsp_ext, to_proto::url_from_abs_path};
|
||||||
|
|
||||||
use super::DiagnosticsMapConfig;
|
use super::{DiagnosticsMapConfig, Fix};
|
||||||
|
|
||||||
/// Determines the LSP severity from a diagnostic
|
/// Determines the LSP severity from a diagnostic
|
||||||
fn diagnostic_severity(
|
fn diagnostic_severity(
|
||||||
|
@ -124,7 +124,7 @@ fn resolve_path(
|
||||||
|
|
||||||
struct SubDiagnostic {
|
struct SubDiagnostic {
|
||||||
related: lsp_types::DiagnosticRelatedInformation,
|
related: lsp_types::DiagnosticRelatedInformation,
|
||||||
suggested_fix: Option<lsp_ext::CodeAction>,
|
suggested_fix: Option<Fix>,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MappedRustChildDiagnostic {
|
enum MappedRustChildDiagnostic {
|
||||||
|
@ -181,7 +181,12 @@ fn map_rust_child_diagnostic(
|
||||||
location: location(config, workspace_root, spans[0]),
|
location: location(config, workspace_root, spans[0]),
|
||||||
message: message.clone(),
|
message: message.clone(),
|
||||||
},
|
},
|
||||||
suggested_fix: Some(lsp_ext::CodeAction {
|
suggested_fix: Some(Fix {
|
||||||
|
ranges: spans
|
||||||
|
.iter()
|
||||||
|
.map(|&span| location(config, workspace_root, span).range)
|
||||||
|
.collect(),
|
||||||
|
action: lsp_ext::CodeAction {
|
||||||
title: message,
|
title: message,
|
||||||
group: None,
|
group: None,
|
||||||
kind: Some(lsp_types::CodeActionKind::QUICKFIX),
|
kind: Some(lsp_types::CodeActionKind::QUICKFIX),
|
||||||
|
@ -193,6 +198,7 @@ fn map_rust_child_diagnostic(
|
||||||
}),
|
}),
|
||||||
is_preferred: Some(true),
|
is_preferred: Some(true),
|
||||||
data: None,
|
data: None,
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -202,7 +208,7 @@ fn map_rust_child_diagnostic(
|
||||||
pub(crate) struct MappedRustDiagnostic {
|
pub(crate) struct MappedRustDiagnostic {
|
||||||
pub(crate) url: lsp_types::Url,
|
pub(crate) url: lsp_types::Url,
|
||||||
pub(crate) diagnostic: lsp_types::Diagnostic,
|
pub(crate) diagnostic: lsp_types::Diagnostic,
|
||||||
pub(crate) fixes: Vec<lsp_ext::CodeAction>,
|
pub(crate) fix: Option<Fix>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a Rust root diagnostic to LSP form
|
/// Converts a Rust root diagnostic to LSP form
|
||||||
|
@ -359,7 +365,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
|
||||||
diagnostics.push(MappedRustDiagnostic {
|
diagnostics.push(MappedRustDiagnostic {
|
||||||
url: secondary_location.uri,
|
url: secondary_location.uri,
|
||||||
diagnostic,
|
diagnostic,
|
||||||
fixes: Vec::new(),
|
fix: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,7 +394,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
|
||||||
tags: if tags.is_empty() { None } else { Some(tags.clone()) },
|
tags: if tags.is_empty() { None } else { Some(tags.clone()) },
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
fixes: Vec::new(),
|
fix: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Emit hint-level diagnostics for all `related_information` entries such as "help"s.
|
// Emit hint-level diagnostics for all `related_information` entries such as "help"s.
|
||||||
|
@ -405,7 +411,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
|
||||||
}
|
}
|
||||||
diagnostics.push(MappedRustDiagnostic {
|
diagnostics.push(MappedRustDiagnostic {
|
||||||
url: sub.related.location.uri.clone(),
|
url: sub.related.location.uri.clone(),
|
||||||
fixes: sub.suggested_fix.iter().cloned().collect(),
|
fix: sub.suggested_fix.clone(),
|
||||||
diagnostic: lsp_types::Diagnostic {
|
diagnostic: lsp_types::Diagnostic {
|
||||||
range: sub.related.location.range,
|
range: sub.related.location.range,
|
||||||
severity: Some(lsp_types::DiagnosticSeverity::HINT),
|
severity: Some(lsp_types::DiagnosticSeverity::HINT),
|
||||||
|
|
|
@ -1081,8 +1081,13 @@ pub(crate) fn handle_code_action(
|
||||||
for fix in snap.check_fixes.get(&frange.file_id).into_iter().flatten() {
|
for fix in snap.check_fixes.get(&frange.file_id).into_iter().flatten() {
|
||||||
// FIXME: this mapping is awkward and shouldn't exist. Refactor
|
// FIXME: this mapping is awkward and shouldn't exist. Refactor
|
||||||
// `snap.check_fixes` to not convert to LSP prematurely.
|
// `snap.check_fixes` to not convert to LSP prematurely.
|
||||||
let fix_range = from_proto::text_range(&line_index, fix.range);
|
let intersect_fix_range = fix
|
||||||
if fix_range.intersect(frange.range).is_some() {
|
.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());
|
res.push(fix.action.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,7 +370,7 @@ impl GlobalState {
|
||||||
Ok(file_id) => self.diagnostics.add_check_diagnostic(
|
Ok(file_id) => self.diagnostics.add_check_diagnostic(
|
||||||
file_id,
|
file_id,
|
||||||
diag.diagnostic,
|
diag.diagnostic,
|
||||||
diag.fixes,
|
diag.fix,
|
||||||
),
|
),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
tracing::error!(
|
tracing::error!(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue