aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--crates/paths/src/lib.rs26
-rw-r--r--crates/ra_project_model/Cargo.toml1
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs42
-rw-r--r--crates/ra_project_model/src/lib.rs51
-rw-r--r--crates/ra_project_model/src/sysroot.rs23
-rw-r--r--crates/rust-analyzer/src/bin/main.rs37
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs2
-rw-r--r--crates/rust-analyzer/src/config.rs22
-rw-r--r--crates/rust-analyzer/src/global_state.rs7
-rw-r--r--crates/rust-analyzer/tests/heavy_tests/support.rs8
11 files changed, 126 insertions, 94 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9ea1765cb..91a932549 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1174,6 +1174,7 @@ dependencies = [
1174 "anyhow", 1174 "anyhow",
1175 "cargo_metadata", 1175 "cargo_metadata",
1176 "log", 1176 "log",
1177 "paths",
1177 "ra_arena", 1178 "ra_arena",
1178 "ra_cfg", 1179 "ra_cfg",
1179 "ra_db", 1180 "ra_db",
diff --git a/crates/paths/src/lib.rs b/crates/paths/src/lib.rs
index 45b19c45a..1b259682d 100644
--- a/crates/paths/src/lib.rs
+++ b/crates/paths/src/lib.rs
@@ -28,6 +28,12 @@ impl AsRef<Path> for AbsPathBuf {
28 } 28 }
29} 29}
30 30
31impl AsRef<AbsPath> for AbsPathBuf {
32 fn as_ref(&self) -> &AbsPath {
33 self.as_path()
34 }
35}
36
31impl TryFrom<PathBuf> for AbsPathBuf { 37impl TryFrom<PathBuf> for AbsPathBuf {
32 type Error = PathBuf; 38 type Error = PathBuf;
33 fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> { 39 fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> {
@@ -45,9 +51,19 @@ impl TryFrom<&str> for AbsPathBuf {
45 } 51 }
46} 52}
47 53
54impl PartialEq<AbsPath> for AbsPathBuf {
55 fn eq(&self, other: &AbsPath) -> bool {
56 self.as_path() == other
57 }
58}
59
48impl AbsPathBuf { 60impl AbsPathBuf {
61 pub fn assert(path: PathBuf) -> AbsPathBuf {
62 AbsPathBuf::try_from(path)
63 .unwrap_or_else(|path| panic!("expected absolute path, got {}", path.display()))
64 }
49 pub fn as_path(&self) -> &AbsPath { 65 pub fn as_path(&self) -> &AbsPath {
50 AbsPath::new_unchecked(self.0.as_path()) 66 AbsPath::assert(self.0.as_path())
51 } 67 }
52 pub fn pop(&mut self) -> bool { 68 pub fn pop(&mut self) -> bool {
53 self.0.pop() 69 self.0.pop()
@@ -77,15 +93,19 @@ impl<'a> TryFrom<&'a Path> for &'a AbsPath {
77 if !path.is_absolute() { 93 if !path.is_absolute() {
78 return Err(path); 94 return Err(path);
79 } 95 }
80 Ok(AbsPath::new_unchecked(path)) 96 Ok(AbsPath::assert(path))
81 } 97 }
82} 98}
83 99
84impl AbsPath { 100impl AbsPath {
85 fn new_unchecked(path: &Path) -> &AbsPath { 101 pub fn assert(path: &Path) -> &AbsPath {
102 assert!(path.is_absolute());
86 unsafe { &*(path as *const Path as *const AbsPath) } 103 unsafe { &*(path as *const Path as *const AbsPath) }
87 } 104 }
88 105
106 pub fn parent(&self) -> Option<&AbsPath> {
107 self.0.parent().map(AbsPath::assert)
108 }
89 pub fn join(&self, path: impl AsRef<Path>) -> AbsPathBuf { 109 pub fn join(&self, path: impl AsRef<Path>) -> AbsPathBuf {
90 self.as_ref().join(path).try_into().unwrap() 110 self.as_ref().join(path).try_into().unwrap()
91 } 111 }
diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml
index e4a60f4c0..818947014 100644
--- a/crates/ra_project_model/Cargo.toml
+++ b/crates/ra_project_model/Cargo.toml
@@ -18,6 +18,7 @@ ra_cfg = { path = "../ra_cfg" }
18ra_db = { path = "../ra_db" } 18ra_db = { path = "../ra_db" }
19ra_toolchain = { path = "../ra_toolchain" } 19ra_toolchain = { path = "../ra_toolchain" }
20ra_proc_macro = { path = "../ra_proc_macro" } 20ra_proc_macro = { path = "../ra_proc_macro" }
21paths = { path = "../paths" }
21 22
22serde = { version = "1.0.106", features = ["derive"] } 23serde = { version = "1.0.106", features = ["derive"] }
23serde_json = "1.0.48" 24serde_json = "1.0.48"
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs
index 4b7444039..8ce63ab3c 100644
--- a/crates/ra_project_model/src/cargo_workspace.rs
+++ b/crates/ra_project_model/src/cargo_workspace.rs
@@ -1,14 +1,10 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use std::{ 3use std::{ffi::OsStr, ops, path::Path, process::Command};
4 ffi::OsStr,
5 ops,
6 path::{Path, PathBuf},
7 process::Command,
8};
9 4
10use anyhow::{Context, Result}; 5use anyhow::{Context, Result};
11use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; 6use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId};
7use paths::{AbsPath, AbsPathBuf};
12use ra_arena::{Arena, Idx}; 8use ra_arena::{Arena, Idx};
13use ra_db::Edition; 9use ra_db::Edition;
14use rustc_hash::FxHashMap; 10use rustc_hash::FxHashMap;
@@ -20,11 +16,14 @@ use rustc_hash::FxHashMap;
20/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, 16/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
21/// while this knows about `Packages` & `Targets`: purely cargo-related 17/// while this knows about `Packages` & `Targets`: purely cargo-related
22/// concepts. 18/// concepts.
19///
20/// We use absolute paths here, `cargo metadata` guarantees to always produce
21/// abs paths.
23#[derive(Debug, Clone)] 22#[derive(Debug, Clone)]
24pub struct CargoWorkspace { 23pub struct CargoWorkspace {
25 packages: Arena<PackageData>, 24 packages: Arena<PackageData>,
26 targets: Arena<TargetData>, 25 targets: Arena<TargetData>,
27 workspace_root: PathBuf, 26 workspace_root: AbsPathBuf,
28} 27}
29 28
30impl ops::Index<Package> for CargoWorkspace { 29impl ops::Index<Package> for CargoWorkspace {
@@ -80,15 +79,15 @@ pub type Target = Idx<TargetData>;
80pub struct PackageData { 79pub struct PackageData {
81 pub version: String, 80 pub version: String,
82 pub name: String, 81 pub name: String,
83 pub manifest: PathBuf, 82 pub manifest: AbsPathBuf,
84 pub targets: Vec<Target>, 83 pub targets: Vec<Target>,
85 pub is_member: bool, 84 pub is_member: bool,
86 pub dependencies: Vec<PackageDependency>, 85 pub dependencies: Vec<PackageDependency>,
87 pub edition: Edition, 86 pub edition: Edition,
88 pub features: Vec<String>, 87 pub features: Vec<String>,
89 pub cfgs: Vec<String>, 88 pub cfgs: Vec<String>,
90 pub out_dir: Option<PathBuf>, 89 pub out_dir: Option<AbsPathBuf>,
91 pub proc_macro_dylib_path: Option<PathBuf>, 90 pub proc_macro_dylib_path: Option<AbsPathBuf>,
92} 91}
93 92
94#[derive(Debug, Clone)] 93#[derive(Debug, Clone)]
@@ -101,7 +100,7 @@ pub struct PackageDependency {
101pub struct TargetData { 100pub struct TargetData {
102 pub package: Package, 101 pub package: Package,
103 pub name: String, 102 pub name: String,
104 pub root: PathBuf, 103 pub root: AbsPathBuf,
105 pub kind: TargetKind, 104 pub kind: TargetKind,
106 pub is_proc_macro: bool, 105 pub is_proc_macro: bool,
107} 106}
@@ -135,7 +134,7 @@ impl TargetKind {
135} 134}
136 135
137impl PackageData { 136impl PackageData {
138 pub fn root(&self) -> &Path { 137 pub fn root(&self) -> &AbsPath {
139 self.manifest.parent().unwrap() 138 self.manifest.parent().unwrap()
140 } 139 }
141} 140}
@@ -193,7 +192,7 @@ impl CargoWorkspace {
193 let pkg = packages.alloc(PackageData { 192 let pkg = packages.alloc(PackageData {
194 name, 193 name,
195 version: version.to_string(), 194 version: version.to_string(),
196 manifest: manifest_path, 195 manifest: AbsPathBuf::assert(manifest_path),
197 targets: Vec::new(), 196 targets: Vec::new(),
198 is_member, 197 is_member,
199 edition, 198 edition,
@@ -210,7 +209,7 @@ impl CargoWorkspace {
210 let tgt = targets.alloc(TargetData { 209 let tgt = targets.alloc(TargetData {
211 package: pkg, 210 package: pkg,
212 name: meta_tgt.name, 211 name: meta_tgt.name,
213 root: meta_tgt.src_path.clone(), 212 root: AbsPathBuf::assert(meta_tgt.src_path.clone()),
214 kind: TargetKind::new(meta_tgt.kind.as_slice()), 213 kind: TargetKind::new(meta_tgt.kind.as_slice()),
215 is_proc_macro, 214 is_proc_macro,
216 }); 215 });
@@ -246,16 +245,17 @@ impl CargoWorkspace {
246 packages[source].features.extend(node.features); 245 packages[source].features.extend(node.features);
247 } 246 }
248 247
249 Ok(CargoWorkspace { packages, targets, workspace_root: meta.workspace_root }) 248 let workspace_root = AbsPathBuf::assert(meta.workspace_root);
249 Ok(CargoWorkspace { packages, targets, workspace_root: workspace_root })
250 } 250 }
251 251
252 pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + ExactSizeIterator + 'a { 252 pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + ExactSizeIterator + 'a {
253 self.packages.iter().map(|(id, _pkg)| id) 253 self.packages.iter().map(|(id, _pkg)| id)
254 } 254 }
255 255
256 pub fn target_by_root(&self, root: &Path) -> Option<Target> { 256 pub fn target_by_root(&self, root: &AbsPath) -> Option<Target> {
257 self.packages() 257 self.packages()
258 .filter_map(|pkg| self[pkg].targets.iter().find(|&&it| self[it].root == root)) 258 .filter_map(|pkg| self[pkg].targets.iter().find(|&&it| &self[it].root == root))
259 .next() 259 .next()
260 .copied() 260 .copied()
261 } 261 }
@@ -279,8 +279,8 @@ impl CargoWorkspace {
279 279
280#[derive(Debug, Clone, Default)] 280#[derive(Debug, Clone, Default)]
281pub struct ExternResources { 281pub struct ExternResources {
282 out_dirs: FxHashMap<PackageId, PathBuf>, 282 out_dirs: FxHashMap<PackageId, AbsPathBuf>,
283 proc_dylib_paths: FxHashMap<PackageId, PathBuf>, 283 proc_dylib_paths: FxHashMap<PackageId, AbsPathBuf>,
284 cfgs: FxHashMap<PackageId, Vec<String>>, 284 cfgs: FxHashMap<PackageId, Vec<String>>,
285} 285}
286 286
@@ -308,6 +308,7 @@ pub fn load_extern_resources(
308 if let Ok(message) = message { 308 if let Ok(message) = message {
309 match message { 309 match message {
310 Message::BuildScriptExecuted(BuildScript { package_id, out_dir, cfgs, .. }) => { 310 Message::BuildScriptExecuted(BuildScript { package_id, out_dir, cfgs, .. }) => {
311 let out_dir = AbsPathBuf::assert(out_dir);
311 res.out_dirs.insert(package_id.clone(), out_dir); 312 res.out_dirs.insert(package_id.clone(), out_dir);
312 res.cfgs.insert(package_id, cfgs); 313 res.cfgs.insert(package_id, cfgs);
313 } 314 }
@@ -317,7 +318,8 @@ pub fn load_extern_resources(
317 // Skip rmeta file 318 // Skip rmeta file
318 if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name)) 319 if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name))
319 { 320 {
320 res.proc_dylib_paths.insert(package_id, filename.clone()); 321 let filename = AbsPathBuf::assert(filename.clone());
322 res.proc_dylib_paths.insert(package_id, filename);
321 } 323 }
322 } 324 }
323 } 325 }
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index fe3e81689..ac88532f0 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -7,11 +7,12 @@ mod sysroot;
7use std::{ 7use std::{
8 fs::{read_dir, File, ReadDir}, 8 fs::{read_dir, File, ReadDir},
9 io::{self, BufReader}, 9 io::{self, BufReader},
10 path::{Path, PathBuf}, 10 path::Path,
11 process::{Command, Output}, 11 process::{Command, Output},
12}; 12};
13 13
14use anyhow::{bail, Context, Result}; 14use anyhow::{bail, Context, Result};
15use paths::{AbsPath, AbsPathBuf};
15use ra_cfg::CfgOptions; 16use ra_cfg::CfgOptions;
16use ra_db::{CrateGraph, CrateName, Edition, Env, FileId}; 17use ra_db::{CrateGraph, CrateName, Edition, Env, FileId};
17use rustc_hash::{FxHashMap, FxHashSet}; 18use rustc_hash::{FxHashMap, FxHashSet};
@@ -29,7 +30,7 @@ pub enum ProjectWorkspace {
29 /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. 30 /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
30 Cargo { cargo: CargoWorkspace, sysroot: Sysroot }, 31 Cargo { cargo: CargoWorkspace, sysroot: Sysroot },
31 /// Project workspace was manually specified using a `rust-project.json` file. 32 /// Project workspace was manually specified using a `rust-project.json` file.
32 Json { project: JsonProject, project_location: PathBuf }, 33 Json { project: JsonProject, project_location: AbsPathBuf },
33} 34}
34 35
35/// `PackageRoot` describes a package root folder. 36/// `PackageRoot` describes a package root folder.
@@ -38,22 +39,22 @@ pub enum ProjectWorkspace {
38#[derive(Debug, Clone)] 39#[derive(Debug, Clone)]
39pub struct PackageRoot { 40pub struct PackageRoot {
40 /// Path to the root folder 41 /// Path to the root folder
41 path: PathBuf, 42 path: AbsPathBuf,
42 /// Is a member of the current workspace 43 /// Is a member of the current workspace
43 is_member: bool, 44 is_member: bool,
44 out_dir: Option<PathBuf>, 45 out_dir: Option<AbsPathBuf>,
45} 46}
46impl PackageRoot { 47impl PackageRoot {
47 pub fn new_member(path: PathBuf) -> PackageRoot { 48 pub fn new_member(path: AbsPathBuf) -> PackageRoot {
48 Self { path, is_member: true, out_dir: None } 49 Self { path, is_member: true, out_dir: None }
49 } 50 }
50 pub fn new_non_member(path: PathBuf) -> PackageRoot { 51 pub fn new_non_member(path: AbsPathBuf) -> PackageRoot {
51 Self { path, is_member: false, out_dir: None } 52 Self { path, is_member: false, out_dir: None }
52 } 53 }
53 pub fn path(&self) -> &Path { 54 pub fn path(&self) -> &AbsPath {
54 &self.path 55 &self.path
55 } 56 }
56 pub fn out_dir(&self) -> Option<&Path> { 57 pub fn out_dir(&self) -> Option<&AbsPath> {
57 self.out_dir.as_deref() 58 self.out_dir.as_deref()
58 } 59 }
59 pub fn is_member(&self) -> bool { 60 pub fn is_member(&self) -> bool {
@@ -63,12 +64,12 @@ impl PackageRoot {
63 64
64#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] 65#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
65pub enum ProjectManifest { 66pub enum ProjectManifest {
66 ProjectJson(PathBuf), 67 ProjectJson(AbsPathBuf),
67 CargoToml(PathBuf), 68 CargoToml(AbsPathBuf),
68} 69}
69 70
70impl ProjectManifest { 71impl ProjectManifest {
71 pub fn from_manifest_file(path: PathBuf) -> Result<ProjectManifest> { 72 pub fn from_manifest_file(path: AbsPathBuf) -> Result<ProjectManifest> {
72 if path.ends_with("rust-project.json") { 73 if path.ends_with("rust-project.json") {
73 return Ok(ProjectManifest::ProjectJson(path)); 74 return Ok(ProjectManifest::ProjectJson(path));
74 } 75 }
@@ -78,7 +79,7 @@ impl ProjectManifest {
78 bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display()) 79 bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display())
79 } 80 }
80 81
81 pub fn discover_single(path: &Path) -> Result<ProjectManifest> { 82 pub fn discover_single(path: &AbsPath) -> Result<ProjectManifest> {
82 let mut candidates = ProjectManifest::discover(path)?; 83 let mut candidates = ProjectManifest::discover(path)?;
83 let res = match candidates.pop() { 84 let res = match candidates.pop() {
84 None => bail!("no projects"), 85 None => bail!("no projects"),
@@ -91,23 +92,23 @@ impl ProjectManifest {
91 Ok(res) 92 Ok(res)
92 } 93 }
93 94
94 pub fn discover(path: &Path) -> io::Result<Vec<ProjectManifest>> { 95 pub fn discover(path: &AbsPath) -> io::Result<Vec<ProjectManifest>> {
95 if let Some(project_json) = find_in_parent_dirs(path, "rust-project.json") { 96 if let Some(project_json) = find_in_parent_dirs(path, "rust-project.json") {
96 return Ok(vec![ProjectManifest::ProjectJson(project_json)]); 97 return Ok(vec![ProjectManifest::ProjectJson(project_json)]);
97 } 98 }
98 return find_cargo_toml(path) 99 return find_cargo_toml(path)
99 .map(|paths| paths.into_iter().map(ProjectManifest::CargoToml).collect()); 100 .map(|paths| paths.into_iter().map(ProjectManifest::CargoToml).collect());
100 101
101 fn find_cargo_toml(path: &Path) -> io::Result<Vec<PathBuf>> { 102 fn find_cargo_toml(path: &AbsPath) -> io::Result<Vec<AbsPathBuf>> {
102 match find_in_parent_dirs(path, "Cargo.toml") { 103 match find_in_parent_dirs(path, "Cargo.toml") {
103 Some(it) => Ok(vec![it]), 104 Some(it) => Ok(vec![it]),
104 None => Ok(find_cargo_toml_in_child_dir(read_dir(path)?)), 105 None => Ok(find_cargo_toml_in_child_dir(read_dir(path)?)),
105 } 106 }
106 } 107 }
107 108
108 fn find_in_parent_dirs(path: &Path, target_file_name: &str) -> Option<PathBuf> { 109 fn find_in_parent_dirs(path: &AbsPath, target_file_name: &str) -> Option<AbsPathBuf> {
109 if path.ends_with(target_file_name) { 110 if path.ends_with(target_file_name) {
110 return Some(path.to_owned()); 111 return Some(path.to_path_buf());
111 } 112 }
112 113
113 let mut curr = Some(path); 114 let mut curr = Some(path);
@@ -123,17 +124,18 @@ impl ProjectManifest {
123 None 124 None
124 } 125 }
125 126
126 fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec<PathBuf> { 127 fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec<AbsPathBuf> {
127 // Only one level down to avoid cycles the easy way and stop a runaway scan with large projects 128 // Only one level down to avoid cycles the easy way and stop a runaway scan with large projects
128 entities 129 entities
129 .filter_map(Result::ok) 130 .filter_map(Result::ok)
130 .map(|it| it.path().join("Cargo.toml")) 131 .map(|it| it.path().join("Cargo.toml"))
131 .filter(|it| it.exists()) 132 .filter(|it| it.exists())
133 .map(AbsPathBuf::assert)
132 .collect() 134 .collect()
133 } 135 }
134 } 136 }
135 137
136 pub fn discover_all(paths: &[impl AsRef<Path>]) -> Vec<ProjectManifest> { 138 pub fn discover_all(paths: &[impl AsRef<AbsPath>]) -> Vec<ProjectManifest> {
137 let mut res = paths 139 let mut res = paths
138 .iter() 140 .iter()
139 .filter_map(|it| ProjectManifest::discover(it.as_ref()).ok()) 141 .filter_map(|it| ProjectManifest::discover(it.as_ref()).ok())
@@ -158,15 +160,12 @@ impl ProjectWorkspace {
158 format!("Failed to open json file {}", project_json.display()) 160 format!("Failed to open json file {}", project_json.display())
159 })?; 161 })?;
160 let reader = BufReader::new(file); 162 let reader = BufReader::new(file);
161 let project_location = match project_json.parent() { 163 let project_location = project_json.parent().unwrap().to_path_buf();
162 Some(parent) => PathBuf::from(parent),
163 None => PathBuf::new(),
164 };
165 ProjectWorkspace::Json { 164 ProjectWorkspace::Json {
166 project: from_reader(reader).with_context(|| { 165 project: from_reader(reader).with_context(|| {
167 format!("Failed to deserialize json file {}", project_json.display()) 166 format!("Failed to deserialize json file {}", project_json.display())
168 })?, 167 })?,
169 project_location: project_location, 168 project_location,
170 } 169 }
171 } 170 }
172 ProjectManifest::CargoToml(cargo_toml) => { 171 ProjectManifest::CargoToml(cargo_toml) => {
@@ -218,13 +217,13 @@ impl ProjectWorkspace {
218 } 217 }
219 } 218 }
220 219
221 pub fn proc_macro_dylib_paths(&self) -> Vec<PathBuf> { 220 pub fn proc_macro_dylib_paths(&self) -> Vec<AbsPathBuf> {
222 match self { 221 match self {
223 ProjectWorkspace::Json { project, .. } => project 222 ProjectWorkspace::Json { project, project_location } => project
224 .crates 223 .crates
225 .iter() 224 .iter()
226 .filter_map(|krate| krate.proc_macro_dylib_path.as_ref()) 225 .filter_map(|krate| krate.proc_macro_dylib_path.as_ref())
227 .cloned() 226 .map(|it| project_location.join(it))
228 .collect(), 227 .collect(),
229 ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => cargo 228 ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => cargo
230 .packages() 229 .packages()
diff --git a/crates/ra_project_model/src/sysroot.rs b/crates/ra_project_model/src/sysroot.rs
index a8a196e64..943ff92df 100644
--- a/crates/ra_project_model/src/sysroot.rs
+++ b/crates/ra_project_model/src/sysroot.rs
@@ -1,15 +1,12 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use std::{ 3use std::{convert::TryFrom, env, ops, path::Path, process::Command};
4 env, ops,
5 path::{Path, PathBuf},
6 process::Command,
7};
8 4
9use anyhow::{bail, Result}; 5use anyhow::{bail, format_err, Result};
10use ra_arena::{Arena, Idx}; 6use ra_arena::{Arena, Idx};
11 7
12use crate::output; 8use crate::output;
9use paths::{AbsPath, AbsPathBuf};
13 10
14#[derive(Default, Debug, Clone)] 11#[derive(Default, Debug, Clone)]
15pub struct Sysroot { 12pub struct Sysroot {
@@ -21,7 +18,7 @@ pub type SysrootCrate = Idx<SysrootCrateData>;
21#[derive(Debug, Clone)] 18#[derive(Debug, Clone)]
22pub struct SysrootCrateData { 19pub struct SysrootCrateData {
23 pub name: String, 20 pub name: String,
24 pub root: PathBuf, 21 pub root: AbsPathBuf,
25 pub deps: Vec<SysrootCrate>, 22 pub deps: Vec<SysrootCrate>,
26} 23}
27 24
@@ -53,7 +50,7 @@ impl Sysroot {
53 self.crates.iter().map(|(id, _data)| id) 50 self.crates.iter().map(|(id, _data)| id)
54 } 51 }
55 52
56 pub fn discover(cargo_toml: &Path) -> Result<Sysroot> { 53 pub fn discover(cargo_toml: &AbsPath) -> Result<Sysroot> {
57 let src = get_or_install_rust_src(cargo_toml)?; 54 let src = get_or_install_rust_src(cargo_toml)?;
58 let mut sysroot = Sysroot { crates: Arena::default() }; 55 let mut sysroot = Sysroot { crates: Arena::default() };
59 for name in SYSROOT_CRATES.trim().lines() { 56 for name in SYSROOT_CRATES.trim().lines() {
@@ -86,16 +83,18 @@ impl Sysroot {
86 } 83 }
87} 84}
88 85
89fn get_or_install_rust_src(cargo_toml: &Path) -> Result<PathBuf> { 86fn get_or_install_rust_src(cargo_toml: &AbsPath) -> Result<AbsPathBuf> {
90 if let Ok(path) = env::var("RUST_SRC_PATH") { 87 if let Ok(path) = env::var("RUST_SRC_PATH") {
91 return Ok(path.into()); 88 let path = AbsPathBuf::try_from(path.as_str())
89 .map_err(|path| format_err!("RUST_SRC_PATH must be absolute: {}", path.display()))?;
90 return Ok(path);
92 } 91 }
93 let current_dir = cargo_toml.parent().unwrap(); 92 let current_dir = cargo_toml.parent().unwrap();
94 let mut rustc = Command::new(ra_toolchain::rustc()); 93 let mut rustc = Command::new(ra_toolchain::rustc());
95 rustc.current_dir(current_dir).args(&["--print", "sysroot"]); 94 rustc.current_dir(current_dir).args(&["--print", "sysroot"]);
96 let rustc_output = output(rustc)?; 95 let rustc_output = output(rustc)?;
97 let stdout = String::from_utf8(rustc_output.stdout)?; 96 let stdout = String::from_utf8(rustc_output.stdout)?;
98 let sysroot_path = Path::new(stdout.trim()); 97 let sysroot_path = AbsPath::assert(Path::new(stdout.trim()));
99 let src_path = sysroot_path.join("lib/rustlib/src/rust/src"); 98 let src_path = sysroot_path.join("lib/rustlib/src/rust/src");
100 99
101 if !src_path.exists() { 100 if !src_path.exists() {
@@ -116,7 +115,7 @@ fn get_or_install_rust_src(cargo_toml: &Path) -> Result<PathBuf> {
116} 115}
117 116
118impl SysrootCrateData { 117impl SysrootCrateData {
119 pub fn root_dir(&self) -> &Path { 118 pub fn root_dir(&self) -> &AbsPath {
120 self.root.parent().unwrap() 119 self.root.parent().unwrap()
121 } 120 }
122} 121}
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 99e3f7173..45204d1a3 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -3,6 +3,8 @@
3//! Based on cli flags, either spawns an LSP server, or runs a batch analysis 3//! Based on cli flags, either spawns an LSP server, or runs a batch analysis
4mod args; 4mod args;
5 5
6use std::convert::TryFrom;
7
6use lsp_server::Connection; 8use lsp_server::Connection;
7use rust_analyzer::{ 9use rust_analyzer::{
8 cli, 10 cli,
@@ -10,9 +12,11 @@ use rust_analyzer::{
10 from_json, Result, 12 from_json, Result,
11}; 13};
12 14
13use crate::args::HelpPrinted; 15use ra_db::AbsPathBuf;
14use ra_project_model::ProjectManifest; 16use ra_project_model::ProjectManifest;
15 17
18use crate::args::HelpPrinted;
19
16fn main() -> Result<()> { 20fn main() -> Result<()> {
17 setup_logging()?; 21 setup_logging()?;
18 let args = match args::Args::parse()? { 22 let args = match args::Args::parse()? {
@@ -20,6 +24,9 @@ fn main() -> Result<()> {
20 Err(HelpPrinted) => return Ok(()), 24 Err(HelpPrinted) => return Ok(()),
21 }; 25 };
22 match args.command { 26 match args.command {
27 args::Command::RunServer => run_server()?,
28 args::Command::ProcMacro => ra_proc_macro_srv::cli::run()?,
29
23 args::Command::Parse { no_dump } => cli::parse(no_dump)?, 30 args::Command::Parse { no_dump } => cli::parse(no_dump)?,
24 args::Command::Symbols => cli::symbols()?, 31 args::Command::Symbols => cli::symbols()?,
25 args::Command::Highlight { rainbow } => cli::highlight(rainbow)?, 32 args::Command::Highlight { rainbow } => cli::highlight(rainbow)?,
@@ -41,7 +48,6 @@ fn main() -> Result<()> {
41 load_output_dirs, 48 load_output_dirs,
42 with_proc_macro, 49 with_proc_macro,
43 )?, 50 )?,
44
45 args::Command::Bench { path, what, load_output_dirs, with_proc_macro } => { 51 args::Command::Bench { path, what, load_output_dirs, with_proc_macro } => {
46 cli::analysis_bench( 52 cli::analysis_bench(
47 args.verbosity, 53 args.verbosity,
@@ -51,13 +57,9 @@ fn main() -> Result<()> {
51 with_proc_macro, 57 with_proc_macro,
52 )? 58 )?
53 } 59 }
54
55 args::Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } => { 60 args::Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } => {
56 cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro, all)? 61 cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro, all)?
57 } 62 }
58
59 args::Command::ProcMacro => run_proc_macro_srv()?,
60 args::Command::RunServer => run_server()?,
61 args::Command::Version => println!("rust-analyzer {}", env!("REV")), 63 args::Command::Version => println!("rust-analyzer {}", env!("REV")),
62 } 64 }
63 Ok(()) 65 Ok(())
@@ -70,11 +72,6 @@ fn setup_logging() -> Result<()> {
70 Ok(()) 72 Ok(())
71} 73}
72 74
73fn run_proc_macro_srv() -> Result<()> {
74 ra_proc_macro_srv::cli::run()?;
75 Ok(())
76}
77
78fn run_server() -> Result<()> { 75fn run_server() -> Result<()> {
79 log::info!("lifecycle: server started"); 76 log::info!("lifecycle: server started");
80 77
@@ -103,14 +100,23 @@ fn run_server() -> Result<()> {
103 } 100 }
104 101
105 let config = { 102 let config = {
106 let mut config = Config::default(); 103 let root_path = match initialize_params
104 .root_uri
105 .and_then(|it| it.to_file_path().ok())
106 .and_then(|it| AbsPathBuf::try_from(it).ok())
107 {
108 Some(it) => it,
109 None => {
110 let cwd = std::env::current_dir()?;
111 AbsPathBuf::assert(cwd)
112 }
113 };
114
115 let mut config = Config::new(root_path);
107 if let Some(value) = &initialize_params.initialization_options { 116 if let Some(value) = &initialize_params.initialization_options {
108 config.update(value); 117 config.update(value);
109 } 118 }
110 config.update_caps(&initialize_params.capabilities); 119 config.update_caps(&initialize_params.capabilities);
111 let cwd = std::env::current_dir()?;
112 config.root_path =
113 initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd);
114 120
115 if config.linked_projects.is_empty() { 121 if config.linked_projects.is_empty() {
116 let workspace_roots = initialize_params 122 let workspace_roots = initialize_params
@@ -119,6 +125,7 @@ fn run_server() -> Result<()> {
119 workspaces 125 workspaces
120 .into_iter() 126 .into_iter()
121 .filter_map(|it| it.uri.to_file_path().ok()) 127 .filter_map(|it| it.uri.to_file_path().ok())
128 .filter_map(|it| AbsPathBuf::try_from(it).ok())
122 .collect::<Vec<_>>() 129 .collect::<Vec<_>>()
123 }) 130 })
124 .filter(|workspaces| !workspaces.is_empty()) 131 .filter(|workspaces| !workspaces.is_empty())
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs
index 00bbbaf40..e910db6eb 100644
--- a/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -16,7 +16,7 @@ pub fn load_cargo(
16 load_out_dirs_from_check: bool, 16 load_out_dirs_from_check: bool,
17 with_proc_macro: bool, 17 with_proc_macro: bool,
18) -> Result<(AnalysisHost, vfs::Vfs)> { 18) -> Result<(AnalysisHost, vfs::Vfs)> {
19 let root = std::env::current_dir()?.join(root); 19 let root = AbsPathBuf::assert(std::env::current_dir()?.join(root));
20 let root = ProjectManifest::discover_single(&root)?; 20 let root = ProjectManifest::discover_single(&root)?;
21 let ws = ProjectWorkspace::load( 21 let ws = ProjectWorkspace::load(
22 root, 22 root,
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index aa2c4ae15..0be34c43f 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -11,6 +11,7 @@ use std::{ffi::OsString, path::PathBuf};
11 11
12use crate::diagnostics::DiagnosticsConfig; 12use crate::diagnostics::DiagnosticsConfig;
13use lsp_types::ClientCapabilities; 13use lsp_types::ClientCapabilities;
14use ra_db::AbsPathBuf;
14use ra_flycheck::FlycheckConfig; 15use ra_flycheck::FlycheckConfig;
15use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig}; 16use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig};
16use ra_project_model::{CargoConfig, JsonProject, ProjectManifest}; 17use ra_project_model::{CargoConfig, JsonProject, ProjectManifest};
@@ -40,7 +41,7 @@ pub struct Config {
40 41
41 pub with_sysroot: bool, 42 pub with_sysroot: bool,
42 pub linked_projects: Vec<LinkedProject>, 43 pub linked_projects: Vec<LinkedProject>,
43 pub root_path: PathBuf, 44 pub root_path: AbsPathBuf,
44} 45}
45 46
46#[derive(Debug, Clone)] 47#[derive(Debug, Clone)]
@@ -131,8 +132,8 @@ pub struct ClientCapsConfig {
131 pub hover_actions: bool, 132 pub hover_actions: bool,
132} 133}
133 134
134impl Default for Config { 135impl Config {
135 fn default() -> Self { 136 pub fn new(root_path: AbsPathBuf) -> Self {
136 Config { 137 Config {
137 client_caps: ClientCapsConfig::default(), 138 client_caps: ClientCapsConfig::default(),
138 139
@@ -171,18 +172,16 @@ impl Default for Config {
171 lens: LensConfig::default(), 172 lens: LensConfig::default(),
172 hover: HoverConfig::default(), 173 hover: HoverConfig::default(),
173 linked_projects: Vec::new(), 174 linked_projects: Vec::new(),
174 root_path: PathBuf::new(), 175 root_path,
175 } 176 }
176 } 177 }
177}
178 178
179impl Config {
180 #[rustfmt::skip] 179 #[rustfmt::skip]
181 pub fn update(&mut self, value: &serde_json::Value) { 180 pub fn update(&mut self, value: &serde_json::Value) {
182 log::info!("Config::update({:#})", value); 181 log::info!("Config::update({:#})", value);
183 182
184 let client_caps = self.client_caps.clone(); 183 let client_caps = self.client_caps.clone();
185 *self = Default::default(); 184 *self = Config::new(self.root_path.clone());
186 self.client_caps = client_caps; 185 self.client_caps = client_caps;
187 186
188 set(value, "/withSysroot", &mut self.with_sysroot); 187 set(value, "/withSysroot", &mut self.with_sysroot);
@@ -279,9 +278,12 @@ impl Config {
279 self.linked_projects.clear(); 278 self.linked_projects.clear();
280 for linked_project in linked_projects { 279 for linked_project in linked_projects {
281 let linked_project = match linked_project { 280 let linked_project = match linked_project {
282 ManifestOrJsonProject::Manifest(it) => match ProjectManifest::from_manifest_file(it) { 281 ManifestOrJsonProject::Manifest(it) => {
283 Ok(it) => it.into(), 282 let path = self.root_path.join(it);
284 Err(_) => continue, 283 match ProjectManifest::from_manifest_file(path) {
284 Ok(it) => it.into(),
285 Err(_) => continue,
286 }
285 } 287 }
286 ManifestOrJsonProject::JsonProject(it) => it.into(), 288 ManifestOrJsonProject::JsonProject(it) => it.into(),
287 }; 289 };
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index e2ddb7933..f18694feb 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -310,11 +310,10 @@ impl ProjectFolders {
310 310
311 let mut file_set_roots: Vec<VfsPath> = vec![]; 311 let mut file_set_roots: Vec<VfsPath> = vec![];
312 312
313 let path = AbsPathBuf::try_from(path).unwrap();
314 let entry = if root.is_member() { 313 let entry = if root.is_member() {
315 vfs::loader::Entry::local_cargo_package(path.clone()) 314 vfs::loader::Entry::local_cargo_package(path.to_path_buf())
316 } else { 315 } else {
317 vfs::loader::Entry::cargo_package_dependency(path.clone()) 316 vfs::loader::Entry::cargo_package_dependency(path.to_path_buf())
318 }; 317 };
319 res.load.push(entry); 318 res.load.push(entry);
320 if root.is_member() { 319 if root.is_member() {
@@ -329,7 +328,7 @@ impl ProjectFolders {
329 } 328 }
330 file_set_roots.push(out_dir.into()); 329 file_set_roots.push(out_dir.into());
331 } 330 }
332 file_set_roots.push(path.into()); 331 file_set_roots.push(path.to_path_buf().into());
333 332
334 if root.is_member() { 333 if root.is_member() {
335 local_filesets.push(fsc.len()); 334 local_filesets.push(fsc.len());
diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs
index 8d88f992d..49f194f7e 100644
--- a/crates/rust-analyzer/tests/heavy_tests/support.rs
+++ b/crates/rust-analyzer/tests/heavy_tests/support.rs
@@ -17,6 +17,7 @@ use serde_json::{to_string_pretty, Value};
17use tempfile::TempDir; 17use tempfile::TempDir;
18use test_utils::{find_mismatch, Fixture}; 18use test_utils::{find_mismatch, Fixture};
19 19
20use ra_db::AbsPathBuf;
20use ra_project_model::ProjectManifest; 21use ra_project_model::ProjectManifest;
21use rust_analyzer::{ 22use rust_analyzer::{
22 config::{ClientCapsConfig, Config, FilesConfig, FilesWatcher, LinkedProject}, 23 config::{ClientCapsConfig, Config, FilesConfig, FilesWatcher, LinkedProject},
@@ -70,10 +71,11 @@ impl<'a> Project<'a> {
70 fs::write(path.as_path(), entry.text.as_bytes()).unwrap(); 71 fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
71 } 72 }
72 73
74 let tmp_dir_path = AbsPathBuf::assert(tmp_dir.path().to_path_buf());
73 let mut roots = 75 let mut roots =
74 self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect::<Vec<_>>(); 76 self.roots.into_iter().map(|root| tmp_dir_path.join(root)).collect::<Vec<_>>();
75 if roots.is_empty() { 77 if roots.is_empty() {
76 roots.push(tmp_dir.path().to_path_buf()); 78 roots.push(tmp_dir_path.clone());
77 } 79 }
78 let linked_projects = roots 80 let linked_projects = roots
79 .into_iter() 81 .into_iter()
@@ -91,7 +93,7 @@ impl<'a> Project<'a> {
91 with_sysroot: self.with_sysroot, 93 with_sysroot: self.with_sysroot,
92 linked_projects, 94 linked_projects,
93 files: FilesConfig { watcher: FilesWatcher::Client, exclude: Vec::new() }, 95 files: FilesConfig { watcher: FilesWatcher::Client, exclude: Vec::new() },
94 ..Config::default() 96 ..Config::new(tmp_dir_path)
95 }; 97 };
96 if let Some(f) = &self.config { 98 if let Some(f) = &self.config {
97 f(&mut config) 99 f(&mut config)