Skip to content

Commit 246c66a

Browse files
bors[bot]matklad
andauthored
Merge #4867
4867: Cleanup URL handling r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
2 parents d64b583 + 50bbf72 commit 246c66a

File tree

6 files changed

+134
-160
lines changed

6 files changed

+134
-160
lines changed

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

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

95
use lsp_types::{
106
Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, DiagnosticTag, Location,
@@ -13,7 +9,7 @@ use lsp_types::{
139
use ra_flycheck::{Applicability, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion};
1410
use stdx::format_to;
1511

16-
use crate::{lsp_ext, Result};
12+
use crate::{lsp_ext, to_proto::url_from_abs_path};
1713

1814
/// Converts a Rust level string to a LSP severity
1915
fn map_level_to_severity(val: DiagnosticLevel) -> Option<DiagnosticSeverity> {
@@ -65,7 +61,7 @@ fn map_span_to_location(span: &DiagnosticSpan, workspace_root: &Path) -> Locatio
6561
fn map_span_to_location_naive(span: &DiagnosticSpan, workspace_root: &Path) -> Location {
6662
let mut file_name = workspace_root.to_path_buf();
6763
file_name.push(&span.file_name);
68-
let uri = url_from_path_with_drive_lowercasing(file_name).unwrap();
64+
let uri = url_from_abs_path(&file_name);
6965

7066
// FIXME: this doesn't handle UTF16 offsets correctly
7167
let range = Range::new(
@@ -274,70 +270,16 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
274270
.collect()
275271
}
276272

277-
/// Returns a `Url` object from a given path, will lowercase drive letters if present.
278-
/// This will only happen when processing windows paths.
279-
///
280-
/// When processing non-windows path, this is essentially the same as `Url::from_file_path`.
281-
pub fn url_from_path_with_drive_lowercasing(path: impl AsRef<Path>) -> Result<Url> {
282-
let component_has_windows_drive = path.as_ref().components().any(|comp| {
283-
if let Component::Prefix(c) = comp {
284-
return matches!(c.kind(), Prefix::Disk(_) | Prefix::VerbatimDisk(_));
285-
}
286-
false
287-
});
288-
289-
// VSCode expects drive letters to be lowercased, where rust will uppercase the drive letters.
290-
let res = if component_has_windows_drive {
291-
let url_original = Url::from_file_path(&path)
292-
.map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?;
293-
294-
let drive_partition: Vec<&str> = url_original.as_str().rsplitn(2, ':').collect();
295-
296-
// There is a drive partition, but we never found a colon.
297-
// This should not happen, but in this case we just pass it through.
298-
if drive_partition.len() == 1 {
299-
return Ok(url_original);
300-
}
301-
302-
let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0];
303-
let url = Url::from_str(&joined).expect("This came from a valid `Url`");
304-
305-
url
306-
} else {
307-
Url::from_file_path(&path)
308-
.map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?
309-
};
310-
Ok(res)
311-
}
312-
313273
#[cfg(test)]
274+
#[cfg(not(windows))]
314275
mod tests {
315276
use super::*;
316277

317-
// `Url` is not able to parse windows paths on unix machines.
318-
#[test]
319-
#[cfg(target_os = "windows")]
320-
fn test_lowercase_drive_letter_with_drive() {
321-
let url = url_from_path_with_drive_lowercasing("C:\\Test").unwrap();
322-
323-
assert_eq!(url.to_string(), "file:///c:/Test");
324-
}
325-
326-
#[test]
327-
#[cfg(target_os = "windows")]
328-
fn test_drive_without_colon_passthrough() {
329-
let url = url_from_path_with_drive_lowercasing(r#"\\localhost\C$\my_dir"#).unwrap();
330-
331-
assert_eq!(url.to_string(), "file://localhost/C$/my_dir");
332-
}
333-
334-
#[cfg(not(windows))]
335278
fn parse_diagnostic(val: &str) -> ra_flycheck::Diagnostic {
336279
serde_json::from_str::<ra_flycheck::Diagnostic>(val).unwrap()
337280
}
338281

339282
#[test]
340-
#[cfg(not(windows))]
341283
fn snap_rustc_incompatible_type_for_trait() {
342284
let diag = parse_diagnostic(
343285
r##"{
@@ -391,7 +333,6 @@ mod tests {
391333
}
392334

393335
#[test]
394-
#[cfg(not(windows))]
395336
fn snap_rustc_unused_variable() {
396337
let diag = parse_diagnostic(
397338
r##"{
@@ -474,7 +415,6 @@ mod tests {
474415
}
475416

476417
#[test]
477-
#[cfg(not(windows))]
478418
fn snap_rustc_wrong_number_of_parameters() {
479419
let diag = parse_diagnostic(
480420
r##"{
@@ -599,7 +539,6 @@ mod tests {
599539
}
600540

601541
#[test]
602-
#[cfg(not(windows))]
603542
fn snap_clippy_pass_by_ref() {
604543
let diag = parse_diagnostic(
605544
r##"{
@@ -720,7 +659,6 @@ mod tests {
720659
}
721660

722661
#[test]
723-
#[cfg(not(windows))]
724662
fn snap_rustc_mismatched_type() {
725663
let diag = parse_diagnostic(
726664
r##"{
@@ -764,7 +702,6 @@ mod tests {
764702
}
765703

766704
#[test]
767-
#[cfg(not(windows))]
768705
fn snap_handles_macro_location() {
769706
let diag = parse_diagnostic(
770707
r##"{
@@ -1036,7 +973,6 @@ mod tests {
1036973
}
1037974

1038975
#[test]
1039-
#[cfg(not(windows))]
1040976
fn snap_macro_compiler_error() {
1041977
let diag = parse_diagnostic(
1042978
r##"{
@@ -1266,7 +1202,6 @@ mod tests {
12661202
}
12671203

12681204
#[test]
1269-
#[cfg(not(windows))]
12701205
fn snap_multi_line_fix() {
12711206
let diag = parse_diagnostic(
12721207
r##"{

crates/rust-analyzer/src/from_proto.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> Tex
1717
}
1818

1919
pub(crate) fn file_id(world: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result<FileId> {
20-
world.uri_to_file_id(url)
20+
world.url_to_file_id(url)
2121
}
2222

2323
pub(crate) fn file_position(

crates/rust-analyzer/src/global_state.rs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,9 @@ use stdx::format_to;
2222

2323
use crate::{
2424
config::Config,
25-
diagnostics::{
26-
to_proto::url_from_path_with_drive_lowercasing, CheckFixes, DiagnosticCollection,
27-
},
25+
diagnostics::{CheckFixes, DiagnosticCollection},
2826
main_loop::pending_requests::{CompletedRequest, LatestRequests},
27+
to_proto::url_from_abs_path,
2928
vfs_glob::{Glob, RustPackageFilterBuilder},
3029
LspError, Result,
3130
};
@@ -274,8 +273,8 @@ impl GlobalStateSnapshot {
274273
&self.analysis
275274
}
276275

277-
pub fn uri_to_file_id(&self, uri: &Url) -> Result<FileId> {
278-
let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?;
276+
pub fn url_to_file_id(&self, url: &Url) -> Result<FileId> {
277+
let path = url.to_file_path().map_err(|()| format!("invalid uri: {}", url))?;
279278
let file = self.vfs.read().path2file(&path).ok_or_else(|| {
280279
// Show warning as this file is outside current workspace
281280
// FIXME: just handle such files, and remove `LspError::UNKNOWN_FILE`.
@@ -287,11 +286,8 @@ impl GlobalStateSnapshot {
287286
Ok(FileId(file.0))
288287
}
289288

290-
pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> {
291-
let path = self.vfs.read().file2path(VfsFile(id.0));
292-
let url = url_from_path_with_drive_lowercasing(path)?;
293-
294-
Ok(url)
289+
pub fn file_id_to_url(&self, id: FileId) -> Url {
290+
file_id_to_url(&self.vfs.read(), id)
295291
}
296292

297293
pub fn file_id_to_path(&self, id: FileId) -> PathBuf {
@@ -302,12 +298,10 @@ impl GlobalStateSnapshot {
302298
self.vfs.read().file_line_endings(VfsFile(id.0))
303299
}
304300

305-
pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result<Url> {
301+
pub fn path_to_url(&self, root: SourceRootId, path: &RelativePathBuf) -> Url {
306302
let base = self.vfs.read().root2path(VfsRoot(root.0));
307303
let path = path.to_path(base);
308-
let url = Url::from_file_path(&path)
309-
.map_err(|_| format!("can't convert path to url: {}", path.display()))?;
310-
Ok(url)
304+
url_from_abs_path(&path)
311305
}
312306

313307
pub fn status(&self) -> String {
@@ -335,3 +329,8 @@ impl GlobalStateSnapshot {
335329
self.workspaces.iter().find_map(|ws| ws.workspace_root_for(&path))
336330
}
337331
}
332+
333+
pub(crate) fn file_id_to_url(vfs: &Vfs, id: FileId) -> Url {
334+
let path = vfs.file2path(VfsFile(id.0));
335+
url_from_abs_path(&path)
336+
}

crates/rust-analyzer/src/main_loop.rs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,17 @@ use ra_flycheck::{CheckTask, Status};
2727
use ra_ide::{Canceled, FileId, LibraryData, LineIndex, SourceRootId};
2828
use ra_prof::profile;
2929
use ra_project_model::{PackageRoot, ProjectWorkspace};
30-
use ra_vfs::{VfsFile, VfsTask, Watch};
30+
use ra_vfs::{VfsTask, Watch};
3131
use relative_path::RelativePathBuf;
3232
use rustc_hash::FxHashSet;
3333
use serde::{de::DeserializeOwned, Serialize};
3434
use threadpool::ThreadPool;
3535

3636
use crate::{
3737
config::{Config, FilesWatcher, LinkedProject},
38-
diagnostics::{to_proto::url_from_path_with_drive_lowercasing, DiagnosticTask},
38+
diagnostics::DiagnosticTask,
3939
from_proto,
40-
global_state::{GlobalState, GlobalStateSnapshot},
40+
global_state::{file_id_to_url, GlobalState, GlobalStateSnapshot},
4141
lsp_ext,
4242
main_loop::{
4343
pending_requests::{PendingRequest, PendingRequests},
@@ -801,17 +801,9 @@ fn on_diagnostic_task(task: DiagnosticTask, msg_sender: &Sender<Message>, state:
801801
let subscriptions = state.diagnostics.handle_task(task);
802802

803803
for file_id in subscriptions {
804-
let path = state.vfs.read().file2path(VfsFile(file_id.0));
805-
let uri = match url_from_path_with_drive_lowercasing(&path) {
806-
Ok(uri) => uri,
807-
Err(err) => {
808-
log::error!("Couldn't convert path to url ({}): {}", err, path.display());
809-
continue;
810-
}
811-
};
812-
804+
let url = file_id_to_url(&state.vfs.read(), file_id);
813805
let diagnostics = state.diagnostics.diagnostics_for(file_id).cloned().collect();
814-
let params = lsp_types::PublishDiagnosticsParams { uri, diagnostics, version: None };
806+
let params = lsp_types::PublishDiagnosticsParams { uri: url, diagnostics, version: None };
815807
let not = notification_new::<lsp_types::notification::PublishDiagnostics>(params);
816808
msg_sender.send(not.into()).unwrap();
817809
}

crates/rust-analyzer/src/main_loop/handlers.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ pub fn handle_document_symbol(
258258
let res = if snap.config.client_caps.hierarchical_symbols {
259259
document_symbols.into()
260260
} else {
261-
let url = to_proto::url(&snap, file_id)?;
261+
let url = to_proto::url(&snap, file_id);
262262
let mut symbol_information = Vec::<SymbolInformation>::new();
263263
for symbol in document_symbols {
264264
flatten_document_symbol(&symbol, None, &url, &mut symbol_information);
@@ -1160,7 +1160,7 @@ fn show_impl_command_link(
11601160
) -> Option<lsp_ext::CommandLinkGroup> {
11611161
if snap.config.hover.implementations {
11621162
if let Some(nav_data) = snap.analysis().goto_implementation(*position).unwrap_or(None) {
1163-
let uri = to_proto::url(snap, position.file_id).ok()?;
1163+
let uri = to_proto::url(snap, position.file_id);
11641164
let line_index = snap.analysis().file_line_index(position.file_id).ok()?;
11651165
let position = to_proto::position(&line_index, position.offset);
11661166
let locations: Vec<_> = nav_data

0 commit comments

Comments
 (0)