Skip to content

Commit 60841f4

Browse files
committed
Diagnostic paths attempt to use VSCode's path join behavior before defaulting to Rust's path join behavior.
1 parent 32491c0 commit 60841f4

File tree

1 file changed

+30
-3
lines changed

1 file changed

+30
-3
lines changed

crates/rust-analyzer/src/diagnostics/to_proto.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
//! This module provides the functionality needed to convert diagnostics from
22
//! `cargo check` json format to the LSP diagnostic format.
3-
use std::{collections::HashMap, path::Path};
3+
use std::{
4+
collections::HashMap,
5+
path::{Path, PathBuf},
6+
};
47

58
use flycheck::{DiagnosticLevel, DiagnosticSpan};
69
use stdx::format_to;
@@ -42,7 +45,7 @@ fn is_dummy_macro_file(file_name: &str) -> bool {
4245

4346
/// Converts a Rust span to a LSP location
4447
fn location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location {
45-
let file_name = workspace_root.join(&span.file_name);
48+
let file_name = resolve_path(workspace_root, &span.file_name);
4649
let uri = url_from_abs_path(&file_name);
4750

4851
// FIXME: this doesn't handle UTF16 offsets correctly
@@ -61,7 +64,7 @@ fn location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location
6164
fn primary_location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location {
6265
let span_stack = std::iter::successors(Some(span), |span| Some(&span.expansion.as_ref()?.span));
6366
for span in span_stack.clone() {
64-
let abs_path = workspace_root.join(&span.file_name);
67+
let abs_path = resolve_path(workspace_root, &span.file_name);
6568
if !is_dummy_macro_file(&span.file_name) && abs_path.starts_with(workspace_root) {
6669
return location(workspace_root, span);
6770
}
@@ -84,6 +87,30 @@ fn diagnostic_related_information(
8487
Some(lsp_types::DiagnosticRelatedInformation { location, message })
8588
}
8689

90+
/// Resolves paths mimicking VSCode's behavior when `file_name` starts
91+
/// with the root directory component, which does not discard the base
92+
/// path. If this relative path exists, use it, otherwise fall back
93+
/// to the existing Rust behavior of path joining.
94+
fn resolve_path(workspace_root: &Path, file_name: &str) -> PathBuf {
95+
let file_name = Path::new(file_name);
96+
97+
// Test path with VSCode's path join behavior.
98+
let vscode_path = {
99+
let mut result = PathBuf::from(workspace_root);
100+
result.extend(file_name.components().skip_while(|component| match component {
101+
std::path::Component::RootDir => true,
102+
_ => false,
103+
}));
104+
result
105+
};
106+
if vscode_path.exists() {
107+
return vscode_path;
108+
}
109+
110+
// Default to Rust's path join behavior.
111+
workspace_root.join(file_name)
112+
}
113+
87114
struct SubDiagnostic {
88115
related: lsp_types::DiagnosticRelatedInformation,
89116
suggested_fix: Option<lsp_ext::CodeAction>,

0 commit comments

Comments
 (0)