From e8923713c51bc3484bd98085ad620713959bbc0d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 10 Jan 2019 20:13:08 +0300 Subject: add sysroot boilerplate --- crates/ra_lsp_server/src/main_loop/handlers.rs | 8 +- crates/ra_lsp_server/src/project_model.rs | 116 ++++++++++++++++++--- .../src/project_model/cargo_workspace.rs | 0 crates/ra_lsp_server/src/project_model/sysroot.rs | 0 crates/ra_lsp_server/src/server_world.rs | 24 ++--- crates/ra_lsp_server/tests/heavy_tests/main.rs | 41 +++++++- 6 files changed, 157 insertions(+), 32 deletions(-) create mode 100644 crates/ra_lsp_server/src/project_model/cargo_workspace.rs create mode 100644 crates/ra_lsp_server/src/project_model/sysroot.rs diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 069e7f932..0dda9548a 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -347,11 +347,11 @@ pub fn handle_runnables( .read() .file2path(ra_vfs::VfsFile(file_id.0.into())); let res = world.workspaces.iter().find_map(|ws| { - let tgt = ws.target_by_root(&path)?; + let tgt = ws.cargo.target_by_root(&path)?; let res = CargoTargetSpec { - package: tgt.package(ws).name(ws).to_string(), - target: tgt.name(ws).to_string(), - target_kind: tgt.kind(ws), + package: tgt.package(&ws.cargo).name(&ws.cargo).to_string(), + target: tgt.name(&ws.cargo).to_string(), + target_kind: tgt.kind(&ws.cargo), }; Some(res) }); diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs index 9f429c9a1..6fbaba7d9 100644 --- a/crates/ra_lsp_server/src/project_model.rs +++ b/crates/ra_lsp_server/src/project_model.rs @@ -1,4 +1,7 @@ -use std::path::{Path, PathBuf}; +use std::{ + path::{Path, PathBuf}, + process::Command, +}; use cargo_metadata::{metadata_run, CargoOpt}; use ra_syntax::SmolStr; @@ -9,6 +12,36 @@ use thread_worker::{WorkerHandle, Worker}; use crate::Result; +#[derive(Debug, Clone)] +pub struct ProjectWorkspace { + pub(crate) cargo: CargoWorkspace, + pub(crate) sysroot: Sysroot, +} + +impl ProjectWorkspace { + pub fn discover(path: &Path) -> Result { + let cargo_toml = find_cargo_toml(path)?; + let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml)?; + let sysroot = sysroot_info(&cargo_toml)?; + let res = ProjectWorkspace { cargo, sysroot }; + Ok(res) + } +} + +pub fn workspace_loader() -> (Worker>, WorkerHandle) { + thread_worker::spawn::, _>( + "workspace loader", + 1, + |input_receiver, output_sender| { + input_receiver + .into_iter() + .map(|path| ProjectWorkspace::discover(path.as_path())) + .try_for_each(|it| output_sender.send(it)) + .unwrap() + }, + ) +} + /// `CargoWorksapce` represents the logical structure of, well, a Cargo /// workspace. It pretty closely mirrors `cargo metadata` output. /// @@ -63,6 +96,11 @@ pub enum TargetKind { Other, } +#[derive(Debug, Clone)] +pub(crate) struct Sysroot { + crates: FxHashMap, +} + impl Package { pub fn name(self, ws: &CargoWorkspace) -> &str { ws.packages[self].name.as_str() @@ -160,6 +198,68 @@ impl CargoWorkspace { } } +fn sysroot_info(cargo_toml: &Path) -> Result { + let rustc_output = Command::new("rustc") + .current_dir(cargo_toml.parent().unwrap()) + .args(&["--print", "sysroot"]) + .output()?; + if !rustc_output.status.success() { + failure::bail!("failed to locate sysroot") + } + let stdout = String::from_utf8(rustc_output.stdout)?; + let sysroot_path = Path::new(stdout.trim()); + let src = sysroot_path.join("lib/rustlib/src/rust/src"); + + let crates: &[(&str, &[&str])] = &[ + ( + "std", + &[ + "alloc_jemalloc", + "alloc_system", + "panic_abort", + "rand", + "compiler_builtins", + "unwind", + "rustc_asan", + "rustc_lsan", + "rustc_msan", + "rustc_tsan", + "build_helper", + ], + ), + ("core", &[]), + ("alloc", &[]), + ("collections", &[]), + ("libc", &[]), + ("panic_unwind", &[]), + ("proc_macro", &[]), + ("rustc_unicode", &[]), + ("std_unicode", &[]), + ("test", &[]), + // Feature gated + ("alloc_jemalloc", &[]), + ("alloc_system", &[]), + ("compiler_builtins", &[]), + ("getopts", &[]), + ("panic_unwind", &[]), + ("panic_abort", &[]), + ("rand", &[]), + ("term", &[]), + ("unwind", &[]), + // Dependencies + ("build_helper", &[]), + ("rustc_asan", &[]), + ("rustc_lsan", &[]), + ("rustc_msan", &[]), + ("rustc_tsan", &[]), + ("syntax", &[]), + ]; + + Ok(Sysroot { + crates: FxHashMap::default(), + }) +} + fn find_cargo_toml(path: &Path) -> Result { if path.ends_with("Cargo.toml") { return Ok(path.to_path_buf()); @@ -190,17 +290,3 @@ impl TargetKind { TargetKind::Other } } - -pub fn workspace_loader() -> (Worker>, WorkerHandle) { - thread_worker::spawn::, _>( - "workspace loader", - 1, - |input_receiver, output_sender| { - input_receiver - .into_iter() - .map(|path| CargoWorkspace::from_cargo_metadata(path.as_path())) - .try_for_each(|it| output_sender.send(it)) - .unwrap() - }, - ) -} diff --git a/crates/ra_lsp_server/src/project_model/cargo_workspace.rs b/crates/ra_lsp_server/src/project_model/cargo_workspace.rs new file mode 100644 index 000000000..e69de29bb diff --git a/crates/ra_lsp_server/src/project_model/sysroot.rs b/crates/ra_lsp_server/src/project_model/sysroot.rs new file mode 100644 index 000000000..e69de29bb diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index 76c76766d..2debbe557 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs @@ -15,7 +15,7 @@ use parking_lot::RwLock; use failure::format_err; use crate::{ - project_model::{CargoWorkspace, TargetKind}, + project_model::{ProjectWorkspace, TargetKind}, Result, }; @@ -23,26 +23,26 @@ use crate::{ pub struct ServerWorldState { pub roots_to_scan: usize, pub root: PathBuf, - pub workspaces: Arc>, + pub workspaces: Arc>, pub analysis_host: AnalysisHost, pub vfs: Arc>, } pub struct ServerWorld { - pub workspaces: Arc>, + pub workspaces: Arc>, pub analysis: Analysis, pub vfs: Arc>, } impl ServerWorldState { - pub fn new(root: PathBuf, workspaces: Vec) -> ServerWorldState { + pub fn new(root: PathBuf, workspaces: Vec) -> ServerWorldState { let mut change = AnalysisChange::new(); let mut roots = Vec::new(); roots.push(root.clone()); for ws in workspaces.iter() { - for pkg in ws.packages() { - roots.push(pkg.root(&ws).to_path_buf()); + for pkg in ws.cargo.packages() { + roots.push(pkg.root(&ws.cargo).to_path_buf()); } } let roots_to_scan = roots.len(); @@ -56,13 +56,13 @@ impl ServerWorldState { let mut pkg_to_lib_crate = FxHashMap::default(); let mut pkg_crates = FxHashMap::default(); for ws in workspaces.iter() { - for pkg in ws.packages() { - for tgt in pkg.targets(ws) { - let root = tgt.root(ws); + for pkg in ws.cargo.packages() { + for tgt in pkg.targets(&ws.cargo) { + let root = tgt.root(&ws.cargo); if let Some(file_id) = vfs.load(root) { let file_id = FileId(file_id.0.into()); let crate_id = crate_graph.add_crate_root(file_id); - if tgt.kind(ws) == TargetKind::Lib { + if tgt.kind(&ws.cargo) == TargetKind::Lib { pkg_to_lib_crate.insert(pkg, crate_id); } pkg_crates @@ -72,8 +72,8 @@ impl ServerWorldState { } } } - for pkg in ws.packages() { - for dep in pkg.dependencies(ws) { + for pkg in ws.cargo.packages() { + for dep in pkg.dependencies(&ws.cargo) { if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { for &from in pkg_crates.get(&pkg).into_iter().flatten() { crate_graph.add_dep(from, dep.name.clone(), to); diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs index 9eaf46ac8..927664ffb 100644 --- a/crates/ra_lsp_server/tests/heavy_tests/main.rs +++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs @@ -4,7 +4,7 @@ use languageserver_types::{ CodeActionContext, DocumentFormattingParams, FormattingOptions, Position, Range, }; use ra_lsp_server::req::{ - CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams, + CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams, CompletionParams, Completion, }; use serde_json::json; @@ -12,6 +12,45 @@ use crate::support::project; const LOG: &'static str = ""; +#[test] +fn completes_items_from_standard_library() { + let server = project( + r#" +//- Cargo.toml +[package] +name = "foo" +version = "0.0.0" + +//- src/lib.rs +use std::collections::; +"#, + ); + server.wait_for_feedback("workspace loaded"); + server.request::( + CompletionParams { + text_document: server.doc_id("src/lib.rs"), + context: None, + position: Position::new(0, 22), + }, + json!([ + { + "filterText": "self", + "insertText": "self", + "insertTextFormat": 1, + "kind": 14, + "label": "self" + }, + { + "filterText": "super", + "insertText": "super", + "insertTextFormat": 1, + "kind": 14, + "label": "super" + } + ]), + ); +} + #[test] fn test_runnables_no_project() { let server = project( -- cgit v1.2.3