internal: a bit more of cwd safety for flycheck
This commit is contained in:
@@ -28,7 +28,9 @@ pub(crate) fn load_workspace_at(
|
||||
progress: &dyn Fn(String),
|
||||
) -> Result<(AnalysisHost, vfs::Vfs, Option<ProcMacroClient>)> {
|
||||
let root = AbsPathBuf::assert(std::env::current_dir()?.join(root));
|
||||
eprintln!("root = {:?}", root);
|
||||
let root = ProjectManifest::discover_single(&root)?;
|
||||
eprintln!("root = {:?}", root);
|
||||
let workspace = ProjectWorkspace::load(root, cargo_config, progress)?;
|
||||
|
||||
load_workspace(workspace, load_config, progress)
|
||||
@@ -48,7 +50,7 @@ fn load_workspace(
|
||||
};
|
||||
|
||||
let proc_macro_client = if config.with_proc_macro {
|
||||
let path = std::env::current_exe()?;
|
||||
let path = AbsPathBuf::assert(std::env::current_exe()?);
|
||||
Some(ProcMacroClient::extern_process(path, &["proc-macro"]).unwrap())
|
||||
} else {
|
||||
None
|
||||
@@ -142,7 +144,7 @@ mod tests {
|
||||
use hir::Crate;
|
||||
|
||||
#[test]
|
||||
fn test_loading_rust_analyzer() -> Result<()> {
|
||||
fn test_loading_rust_analyzer() {
|
||||
let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap();
|
||||
let cargo_config = Default::default();
|
||||
let load_cargo_config = LoadCargoConfig {
|
||||
@@ -152,12 +154,10 @@ mod tests {
|
||||
prefill_caches: false,
|
||||
};
|
||||
let (host, _vfs, _proc_macro) =
|
||||
load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {})?;
|
||||
load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {}).unwrap();
|
||||
|
||||
let n_crates = Crate::all(host.raw_database()).len();
|
||||
// RA has quite a few crates, but the exact count doesn't matter
|
||||
assert!(n_crates > 20);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,12 +597,14 @@ impl Config {
|
||||
pub fn lru_capacity(&self) -> Option<usize> {
|
||||
self.data.lruCapacity
|
||||
}
|
||||
pub fn proc_macro_srv(&self) -> Option<(PathBuf, Vec<OsString>)> {
|
||||
pub fn proc_macro_srv(&self) -> Option<(AbsPathBuf, Vec<OsString>)> {
|
||||
if !self.data.procMacro_enable {
|
||||
return None;
|
||||
}
|
||||
|
||||
let path = self.data.procMacro_server.clone().or_else(|| std::env::current_exe().ok())?;
|
||||
let path = match &self.data.procMacro_server {
|
||||
Some(it) => self.root_path.join(it),
|
||||
None => AbsPathBuf::assert(std::env::current_exe().ok()?),
|
||||
};
|
||||
Some((path, vec!["proc-macro".into()]))
|
||||
}
|
||||
pub fn expand_proc_attr_macros(&self) -> bool {
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
//! This module provides the functionality needed to convert diagnostics from
|
||||
//! `cargo check` json format to the LSP diagnostic format.
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use flycheck::{DiagnosticLevel, DiagnosticSpan};
|
||||
use stdx::format_to;
|
||||
use vfs::{AbsPath, AbsPathBuf};
|
||||
|
||||
use crate::{lsp_ext, to_proto::url_from_abs_path};
|
||||
|
||||
@@ -46,7 +44,7 @@ fn is_dummy_macro_file(file_name: &str) -> bool {
|
||||
/// Converts a Rust span to a LSP location
|
||||
fn location(
|
||||
config: &DiagnosticsMapConfig,
|
||||
workspace_root: &Path,
|
||||
workspace_root: &AbsPath,
|
||||
span: &DiagnosticSpan,
|
||||
) -> lsp_types::Location {
|
||||
let file_name = resolve_path(config, workspace_root, &span.file_name);
|
||||
@@ -67,7 +65,7 @@ fn location(
|
||||
/// workspace into account and tries to avoid those, in case macros are involved.
|
||||
fn primary_location(
|
||||
config: &DiagnosticsMapConfig,
|
||||
workspace_root: &Path,
|
||||
workspace_root: &AbsPath,
|
||||
span: &DiagnosticSpan,
|
||||
) -> lsp_types::Location {
|
||||
let span_stack = std::iter::successors(Some(span), |span| Some(&span.expansion.as_ref()?.span));
|
||||
@@ -88,7 +86,7 @@ fn primary_location(
|
||||
/// If the span is unlabelled this will return `None`.
|
||||
fn diagnostic_related_information(
|
||||
config: &DiagnosticsMapConfig,
|
||||
workspace_root: &Path,
|
||||
workspace_root: &AbsPath,
|
||||
span: &DiagnosticSpan,
|
||||
) -> Option<lsp_types::DiagnosticRelatedInformation> {
|
||||
let message = span.label.clone()?;
|
||||
@@ -98,7 +96,11 @@ fn diagnostic_related_information(
|
||||
|
||||
/// Resolves paths applying any matching path prefix remappings, and then
|
||||
/// joining the path to the workspace root.
|
||||
fn resolve_path(config: &DiagnosticsMapConfig, workspace_root: &Path, file_name: &str) -> PathBuf {
|
||||
fn resolve_path(
|
||||
config: &DiagnosticsMapConfig,
|
||||
workspace_root: &AbsPath,
|
||||
file_name: &str,
|
||||
) -> AbsPathBuf {
|
||||
match config
|
||||
.remap_prefix
|
||||
.iter()
|
||||
@@ -121,7 +123,7 @@ enum MappedRustChildDiagnostic {
|
||||
|
||||
fn map_rust_child_diagnostic(
|
||||
config: &DiagnosticsMapConfig,
|
||||
workspace_root: &Path,
|
||||
workspace_root: &AbsPath,
|
||||
rd: &flycheck::Diagnostic,
|
||||
) -> MappedRustChildDiagnostic {
|
||||
let spans: Vec<&DiagnosticSpan> = rd.spans.iter().filter(|s| s.is_primary).collect();
|
||||
@@ -191,7 +193,7 @@ pub(crate) struct MappedRustDiagnostic {
|
||||
pub(crate) fn map_rust_diagnostic_to_lsp(
|
||||
config: &DiagnosticsMapConfig,
|
||||
rd: &flycheck::Diagnostic,
|
||||
workspace_root: &Path,
|
||||
workspace_root: &AbsPath,
|
||||
) -> Vec<MappedRustDiagnostic> {
|
||||
let primary_spans: Vec<&DiagnosticSpan> = rd.spans.iter().filter(|s| s.is_primary).collect();
|
||||
if primary_spans.is_empty() {
|
||||
@@ -426,6 +428,8 @@ fn clippy_code_description(code: Option<&str>) -> Option<lsp_types::CodeDescript
|
||||
#[cfg(test)]
|
||||
#[cfg(not(windows))]
|
||||
mod tests {
|
||||
use std::{convert::TryInto, path::Path};
|
||||
|
||||
use super::*;
|
||||
|
||||
use expect_test::{expect_file, ExpectFile};
|
||||
@@ -436,7 +440,7 @@ mod tests {
|
||||
|
||||
fn check_with_config(config: DiagnosticsMapConfig, diagnostics_json: &str, expect: ExpectFile) {
|
||||
let diagnostic: flycheck::Diagnostic = serde_json::from_str(diagnostics_json).unwrap();
|
||||
let workspace_root = Path::new("/test/");
|
||||
let workspace_root: &AbsPath = Path::new("/test/").try_into().unwrap();
|
||||
let actual = map_rust_diagnostic_to_lsp(&config, &diagnostic, workspace_root);
|
||||
expect.assert_debug_eq(&actual)
|
||||
}
|
||||
|
||||
@@ -73,8 +73,9 @@ impl GlobalState {
|
||||
fn is_interesting(path: &AbsPath, change_kind: ChangeKind) -> bool {
|
||||
const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
|
||||
const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"];
|
||||
let file_name = path.file_name().unwrap_or_default();
|
||||
|
||||
if path.ends_with("Cargo.toml") || path.ends_with("Cargo.lock") {
|
||||
if file_name == "Cargo.toml" || file_name == "Cargo.lock" {
|
||||
return true;
|
||||
}
|
||||
if change_kind == ChangeKind::Modify {
|
||||
@@ -83,22 +84,22 @@ impl GlobalState {
|
||||
if path.extension().unwrap_or_default() != "rs" {
|
||||
return false;
|
||||
}
|
||||
if IMPLICIT_TARGET_FILES.iter().any(|it| path.ends_with(it)) {
|
||||
if IMPLICIT_TARGET_FILES.iter().any(|it| path.as_ref().ends_with(it)) {
|
||||
return true;
|
||||
}
|
||||
let parent = match path.parent() {
|
||||
Some(it) => it,
|
||||
None => return false,
|
||||
};
|
||||
if IMPLICIT_TARGET_DIRS.iter().any(|it| parent.ends_with(it)) {
|
||||
if IMPLICIT_TARGET_DIRS.iter().any(|it| parent.as_ref().ends_with(it)) {
|
||||
return true;
|
||||
}
|
||||
if path.ends_with("main.rs") {
|
||||
if file_name == "main.rs" {
|
||||
let grand_parent = match parent.parent() {
|
||||
Some(it) => it,
|
||||
None => return false,
|
||||
};
|
||||
if IMPLICIT_TARGET_DIRS.iter().any(|it| grand_parent.ends_with(it)) {
|
||||
if IMPLICIT_TARGET_DIRS.iter().any(|it| grand_parent.as_ref().ends_with(it)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Conversion of rust-analyzer specific types to lsp_types equivalents.
|
||||
use std::{
|
||||
iter::once,
|
||||
path::{self, Path},
|
||||
path,
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
};
|
||||
|
||||
@@ -14,6 +14,7 @@ use ide::{
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use serde_json::to_value;
|
||||
use vfs::AbsPath;
|
||||
|
||||
use crate::{
|
||||
cargo_target_spec::CargoTargetSpec,
|
||||
@@ -622,10 +623,9 @@ pub(crate) fn url(snap: &GlobalStateSnapshot, file_id: FileId) -> lsp_types::Url
|
||||
/// This will only happen when processing windows paths.
|
||||
///
|
||||
/// When processing non-windows path, this is essentially the same as `Url::from_file_path`.
|
||||
pub(crate) fn url_from_abs_path(path: &Path) -> lsp_types::Url {
|
||||
assert!(path.is_absolute());
|
||||
pub(crate) fn url_from_abs_path(path: &AbsPath) -> lsp_types::Url {
|
||||
let url = lsp_types::Url::from_file_path(path).unwrap();
|
||||
match path.components().next() {
|
||||
match path.as_ref().components().next() {
|
||||
Some(path::Component::Prefix(prefix))
|
||||
if matches!(prefix.kind(), path::Prefix::Disk(_) | path::Prefix::VerbatimDisk(_)) =>
|
||||
{
|
||||
@@ -1328,15 +1328,13 @@ fn main() {
|
||||
// `Url` is not able to parse windows paths on unix machines.
|
||||
#[test]
|
||||
#[cfg(target_os = "windows")]
|
||||
fn test_lowercase_drive_letter_with_drive() {
|
||||
let url = url_from_abs_path(Path::new("C:\\Test"));
|
||||
assert_eq!(url.to_string(), "file:///c:/Test");
|
||||
}
|
||||
fn test_lowercase_drive_letter() {
|
||||
use std::{convert::TryInto, path::Path};
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "windows")]
|
||||
fn test_drive_without_colon_passthrough() {
|
||||
let url = url_from_abs_path(Path::new(r#"\\localhost\C$\my_dir"#));
|
||||
let url = url_from_abs_path(Path::new("C:\\Test").try_into().unwrap());
|
||||
assert_eq!(url.to_string(), "file:///c:/Test");
|
||||
|
||||
let url = url_from_abs_path(Path::new(r#"\\localhost\C$\my_dir"#).try_into().unwrap());
|
||||
assert_eq!(url.to_string(), "file://localhost/C$/my_dir");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user