diff options
Diffstat (limited to 'crates/ra_db')
-rw-r--r-- | crates/ra_db/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/ra_db/src/fixture.rs | 180 | ||||
-rw-r--r-- | crates/ra_db/src/input.rs | 110 | ||||
-rw-r--r-- | crates/ra_db/src/lib.rs | 30 |
4 files changed, 109 insertions, 213 deletions
diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml index 8ab409158..372fb242b 100644 --- a/crates/ra_db/Cargo.toml +++ b/crates/ra_db/Cargo.toml | |||
@@ -17,3 +17,5 @@ ra_cfg = { path = "../ra_cfg" } | |||
17 | ra_prof = { path = "../ra_prof" } | 17 | ra_prof = { path = "../ra_prof" } |
18 | ra_tt = { path = "../ra_tt" } | 18 | ra_tt = { path = "../ra_tt" } |
19 | test_utils = { path = "../test_utils" } | 19 | test_utils = { path = "../test_utils" } |
20 | vfs = { path = "../vfs" } | ||
21 | stdx = { path = "../stdx" } | ||
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs index 482a2f3e6..4f4fb4494 100644 --- a/crates/ra_db/src/fixture.rs +++ b/crates/ra_db/src/fixture.rs | |||
@@ -57,17 +57,16 @@ | |||
57 | //! fn insert_source_code_here() {} | 57 | //! fn insert_source_code_here() {} |
58 | //! " | 58 | //! " |
59 | //! ``` | 59 | //! ``` |
60 | 60 | use std::{str::FromStr, sync::Arc}; | |
61 | use std::str::FromStr; | ||
62 | use std::sync::Arc; | ||
63 | 61 | ||
64 | use ra_cfg::CfgOptions; | 62 | use ra_cfg::CfgOptions; |
65 | use rustc_hash::FxHashMap; | 63 | use rustc_hash::FxHashMap; |
66 | use test_utils::{extract_offset, parse_fixture, parse_single_fixture, FixtureMeta, CURSOR_MARKER}; | 64 | use test_utils::{extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER}; |
65 | use vfs::{file_set::FileSet, VfsPath}; | ||
67 | 66 | ||
68 | use crate::{ | 67 | use crate::{ |
69 | input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, RelativePathBuf, | 68 | input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, SourceDatabaseExt, |
70 | SourceDatabaseExt, SourceRoot, SourceRootId, | 69 | SourceRoot, SourceRootId, |
71 | }; | 70 | }; |
72 | 71 | ||
73 | pub const WORKSPACE: SourceRootId = SourceRootId(0); | 72 | pub const WORKSPACE: SourceRootId = SourceRootId(0); |
@@ -75,21 +74,32 @@ pub const WORKSPACE: SourceRootId = SourceRootId(0); | |||
75 | pub trait WithFixture: Default + SourceDatabaseExt + 'static { | 74 | pub trait WithFixture: Default + SourceDatabaseExt + 'static { |
76 | fn with_single_file(text: &str) -> (Self, FileId) { | 75 | fn with_single_file(text: &str) -> (Self, FileId) { |
77 | let mut db = Self::default(); | 76 | let mut db = Self::default(); |
78 | let file_id = with_single_file(&mut db, text); | 77 | let (_, files) = with_files(&mut db, text); |
79 | (db, file_id) | 78 | assert_eq!(files.len(), 1); |
79 | (db, files[0]) | ||
80 | } | 80 | } |
81 | 81 | ||
82 | fn with_files(ra_fixture: &str) -> Self { | 82 | fn with_files(ra_fixture: &str) -> Self { |
83 | let mut db = Self::default(); | 83 | let mut db = Self::default(); |
84 | let pos = with_files(&mut db, ra_fixture); | 84 | let (pos, _) = with_files(&mut db, ra_fixture); |
85 | assert!(pos.is_none()); | 85 | assert!(pos.is_none()); |
86 | db | 86 | db |
87 | } | 87 | } |
88 | 88 | ||
89 | fn with_position(ra_fixture: &str) -> (Self, FilePosition) { | 89 | fn with_position(ra_fixture: &str) -> (Self, FilePosition) { |
90 | let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture); | ||
91 | let offset = match range_or_offset { | ||
92 | RangeOrOffset::Range(_) => panic!(), | ||
93 | RangeOrOffset::Offset(it) => it, | ||
94 | }; | ||
95 | (db, FilePosition { file_id, offset }) | ||
96 | } | ||
97 | |||
98 | fn with_range_or_offset(ra_fixture: &str) -> (Self, FileId, RangeOrOffset) { | ||
90 | let mut db = Self::default(); | 99 | let mut db = Self::default(); |
91 | let pos = with_files(&mut db, ra_fixture); | 100 | let (pos, _) = with_files(&mut db, ra_fixture); |
92 | (db, pos.unwrap()) | 101 | let (file_id, range_or_offset) = pos.unwrap(); |
102 | (db, file_id, range_or_offset) | ||
93 | } | 103 | } |
94 | 104 | ||
95 | fn test_crate(&self) -> CrateId { | 105 | fn test_crate(&self) -> CrateId { |
@@ -103,83 +113,36 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { | |||
103 | 113 | ||
104 | impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {} | 114 | impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {} |
105 | 115 | ||
106 | fn with_single_file(db: &mut dyn SourceDatabaseExt, ra_fixture: &str) -> FileId { | 116 | fn with_files( |
107 | let file_id = FileId(0); | 117 | db: &mut dyn SourceDatabaseExt, |
108 | let rel_path: RelativePathBuf = "/main.rs".into(); | 118 | fixture: &str, |
109 | 119 | ) -> (Option<(FileId, RangeOrOffset)>, Vec<FileId>) { | |
110 | let mut source_root = SourceRoot::new_local(); | 120 | let fixture = Fixture::parse(fixture); |
111 | source_root.insert_file(rel_path.clone(), file_id); | ||
112 | |||
113 | let fixture = parse_single_fixture(ra_fixture); | ||
114 | |||
115 | let crate_graph = if let Some(entry) = fixture { | ||
116 | let meta = match ParsedMeta::from(&entry.meta) { | ||
117 | ParsedMeta::File(it) => it, | ||
118 | _ => panic!("with_single_file only support file meta"), | ||
119 | }; | ||
120 | |||
121 | let mut crate_graph = CrateGraph::default(); | ||
122 | crate_graph.add_crate_root( | ||
123 | file_id, | ||
124 | meta.edition, | ||
125 | meta.krate.map(|name| { | ||
126 | CrateName::new(&name).expect("Fixture crate name should not contain dashes") | ||
127 | }), | ||
128 | meta.cfg, | ||
129 | meta.env, | ||
130 | Default::default(), | ||
131 | Default::default(), | ||
132 | ); | ||
133 | crate_graph | ||
134 | } else { | ||
135 | let mut crate_graph = CrateGraph::default(); | ||
136 | crate_graph.add_crate_root( | ||
137 | file_id, | ||
138 | Edition::Edition2018, | ||
139 | None, | ||
140 | CfgOptions::default(), | ||
141 | Env::default(), | ||
142 | Default::default(), | ||
143 | Default::default(), | ||
144 | ); | ||
145 | crate_graph | ||
146 | }; | ||
147 | |||
148 | db.set_file_text(file_id, Arc::new(ra_fixture.to_string())); | ||
149 | db.set_file_relative_path(file_id, rel_path); | ||
150 | db.set_file_source_root(file_id, WORKSPACE); | ||
151 | db.set_source_root(WORKSPACE, Arc::new(source_root)); | ||
152 | db.set_crate_graph(Arc::new(crate_graph)); | ||
153 | |||
154 | file_id | ||
155 | } | ||
156 | |||
157 | fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosition> { | ||
158 | let fixture = parse_fixture(fixture); | ||
159 | 121 | ||
122 | let mut files = Vec::new(); | ||
160 | let mut crate_graph = CrateGraph::default(); | 123 | let mut crate_graph = CrateGraph::default(); |
161 | let mut crates = FxHashMap::default(); | 124 | let mut crates = FxHashMap::default(); |
162 | let mut crate_deps = Vec::new(); | 125 | let mut crate_deps = Vec::new(); |
163 | let mut default_crate_root: Option<FileId> = None; | 126 | let mut default_crate_root: Option<FileId> = None; |
164 | 127 | ||
165 | let mut source_root = SourceRoot::new_local(); | 128 | let mut file_set = FileSet::default(); |
166 | let mut source_root_id = WORKSPACE; | 129 | let source_root_id = WORKSPACE; |
167 | let mut source_root_prefix: RelativePathBuf = "/".into(); | 130 | let source_root_prefix = "/".to_string(); |
168 | let mut file_id = FileId(0); | 131 | let mut file_id = FileId(0); |
169 | 132 | ||
170 | let mut file_position = None; | 133 | let mut file_position = None; |
171 | 134 | ||
172 | for entry in fixture.iter() { | 135 | for entry in fixture { |
173 | let meta = match ParsedMeta::from(&entry.meta) { | 136 | let text = if entry.text.contains(CURSOR_MARKER) { |
174 | ParsedMeta::Root { path } => { | 137 | let (range_or_offset, text) = extract_range_or_offset(&entry.text); |
175 | let source_root = std::mem::replace(&mut source_root, SourceRoot::new_local()); | 138 | assert!(file_position.is_none()); |
176 | db.set_source_root(source_root_id, Arc::new(source_root)); | 139 | file_position = Some((file_id, range_or_offset)); |
177 | source_root_id.0 += 1; | 140 | text.to_string() |
178 | source_root_prefix = path; | 141 | } else { |
179 | continue; | 142 | entry.text.clone() |
180 | } | ||
181 | ParsedMeta::File(it) => it, | ||
182 | }; | 143 | }; |
144 | |||
145 | let meta = FileMeta::from(entry); | ||
183 | assert!(meta.path.starts_with(&source_root_prefix)); | 146 | assert!(meta.path.starts_with(&source_root_prefix)); |
184 | 147 | ||
185 | if let Some(krate) = meta.krate { | 148 | if let Some(krate) = meta.krate { |
@@ -190,7 +153,6 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit | |||
190 | meta.cfg, | 153 | meta.cfg, |
191 | meta.env, | 154 | meta.env, |
192 | Default::default(), | 155 | Default::default(), |
193 | Default::default(), | ||
194 | ); | 156 | ); |
195 | let prev = crates.insert(krate.clone(), crate_id); | 157 | let prev = crates.insert(krate.clone(), crate_id); |
196 | assert!(prev.is_none()); | 158 | assert!(prev.is_none()); |
@@ -202,20 +164,11 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit | |||
202 | default_crate_root = Some(file_id); | 164 | default_crate_root = Some(file_id); |
203 | } | 165 | } |
204 | 166 | ||
205 | let text = if entry.text.contains(CURSOR_MARKER) { | ||
206 | let (offset, text) = extract_offset(&entry.text); | ||
207 | assert!(file_position.is_none()); | ||
208 | file_position = Some(FilePosition { file_id, offset }); | ||
209 | text.to_string() | ||
210 | } else { | ||
211 | entry.text.to_string() | ||
212 | }; | ||
213 | |||
214 | db.set_file_text(file_id, Arc::new(text)); | 167 | db.set_file_text(file_id, Arc::new(text)); |
215 | db.set_file_relative_path(file_id, meta.path.clone()); | ||
216 | db.set_file_source_root(file_id, source_root_id); | 168 | db.set_file_source_root(file_id, source_root_id); |
217 | source_root.insert_file(meta.path, file_id); | 169 | let path = VfsPath::new_virtual_path(meta.path); |
218 | 170 | file_set.insert(file_id, path.into()); | |
171 | files.push(file_id); | ||
219 | file_id.0 += 1; | 172 | file_id.0 += 1; |
220 | } | 173 | } |
221 | 174 | ||
@@ -228,7 +181,6 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit | |||
228 | CfgOptions::default(), | 181 | CfgOptions::default(), |
229 | Env::default(), | 182 | Env::default(), |
230 | Default::default(), | 183 | Default::default(), |
231 | Default::default(), | ||
232 | ); | 184 | ); |
233 | } else { | 185 | } else { |
234 | for (from, to) in crate_deps { | 186 | for (from, to) in crate_deps { |
@@ -238,19 +190,14 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit | |||
238 | } | 190 | } |
239 | } | 191 | } |
240 | 192 | ||
241 | db.set_source_root(source_root_id, Arc::new(source_root)); | 193 | db.set_source_root(source_root_id, Arc::new(SourceRoot::new_local(file_set))); |
242 | db.set_crate_graph(Arc::new(crate_graph)); | 194 | db.set_crate_graph(Arc::new(crate_graph)); |
243 | 195 | ||
244 | file_position | 196 | (file_position, files) |
245 | } | ||
246 | |||
247 | enum ParsedMeta { | ||
248 | Root { path: RelativePathBuf }, | ||
249 | File(FileMeta), | ||
250 | } | 197 | } |
251 | 198 | ||
252 | struct FileMeta { | 199 | struct FileMeta { |
253 | path: RelativePathBuf, | 200 | path: String, |
254 | krate: Option<String>, | 201 | krate: Option<String>, |
255 | deps: Vec<String>, | 202 | deps: Vec<String>, |
256 | cfg: CfgOptions, | 203 | cfg: CfgOptions, |
@@ -258,25 +205,22 @@ struct FileMeta { | |||
258 | env: Env, | 205 | env: Env, |
259 | } | 206 | } |
260 | 207 | ||
261 | impl From<&FixtureMeta> for ParsedMeta { | 208 | impl From<Fixture> for FileMeta { |
262 | fn from(meta: &FixtureMeta) -> Self { | 209 | fn from(f: Fixture) -> FileMeta { |
263 | match meta { | 210 | let mut cfg = CfgOptions::default(); |
264 | FixtureMeta::Root { path } => { | 211 | f.cfg_atoms.iter().for_each(|it| cfg.insert_atom(it.into())); |
265 | // `Self::Root` causes a false warning: 'variant is never constructed: `Root` ' | 212 | f.cfg_key_values.iter().for_each(|(k, v)| cfg.insert_key_value(k.into(), v.into())); |
266 | // see https://github.com/rust-lang/rust/issues/69018 | 213 | |
267 | ParsedMeta::Root { path: path.to_owned() } | 214 | FileMeta { |
268 | } | 215 | path: f.path, |
269 | FixtureMeta::File(f) => Self::File(FileMeta { | 216 | krate: f.krate, |
270 | path: f.path.to_owned(), | 217 | deps: f.deps, |
271 | krate: f.crate_name.to_owned(), | 218 | cfg, |
272 | deps: f.deps.to_owned(), | 219 | edition: f |
273 | cfg: f.cfg.to_owned(), | 220 | .edition |
274 | edition: f | 221 | .as_ref() |
275 | .edition | 222 | .map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()), |
276 | .as_ref() | 223 | env: Env::from(f.env.iter()), |
277 | .map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()), | ||
278 | env: Env::from(f.env.iter()), | ||
279 | }), | ||
280 | } | 224 | } |
281 | } | 225 | } |
282 | } | 226 | } |
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index bf26048f2..7f3660118 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs | |||
@@ -6,27 +6,15 @@ | |||
6 | //! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how | 6 | //! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how |
7 | //! actual IO is done and lowered to input. | 7 | //! actual IO is done and lowered to input. |
8 | 8 | ||
9 | use std::{ | 9 | use std::{fmt, ops, str::FromStr, sync::Arc}; |
10 | fmt, ops, | ||
11 | path::{Path, PathBuf}, | ||
12 | str::FromStr, | ||
13 | sync::Arc, | ||
14 | }; | ||
15 | 10 | ||
16 | use ra_cfg::CfgOptions; | 11 | use ra_cfg::CfgOptions; |
17 | use ra_syntax::SmolStr; | 12 | use ra_syntax::SmolStr; |
18 | use ra_tt::TokenExpander; | 13 | use ra_tt::TokenExpander; |
19 | use rustc_hash::{FxHashMap, FxHashSet}; | 14 | use rustc_hash::{FxHashMap, FxHashSet}; |
15 | use vfs::file_set::FileSet; | ||
20 | 16 | ||
21 | use crate::{RelativePath, RelativePathBuf}; | 17 | pub use vfs::FileId; |
22 | |||
23 | /// `FileId` is an integer which uniquely identifies a file. File paths are | ||
24 | /// messy and system-dependent, so most of the code should work directly with | ||
25 | /// `FileId`, without inspecting the path. The mapping between `FileId` and path | ||
26 | /// and `SourceRoot` is constant. A file rename is represented as a pair of | ||
27 | /// deletion/creation. | ||
28 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
29 | pub struct FileId(pub u32); | ||
30 | 18 | ||
31 | /// Files are grouped into source roots. A source root is a directory on the | 19 | /// Files are grouped into source roots. A source root is a directory on the |
32 | /// file systems which is watched for changes. Typically it corresponds to a | 20 | /// file systems which is watched for changes. Typically it corresponds to a |
@@ -45,27 +33,18 @@ pub struct SourceRoot { | |||
45 | /// Libraries are considered mostly immutable, this assumption is used to | 33 | /// Libraries are considered mostly immutable, this assumption is used to |
46 | /// optimize salsa's query structure | 34 | /// optimize salsa's query structure |
47 | pub is_library: bool, | 35 | pub is_library: bool, |
48 | files: FxHashMap<RelativePathBuf, FileId>, | 36 | pub(crate) file_set: FileSet, |
49 | } | 37 | } |
50 | 38 | ||
51 | impl SourceRoot { | 39 | impl SourceRoot { |
52 | pub fn new_local() -> SourceRoot { | 40 | pub fn new_local(file_set: FileSet) -> SourceRoot { |
53 | SourceRoot { is_library: false, files: Default::default() } | 41 | SourceRoot { is_library: false, file_set } |
54 | } | ||
55 | pub fn new_library() -> SourceRoot { | ||
56 | SourceRoot { is_library: true, files: Default::default() } | ||
57 | } | ||
58 | pub fn insert_file(&mut self, path: RelativePathBuf, file_id: FileId) { | ||
59 | self.files.insert(path, file_id); | ||
60 | } | 42 | } |
61 | pub fn remove_file(&mut self, path: &RelativePath) { | 43 | pub fn new_library(file_set: FileSet) -> SourceRoot { |
62 | self.files.remove(path); | 44 | SourceRoot { is_library: true, file_set } |
63 | } | 45 | } |
64 | pub fn walk(&self) -> impl Iterator<Item = FileId> + '_ { | 46 | pub fn iter(&self) -> impl Iterator<Item = FileId> + '_ { |
65 | self.files.values().copied() | 47 | self.file_set.iter() |
66 | } | ||
67 | pub fn file_by_relative_path(&self, path: &RelativePath) -> Option<FileId> { | ||
68 | self.files.get(path).copied() | ||
69 | } | 48 | } |
70 | } | 49 | } |
71 | 50 | ||
@@ -141,7 +120,6 @@ pub struct CrateData { | |||
141 | pub display_name: Option<CrateName>, | 120 | pub display_name: Option<CrateName>, |
142 | pub cfg_options: CfgOptions, | 121 | pub cfg_options: CfgOptions, |
143 | pub env: Env, | 122 | pub env: Env, |
144 | pub extern_source: ExternSource, | ||
145 | pub dependencies: Vec<Dependency>, | 123 | pub dependencies: Vec<Dependency>, |
146 | pub proc_macro: Vec<ProcMacro>, | 124 | pub proc_macro: Vec<ProcMacro>, |
147 | } | 125 | } |
@@ -152,22 +130,11 @@ pub enum Edition { | |||
152 | Edition2015, | 130 | Edition2015, |
153 | } | 131 | } |
154 | 132 | ||
155 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
156 | pub struct ExternSourceId(pub u32); | ||
157 | |||
158 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | 133 | #[derive(Default, Debug, Clone, PartialEq, Eq)] |
159 | pub struct Env { | 134 | pub struct Env { |
160 | entries: FxHashMap<String, String>, | 135 | entries: FxHashMap<String, String>, |
161 | } | 136 | } |
162 | 137 | ||
163 | // FIXME: Redesign vfs for solve the following limitation ? | ||
164 | // Note: Some env variables (e.g. OUT_DIR) are located outside of the | ||
165 | // crate. We store a map to allow remap it to ExternSourceId | ||
166 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | ||
167 | pub struct ExternSource { | ||
168 | extern_paths: FxHashMap<PathBuf, ExternSourceId>, | ||
169 | } | ||
170 | |||
171 | #[derive(Debug, Clone, PartialEq, Eq)] | 138 | #[derive(Debug, Clone, PartialEq, Eq)] |
172 | pub struct Dependency { | 139 | pub struct Dependency { |
173 | pub crate_id: CrateId, | 140 | pub crate_id: CrateId, |
@@ -182,7 +149,6 @@ impl CrateGraph { | |||
182 | display_name: Option<CrateName>, | 149 | display_name: Option<CrateName>, |
183 | cfg_options: CfgOptions, | 150 | cfg_options: CfgOptions, |
184 | env: Env, | 151 | env: Env, |
185 | extern_source: ExternSource, | ||
186 | proc_macro: Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)>, | 152 | proc_macro: Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)>, |
187 | ) -> CrateId { | 153 | ) -> CrateId { |
188 | let proc_macro = | 154 | let proc_macro = |
@@ -194,7 +160,6 @@ impl CrateGraph { | |||
194 | display_name, | 160 | display_name, |
195 | cfg_options, | 161 | cfg_options, |
196 | env, | 162 | env, |
197 | extern_source, | ||
198 | proc_macro, | 163 | proc_macro, |
199 | dependencies: Vec::new(), | 164 | dependencies: Vec::new(), |
200 | }; | 165 | }; |
@@ -254,12 +219,12 @@ impl CrateGraph { | |||
254 | return false; | 219 | return false; |
255 | } | 220 | } |
256 | 221 | ||
222 | if target == from { | ||
223 | return true; | ||
224 | } | ||
225 | |||
257 | for dep in &self[from].dependencies { | 226 | for dep in &self[from].dependencies { |
258 | let crate_id = dep.crate_id; | 227 | let crate_id = dep.crate_id; |
259 | if crate_id == target { | ||
260 | return true; | ||
261 | } | ||
262 | |||
263 | if self.dfs_find(target, crate_id, visited) { | 228 | if self.dfs_find(target, crate_id, visited) { |
264 | return true; | 229 | return true; |
265 | } | 230 | } |
@@ -334,20 +299,6 @@ impl Env { | |||
334 | } | 299 | } |
335 | } | 300 | } |
336 | 301 | ||
337 | impl ExternSource { | ||
338 | pub fn extern_path(&self, path: &Path) -> Option<(ExternSourceId, RelativePathBuf)> { | ||
339 | self.extern_paths.iter().find_map(|(root_path, id)| { | ||
340 | let rel_path = path.strip_prefix(root_path).ok()?; | ||
341 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; | ||
342 | Some((*id, rel_path)) | ||
343 | }) | ||
344 | } | ||
345 | |||
346 | pub fn set_extern_path(&mut self, root_path: &Path, root: ExternSourceId) { | ||
347 | self.extern_paths.insert(root_path.to_path_buf(), root); | ||
348 | } | ||
349 | } | ||
350 | |||
351 | #[derive(Debug)] | 302 | #[derive(Debug)] |
352 | pub struct ParseEditionError { | 303 | pub struct ParseEditionError { |
353 | invalid_input: String, | 304 | invalid_input: String, |
@@ -369,7 +320,7 @@ mod tests { | |||
369 | use super::{CfgOptions, CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId}; | 320 | use super::{CfgOptions, CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId}; |
370 | 321 | ||
371 | #[test] | 322 | #[test] |
372 | fn it_should_panic_because_of_cycle_dependencies() { | 323 | fn detect_cyclic_dependency_indirect() { |
373 | let mut graph = CrateGraph::default(); | 324 | let mut graph = CrateGraph::default(); |
374 | let crate1 = graph.add_crate_root( | 325 | let crate1 = graph.add_crate_root( |
375 | FileId(1u32), | 326 | FileId(1u32), |
@@ -378,7 +329,6 @@ mod tests { | |||
378 | CfgOptions::default(), | 329 | CfgOptions::default(), |
379 | Env::default(), | 330 | Env::default(), |
380 | Default::default(), | 331 | Default::default(), |
381 | Default::default(), | ||
382 | ); | 332 | ); |
383 | let crate2 = graph.add_crate_root( | 333 | let crate2 = graph.add_crate_root( |
384 | FileId(2u32), | 334 | FileId(2u32), |
@@ -387,7 +337,6 @@ mod tests { | |||
387 | CfgOptions::default(), | 337 | CfgOptions::default(), |
388 | Env::default(), | 338 | Env::default(), |
389 | Default::default(), | 339 | Default::default(), |
390 | Default::default(), | ||
391 | ); | 340 | ); |
392 | let crate3 = graph.add_crate_root( | 341 | let crate3 = graph.add_crate_root( |
393 | FileId(3u32), | 342 | FileId(3u32), |
@@ -396,7 +345,6 @@ mod tests { | |||
396 | CfgOptions::default(), | 345 | CfgOptions::default(), |
397 | Env::default(), | 346 | Env::default(), |
398 | Default::default(), | 347 | Default::default(), |
399 | Default::default(), | ||
400 | ); | 348 | ); |
401 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); | 349 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); |
402 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); | 350 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); |
@@ -404,7 +352,7 @@ mod tests { | |||
404 | } | 352 | } |
405 | 353 | ||
406 | #[test] | 354 | #[test] |
407 | fn it_works() { | 355 | fn detect_cyclic_dependency_direct() { |
408 | let mut graph = CrateGraph::default(); | 356 | let mut graph = CrateGraph::default(); |
409 | let crate1 = graph.add_crate_root( | 357 | let crate1 = graph.add_crate_root( |
410 | FileId(1u32), | 358 | FileId(1u32), |
@@ -413,7 +361,6 @@ mod tests { | |||
413 | CfgOptions::default(), | 361 | CfgOptions::default(), |
414 | Env::default(), | 362 | Env::default(), |
415 | Default::default(), | 363 | Default::default(), |
416 | Default::default(), | ||
417 | ); | 364 | ); |
418 | let crate2 = graph.add_crate_root( | 365 | let crate2 = graph.add_crate_root( |
419 | FileId(2u32), | 366 | FileId(2u32), |
@@ -422,6 +369,28 @@ mod tests { | |||
422 | CfgOptions::default(), | 369 | CfgOptions::default(), |
423 | Env::default(), | 370 | Env::default(), |
424 | Default::default(), | 371 | Default::default(), |
372 | ); | ||
373 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); | ||
374 | assert!(graph.add_dep(crate2, CrateName::new("crate2").unwrap(), crate2).is_err()); | ||
375 | } | ||
376 | |||
377 | #[test] | ||
378 | fn it_works() { | ||
379 | let mut graph = CrateGraph::default(); | ||
380 | let crate1 = graph.add_crate_root( | ||
381 | FileId(1u32), | ||
382 | Edition2018, | ||
383 | None, | ||
384 | CfgOptions::default(), | ||
385 | Env::default(), | ||
386 | Default::default(), | ||
387 | ); | ||
388 | let crate2 = graph.add_crate_root( | ||
389 | FileId(2u32), | ||
390 | Edition2018, | ||
391 | None, | ||
392 | CfgOptions::default(), | ||
393 | Env::default(), | ||
425 | Default::default(), | 394 | Default::default(), |
426 | ); | 395 | ); |
427 | let crate3 = graph.add_crate_root( | 396 | let crate3 = graph.add_crate_root( |
@@ -431,7 +400,6 @@ mod tests { | |||
431 | CfgOptions::default(), | 400 | CfgOptions::default(), |
432 | Env::default(), | 401 | Env::default(), |
433 | Default::default(), | 402 | Default::default(), |
434 | Default::default(), | ||
435 | ); | 403 | ); |
436 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); | 404 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); |
437 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); | 405 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); |
@@ -447,7 +415,6 @@ mod tests { | |||
447 | CfgOptions::default(), | 415 | CfgOptions::default(), |
448 | Env::default(), | 416 | Env::default(), |
449 | Default::default(), | 417 | Default::default(), |
450 | Default::default(), | ||
451 | ); | 418 | ); |
452 | let crate2 = graph.add_crate_root( | 419 | let crate2 = graph.add_crate_root( |
453 | FileId(2u32), | 420 | FileId(2u32), |
@@ -456,7 +423,6 @@ mod tests { | |||
456 | CfgOptions::default(), | 423 | CfgOptions::default(), |
457 | Env::default(), | 424 | Env::default(), |
458 | Default::default(), | 425 | Default::default(), |
459 | Default::default(), | ||
460 | ); | 426 | ); |
461 | assert!(graph | 427 | assert!(graph |
462 | .add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2) | 428 | .add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2) |
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index 80ddb6058..4a3ba57da 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs | |||
@@ -12,12 +12,13 @@ use rustc_hash::FxHashSet; | |||
12 | pub use crate::{ | 12 | pub use crate::{ |
13 | cancellation::Canceled, | 13 | cancellation::Canceled, |
14 | input::{ | 14 | input::{ |
15 | CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ExternSource, | 15 | CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, FileId, ProcMacroId, |
16 | ExternSourceId, FileId, ProcMacroId, SourceRoot, SourceRootId, | 16 | SourceRoot, SourceRootId, |
17 | }, | 17 | }, |
18 | }; | 18 | }; |
19 | pub use relative_path::{RelativePath, RelativePathBuf}; | 19 | pub use relative_path::{RelativePath, RelativePathBuf}; |
20 | pub use salsa; | 20 | pub use salsa; |
21 | pub use vfs::{file_set::FileSet, AbsPathBuf, VfsPath}; | ||
21 | 22 | ||
22 | #[macro_export] | 23 | #[macro_export] |
23 | macro_rules! impl_intern_key { | 24 | macro_rules! impl_intern_key { |
@@ -113,7 +114,7 @@ pub trait SourceDatabase: CheckCanceled + FileLoader + std::fmt::Debug { | |||
113 | } | 114 | } |
114 | 115 | ||
115 | fn parse_query(db: &impl SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> { | 116 | fn parse_query(db: &impl SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> { |
116 | let _p = profile("parse_query"); | 117 | let _p = profile("parse_query").detail(|| format!("{:?}", file_id)); |
117 | let text = db.file_text(file_id); | 118 | let text = db.file_text(file_id); |
118 | SourceFile::parse(&*text) | 119 | SourceFile::parse(&*text) |
119 | } | 120 | } |
@@ -125,8 +126,6 @@ pub trait SourceDatabaseExt: SourceDatabase { | |||
125 | #[salsa::input] | 126 | #[salsa::input] |
126 | fn file_text(&self, file_id: FileId) -> Arc<String>; | 127 | fn file_text(&self, file_id: FileId) -> Arc<String>; |
127 | /// Path to a file, relative to the root of its source root. | 128 | /// Path to a file, relative to the root of its source root. |
128 | #[salsa::input] | ||
129 | fn file_relative_path(&self, file_id: FileId) -> RelativePathBuf; | ||
130 | /// Source root of the file. | 129 | /// Source root of the file. |
131 | #[salsa::input] | 130 | #[salsa::input] |
132 | fn file_source_root(&self, file_id: FileId) -> SourceRootId; | 131 | fn file_source_root(&self, file_id: FileId) -> SourceRootId; |
@@ -161,24 +160,9 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> { | |||
161 | } | 160 | } |
162 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { | 161 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
163 | // FIXME: this *somehow* should be platform agnostic... | 162 | // FIXME: this *somehow* should be platform agnostic... |
164 | if std::path::Path::new(path).is_absolute() { | 163 | let source_root = self.0.file_source_root(anchor); |
165 | let krate = *self.relevant_crates(anchor).iter().next()?; | 164 | let source_root = self.0.source_root(source_root); |
166 | let (extern_source_id, relative_file) = | 165 | source_root.file_set.resolve_path(anchor, path) |
167 | self.0.crate_graph()[krate].extern_source.extern_path(path.as_ref())?; | ||
168 | |||
169 | let source_root = self.0.source_root(SourceRootId(extern_source_id.0)); | ||
170 | source_root.file_by_relative_path(&relative_file) | ||
171 | } else { | ||
172 | let rel_path = { | ||
173 | let mut rel_path = self.0.file_relative_path(anchor); | ||
174 | assert!(rel_path.pop()); | ||
175 | rel_path.push(path); | ||
176 | rel_path.normalize() | ||
177 | }; | ||
178 | let source_root = self.0.file_source_root(anchor); | ||
179 | let source_root = self.0.source_root(source_root); | ||
180 | source_root.file_by_relative_path(&rel_path) | ||
181 | } | ||
182 | } | 166 | } |
183 | 167 | ||
184 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { | 168 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |