diff options
-rw-r--r-- | crates/ra_db/src/fixture.rs | 12 | ||||
-rw-r--r-- | crates/ra_db/src/input.rs | 43 | ||||
-rw-r--r-- | crates/ra_db/src/lib.rs | 18 | ||||
-rw-r--r-- | crates/ra_hir_def/src/test_db.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/builtin_macro.rs | 182 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/test_db.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/test_db.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/macros.rs | 20 | ||||
-rw-r--r-- | crates/ra_ide/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_ide/src/mock_analysis.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/parent_module.rs | 1 | ||||
-rw-r--r-- | crates/ra_ide_db/src/lib.rs | 7 | ||||
-rw-r--r-- | crates/ra_project_model/src/lib.rs | 25 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/load_cargo.rs | 5 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 4 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 1 | ||||
-rw-r--r-- | crates/rust-analyzer/src/world.rs | 38 | ||||
-rw-r--r-- | editors/code/package.json | 5 | ||||
-rw-r--r-- | editors/code/src/client.ts | 1 | ||||
-rw-r--r-- | editors/code/src/config.ts | 1 |
20 files changed, 320 insertions, 72 deletions
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs index 7f43c2971..3dc86ca2d 100644 --- a/crates/ra_db/src/fixture.rs +++ b/crates/ra_db/src/fixture.rs | |||
@@ -61,7 +61,14 @@ fn with_single_file(db: &mut dyn SourceDatabaseExt, ra_fixture: &str) -> FileId | |||
61 | }; | 61 | }; |
62 | 62 | ||
63 | let mut crate_graph = CrateGraph::default(); | 63 | let mut crate_graph = CrateGraph::default(); |
64 | crate_graph.add_crate_root(file_id, meta.edition, meta.krate, meta.cfg, meta.env); | 64 | crate_graph.add_crate_root( |
65 | file_id, | ||
66 | meta.edition, | ||
67 | meta.krate, | ||
68 | meta.cfg, | ||
69 | meta.env, | ||
70 | Default::default(), | ||
71 | ); | ||
65 | crate_graph | 72 | crate_graph |
66 | } else { | 73 | } else { |
67 | let mut crate_graph = CrateGraph::default(); | 74 | let mut crate_graph = CrateGraph::default(); |
@@ -71,6 +78,7 @@ fn with_single_file(db: &mut dyn SourceDatabaseExt, ra_fixture: &str) -> FileId | |||
71 | None, | 78 | None, |
72 | CfgOptions::default(), | 79 | CfgOptions::default(), |
73 | Env::default(), | 80 | Env::default(), |
81 | Default::default(), | ||
74 | ); | 82 | ); |
75 | crate_graph | 83 | crate_graph |
76 | }; | 84 | }; |
@@ -119,6 +127,7 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit | |||
119 | Some(krate.clone()), | 127 | Some(krate.clone()), |
120 | meta.cfg, | 128 | meta.cfg, |
121 | meta.env, | 129 | meta.env, |
130 | Default::default(), | ||
122 | ); | 131 | ); |
123 | let prev = crates.insert(krate.clone(), crate_id); | 132 | let prev = crates.insert(krate.clone(), crate_id); |
124 | assert!(prev.is_none()); | 133 | assert!(prev.is_none()); |
@@ -155,6 +164,7 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit | |||
155 | None, | 164 | None, |
156 | CfgOptions::default(), | 165 | CfgOptions::default(), |
157 | Env::default(), | 166 | Env::default(), |
167 | Default::default(), | ||
158 | ); | 168 | ); |
159 | } else { | 169 | } else { |
160 | for (from, to) in crate_deps { | 170 | for (from, to) in crate_deps { |
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index 1a1c64202..06d40db96 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs | |||
@@ -113,6 +113,7 @@ pub struct CrateData { | |||
113 | pub display_name: Option<String>, | 113 | pub display_name: Option<String>, |
114 | pub cfg_options: CfgOptions, | 114 | pub cfg_options: CfgOptions, |
115 | pub env: Env, | 115 | pub env: Env, |
116 | pub extern_source: ExternSource, | ||
116 | pub dependencies: Vec<Dependency>, | 117 | pub dependencies: Vec<Dependency>, |
117 | } | 118 | } |
118 | 119 | ||
@@ -122,11 +123,22 @@ pub enum Edition { | |||
122 | Edition2015, | 123 | Edition2015, |
123 | } | 124 | } |
124 | 125 | ||
126 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
127 | pub struct ExternSourceId(pub u32); | ||
128 | |||
125 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | 129 | #[derive(Default, Debug, Clone, PartialEq, Eq)] |
126 | pub struct Env { | 130 | pub struct Env { |
127 | entries: FxHashMap<String, String>, | 131 | entries: FxHashMap<String, String>, |
128 | } | 132 | } |
129 | 133 | ||
134 | // FIXME: Redesign vfs for solve the following limitation ? | ||
135 | // Note: Some env variables (e.g. OUT_DIR) are located outside of the | ||
136 | // crate. We store a map to allow remap it to ExternSourceId | ||
137 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | ||
138 | pub struct ExternSource { | ||
139 | extern_paths: FxHashMap<String, ExternSourceId>, | ||
140 | } | ||
141 | |||
130 | #[derive(Debug, Clone, PartialEq, Eq)] | 142 | #[derive(Debug, Clone, PartialEq, Eq)] |
131 | pub struct Dependency { | 143 | pub struct Dependency { |
132 | pub crate_id: CrateId, | 144 | pub crate_id: CrateId, |
@@ -141,6 +153,7 @@ impl CrateGraph { | |||
141 | display_name: Option<String>, | 153 | display_name: Option<String>, |
142 | cfg_options: CfgOptions, | 154 | cfg_options: CfgOptions, |
143 | env: Env, | 155 | env: Env, |
156 | extern_source: ExternSource, | ||
144 | ) -> CrateId { | 157 | ) -> CrateId { |
145 | let data = CrateData { | 158 | let data = CrateData { |
146 | root_file_id: file_id, | 159 | root_file_id: file_id, |
@@ -148,6 +161,7 @@ impl CrateGraph { | |||
148 | display_name, | 161 | display_name, |
149 | cfg_options, | 162 | cfg_options, |
150 | env, | 163 | env, |
164 | extern_source, | ||
151 | dependencies: Vec::new(), | 165 | dependencies: Vec::new(), |
152 | }; | 166 | }; |
153 | let crate_id = CrateId(self.arena.len() as u32); | 167 | let crate_id = CrateId(self.arena.len() as u32); |
@@ -271,6 +285,27 @@ impl Env { | |||
271 | } | 285 | } |
272 | } | 286 | } |
273 | 287 | ||
288 | impl ExternSource { | ||
289 | pub fn extern_path(&self, path: &str) -> Option<(ExternSourceId, RelativePathBuf)> { | ||
290 | self.extern_paths.iter().find_map(|(root_path, id)| { | ||
291 | if path.starts_with(root_path) { | ||
292 | let mut rel_path = &path[root_path.len()..]; | ||
293 | if rel_path.starts_with("/") { | ||
294 | rel_path = &rel_path[1..]; | ||
295 | } | ||
296 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; | ||
297 | Some((id.clone(), rel_path)) | ||
298 | } else { | ||
299 | None | ||
300 | } | ||
301 | }) | ||
302 | } | ||
303 | |||
304 | pub fn set_extern_path(&mut self, root_path: &str, root: ExternSourceId) { | ||
305 | self.extern_paths.insert(root_path.to_owned(), root); | ||
306 | } | ||
307 | } | ||
308 | |||
274 | #[derive(Debug)] | 309 | #[derive(Debug)] |
275 | pub struct ParseEditionError { | 310 | pub struct ParseEditionError { |
276 | invalid_input: String, | 311 | invalid_input: String, |
@@ -300,6 +335,7 @@ mod tests { | |||
300 | None, | 335 | None, |
301 | CfgOptions::default(), | 336 | CfgOptions::default(), |
302 | Env::default(), | 337 | Env::default(), |
338 | Default::default(), | ||
303 | ); | 339 | ); |
304 | let crate2 = graph.add_crate_root( | 340 | let crate2 = graph.add_crate_root( |
305 | FileId(2u32), | 341 | FileId(2u32), |
@@ -307,6 +343,7 @@ mod tests { | |||
307 | None, | 343 | None, |
308 | CfgOptions::default(), | 344 | CfgOptions::default(), |
309 | Env::default(), | 345 | Env::default(), |
346 | Default::default(), | ||
310 | ); | 347 | ); |
311 | let crate3 = graph.add_crate_root( | 348 | let crate3 = graph.add_crate_root( |
312 | FileId(3u32), | 349 | FileId(3u32), |
@@ -314,6 +351,7 @@ mod tests { | |||
314 | None, | 351 | None, |
315 | CfgOptions::default(), | 352 | CfgOptions::default(), |
316 | Env::default(), | 353 | Env::default(), |
354 | Default::default(), | ||
317 | ); | 355 | ); |
318 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); | 356 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); |
319 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); | 357 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); |
@@ -329,6 +367,7 @@ mod tests { | |||
329 | None, | 367 | None, |
330 | CfgOptions::default(), | 368 | CfgOptions::default(), |
331 | Env::default(), | 369 | Env::default(), |
370 | Default::default(), | ||
332 | ); | 371 | ); |
333 | let crate2 = graph.add_crate_root( | 372 | let crate2 = graph.add_crate_root( |
334 | FileId(2u32), | 373 | FileId(2u32), |
@@ -336,6 +375,7 @@ mod tests { | |||
336 | None, | 375 | None, |
337 | CfgOptions::default(), | 376 | CfgOptions::default(), |
338 | Env::default(), | 377 | Env::default(), |
378 | Default::default(), | ||
339 | ); | 379 | ); |
340 | let crate3 = graph.add_crate_root( | 380 | let crate3 = graph.add_crate_root( |
341 | FileId(3u32), | 381 | FileId(3u32), |
@@ -343,6 +383,7 @@ mod tests { | |||
343 | None, | 383 | None, |
344 | CfgOptions::default(), | 384 | CfgOptions::default(), |
345 | Env::default(), | 385 | Env::default(), |
386 | Default::default(), | ||
346 | ); | 387 | ); |
347 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); | 388 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); |
348 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); | 389 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); |
@@ -357,6 +398,7 @@ mod tests { | |||
357 | None, | 398 | None, |
358 | CfgOptions::default(), | 399 | CfgOptions::default(), |
359 | Env::default(), | 400 | Env::default(), |
401 | Default::default(), | ||
360 | ); | 402 | ); |
361 | let crate2 = graph.add_crate_root( | 403 | let crate2 = graph.add_crate_root( |
362 | FileId(2u32), | 404 | FileId(2u32), |
@@ -364,6 +406,7 @@ mod tests { | |||
364 | None, | 406 | None, |
365 | CfgOptions::default(), | 407 | CfgOptions::default(), |
366 | Env::default(), | 408 | Env::default(), |
409 | Default::default(), | ||
367 | ); | 410 | ); |
368 | assert!(graph | 411 | assert!(graph |
369 | .add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2) | 412 | .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 fb002d717..d500d5e85 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs | |||
@@ -11,7 +11,8 @@ use ra_syntax::{ast, Parse, SourceFile, TextRange, TextUnit}; | |||
11 | pub use crate::{ | 11 | pub use crate::{ |
12 | cancellation::Canceled, | 12 | cancellation::Canceled, |
13 | input::{ | 13 | input::{ |
14 | CrateGraph, CrateId, CrateName, Dependency, Edition, Env, FileId, SourceRoot, SourceRootId, | 14 | CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ExternSource, ExternSourceId, |
15 | FileId, SourceRoot, SourceRootId, | ||
15 | }, | 16 | }, |
16 | }; | 17 | }; |
17 | pub use relative_path::{RelativePath, RelativePathBuf}; | 18 | pub use relative_path::{RelativePath, RelativePathBuf}; |
@@ -87,6 +88,12 @@ pub trait FileLoader { | |||
87 | fn resolve_relative_path(&self, anchor: FileId, relative_path: &RelativePath) | 88 | fn resolve_relative_path(&self, anchor: FileId, relative_path: &RelativePath) |
88 | -> Option<FileId>; | 89 | -> Option<FileId>; |
89 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>>; | 90 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>>; |
91 | |||
92 | fn resolve_extern_path( | ||
93 | &self, | ||
94 | extern_id: ExternSourceId, | ||
95 | relative_path: &RelativePath, | ||
96 | ) -> Option<FileId>; | ||
90 | } | 97 | } |
91 | 98 | ||
92 | /// Database which stores all significant input facts: source code and project | 99 | /// Database which stores all significant input facts: source code and project |
@@ -164,4 +171,13 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> { | |||
164 | let source_root = self.0.file_source_root(file_id); | 171 | let source_root = self.0.file_source_root(file_id); |
165 | self.0.source_root_crates(source_root) | 172 | self.0.source_root_crates(source_root) |
166 | } | 173 | } |
174 | |||
175 | fn resolve_extern_path( | ||
176 | &self, | ||
177 | extern_id: ExternSourceId, | ||
178 | relative_path: &RelativePath, | ||
179 | ) -> Option<FileId> { | ||
180 | let source_root = self.0.source_root(SourceRootId(extern_id.0)); | ||
181 | source_root.file_by_relative_path(&relative_path) | ||
182 | } | ||
167 | } | 183 | } |
diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs index 1568820e9..0756916a8 100644 --- a/crates/ra_hir_def/src/test_db.rs +++ b/crates/ra_hir_def/src/test_db.rs | |||
@@ -6,7 +6,7 @@ use std::{ | |||
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::db::DefDatabase; | 8 | use crate::db::DefDatabase; |
9 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; | 9 | use ra_db::{salsa, CrateId, ExternSourceId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; |
10 | 10 | ||
11 | #[salsa::database( | 11 | #[salsa::database( |
12 | ra_db::SourceDatabaseExtStorage, | 12 | ra_db::SourceDatabaseExtStorage, |
@@ -52,6 +52,14 @@ impl FileLoader for TestDB { | |||
52 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 52 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { |
53 | FileLoaderDelegate(self).relevant_crates(file_id) | 53 | FileLoaderDelegate(self).relevant_crates(file_id) |
54 | } | 54 | } |
55 | |||
56 | fn resolve_extern_path( | ||
57 | &self, | ||
58 | extern_id: ExternSourceId, | ||
59 | relative_path: &RelativePath, | ||
60 | ) -> Option<FileId> { | ||
61 | FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path) | ||
62 | } | ||
55 | } | 63 | } |
56 | 64 | ||
57 | impl TestDB { | 65 | impl TestDB { |
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index 3f60b1cca..a90007f26 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs | |||
@@ -90,15 +90,15 @@ register_builtin! { | |||
90 | (line, Line) => line_expand, | 90 | (line, Line) => line_expand, |
91 | (stringify, Stringify) => stringify_expand, | 91 | (stringify, Stringify) => stringify_expand, |
92 | (format_args, FormatArgs) => format_args_expand, | 92 | (format_args, FormatArgs) => format_args_expand, |
93 | (env, Env) => env_expand, | ||
94 | (option_env, OptionEnv) => option_env_expand, | ||
95 | // format_args_nl only differs in that it adds a newline in the end, | 93 | // format_args_nl only differs in that it adds a newline in the end, |
96 | // so we use the same stub expansion for now | 94 | // so we use the same stub expansion for now |
97 | (format_args_nl, FormatArgsNl) => format_args_expand, | 95 | (format_args_nl, FormatArgsNl) => format_args_expand, |
98 | 96 | ||
99 | EAGER: | 97 | EAGER: |
100 | (concat, Concat) => concat_expand, | 98 | (concat, Concat) => concat_expand, |
101 | (include, Include) => include_expand | 99 | (include, Include) => include_expand, |
100 | (env, Env) => env_expand, | ||
101 | (option_env, OptionEnv) => option_env_expand | ||
102 | } | 102 | } |
103 | 103 | ||
104 | fn line_expand( | 104 | fn line_expand( |
@@ -137,31 +137,6 @@ fn stringify_expand( | |||
137 | Ok(expanded) | 137 | Ok(expanded) |
138 | } | 138 | } |
139 | 139 | ||
140 | fn env_expand( | ||
141 | _db: &dyn AstDatabase, | ||
142 | _id: LazyMacroId, | ||
143 | _tt: &tt::Subtree, | ||
144 | ) -> Result<tt::Subtree, mbe::ExpandError> { | ||
145 | // dummy implementation for type-checking purposes | ||
146 | // we cannot use an empty string here, because for | ||
147 | // `include!(concat!(env!("OUT_DIR"), "/foo.rs"))` will become | ||
148 | // `include!("foo.rs"), which maybe infinite loop | ||
149 | let expanded = quote! { "__RA_UNIMPLEMENTATED__" }; | ||
150 | |||
151 | Ok(expanded) | ||
152 | } | ||
153 | |||
154 | fn option_env_expand( | ||
155 | _db: &dyn AstDatabase, | ||
156 | _id: LazyMacroId, | ||
157 | _tt: &tt::Subtree, | ||
158 | ) -> Result<tt::Subtree, mbe::ExpandError> { | ||
159 | // dummy implementation for type-checking purposes | ||
160 | let expanded = quote! { std::option::Option::None::<&str> }; | ||
161 | |||
162 | Ok(expanded) | ||
163 | } | ||
164 | |||
165 | fn column_expand( | 140 | fn column_expand( |
166 | _db: &dyn AstDatabase, | 141 | _db: &dyn AstDatabase, |
167 | _id: LazyMacroId, | 142 | _id: LazyMacroId, |
@@ -278,30 +253,37 @@ fn concat_expand( | |||
278 | 253 | ||
279 | fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Option<FileId> { | 254 | fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Option<FileId> { |
280 | let call_site = call_id.as_file().original_file(db); | 255 | let call_site = call_id.as_file().original_file(db); |
281 | let path = RelativePath::new(&path); | ||
282 | 256 | ||
283 | let res = db.resolve_relative_path(call_site, &path)?; | 257 | // Handle trivial case |
284 | // Prevent include itself | 258 | if let Some(res) = db.resolve_relative_path(call_site, &RelativePath::new(&path)) { |
285 | if res == call_site { | 259 | // Prevent include itself |
286 | return None; | 260 | return if res == call_site { None } else { Some(res) }; |
287 | } | 261 | } |
288 | Some(res) | 262 | |
263 | // Extern paths ? | ||
264 | let krate = db.relevant_crates(call_site).get(0)?.clone(); | ||
265 | let (extern_source_id, relative_file) = | ||
266 | db.crate_graph()[krate].extern_source.extern_path(path)?; | ||
267 | |||
268 | db.resolve_extern_path(extern_source_id, &relative_file) | ||
289 | } | 269 | } |
290 | 270 | ||
291 | fn include_expand( | 271 | fn parse_string(tt: &tt::Subtree) -> Result<String, mbe::ExpandError> { |
292 | db: &dyn AstDatabase, | 272 | tt.token_trees |
293 | arg_id: EagerMacroId, | ||
294 | tt: &tt::Subtree, | ||
295 | ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { | ||
296 | let path = tt | ||
297 | .token_trees | ||
298 | .get(0) | 273 | .get(0) |
299 | .and_then(|tt| match tt { | 274 | .and_then(|tt| match tt { |
300 | tt::TokenTree::Leaf(tt::Leaf::Literal(it)) => unquote_str(&it), | 275 | tt::TokenTree::Leaf(tt::Leaf::Literal(it)) => unquote_str(&it), |
301 | _ => None, | 276 | _ => None, |
302 | }) | 277 | }) |
303 | .ok_or_else(|| mbe::ExpandError::ConversionError)?; | 278 | .ok_or_else(|| mbe::ExpandError::ConversionError) |
279 | } | ||
304 | 280 | ||
281 | fn include_expand( | ||
282 | db: &dyn AstDatabase, | ||
283 | arg_id: EagerMacroId, | ||
284 | tt: &tt::Subtree, | ||
285 | ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { | ||
286 | let path = parse_string(tt)?; | ||
305 | let file_id = | 287 | let file_id = |
306 | relative_file(db, arg_id.into(), &path).ok_or_else(|| mbe::ExpandError::ConversionError)?; | 288 | relative_file(db, arg_id.into(), &path).ok_or_else(|| mbe::ExpandError::ConversionError)?; |
307 | 289 | ||
@@ -314,12 +296,58 @@ fn include_expand( | |||
314 | Ok((res, FragmentKind::Items)) | 296 | Ok((res, FragmentKind::Items)) |
315 | } | 297 | } |
316 | 298 | ||
299 | fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { | ||
300 | let call_id: MacroCallId = arg_id.into(); | ||
301 | let original_file = call_id.as_file().original_file(db); | ||
302 | |||
303 | let krate = db.relevant_crates(original_file).get(0)?.clone(); | ||
304 | db.crate_graph()[krate].env.get(key) | ||
305 | } | ||
306 | |||
307 | fn env_expand( | ||
308 | db: &dyn AstDatabase, | ||
309 | arg_id: EagerMacroId, | ||
310 | tt: &tt::Subtree, | ||
311 | ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { | ||
312 | let key = parse_string(tt)?; | ||
313 | |||
314 | // FIXME: | ||
315 | // If the environment variable is not defined int rustc, then a compilation error will be emitted. | ||
316 | // We might do the same if we fully support all other stuffs. | ||
317 | // But for now on, we should return some dummy string for better type infer purpose. | ||
318 | // However, we cannot use an empty string here, because for | ||
319 | // `include!(concat!(env!("OUT_DIR"), "/foo.rs"))` will become | ||
320 | // `include!("foo.rs"), which might go to infinite loop | ||
321 | let s = get_env_inner(db, arg_id, &key).unwrap_or("__RA_UNIMPLEMENTATED__".to_string()); | ||
322 | let expanded = quote! { #s }; | ||
323 | |||
324 | Ok((expanded, FragmentKind::Expr)) | ||
325 | } | ||
326 | |||
327 | fn option_env_expand( | ||
328 | db: &dyn AstDatabase, | ||
329 | arg_id: EagerMacroId, | ||
330 | tt: &tt::Subtree, | ||
331 | ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { | ||
332 | let key = parse_string(tt)?; | ||
333 | let expanded = match get_env_inner(db, arg_id, &key) { | ||
334 | None => quote! { std::option::Option::None::<&str> }, | ||
335 | Some(s) => quote! { std::option::Some(#s) }, | ||
336 | }; | ||
337 | |||
338 | Ok((expanded, FragmentKind::Expr)) | ||
339 | } | ||
340 | |||
317 | #[cfg(test)] | 341 | #[cfg(test)] |
318 | mod tests { | 342 | mod tests { |
319 | use super::*; | 343 | use super::*; |
320 | use crate::{name::AsName, test_db::TestDB, AstNode, MacroCallId, MacroCallKind, MacroCallLoc}; | 344 | use crate::{ |
345 | name::AsName, test_db::TestDB, AstNode, EagerCallLoc, MacroCallId, MacroCallKind, | ||
346 | MacroCallLoc, | ||
347 | }; | ||
321 | use ra_db::{fixture::WithFixture, SourceDatabase}; | 348 | use ra_db::{fixture::WithFixture, SourceDatabase}; |
322 | use ra_syntax::ast::NameOwner; | 349 | use ra_syntax::ast::NameOwner; |
350 | use std::sync::Arc; | ||
323 | 351 | ||
324 | fn expand_builtin_macro(ra_fixture: &str) -> String { | 352 | fn expand_builtin_macro(ra_fixture: &str) -> String { |
325 | let (db, file_id) = TestDB::with_single_file(&ra_fixture); | 353 | let (db, file_id) = TestDB::with_single_file(&ra_fixture); |
@@ -330,27 +358,61 @@ mod tests { | |||
330 | let ast_id_map = db.ast_id_map(file_id.into()); | 358 | let ast_id_map = db.ast_id_map(file_id.into()); |
331 | 359 | ||
332 | let expander = find_by_name(¯o_calls[0].name().unwrap().as_name()).unwrap(); | 360 | let expander = find_by_name(¯o_calls[0].name().unwrap().as_name()).unwrap(); |
333 | let expander = expander.left().unwrap(); | ||
334 | 361 | ||
335 | // the first one should be a macro_rules | 362 | let file_id = match expander { |
336 | let def = MacroDefId { | 363 | Either::Left(expander) => { |
337 | krate: Some(CrateId(0)), | 364 | // the first one should be a macro_rules |
338 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), | 365 | let def = MacroDefId { |
339 | kind: MacroDefKind::BuiltIn(expander), | 366 | krate: Some(CrateId(0)), |
340 | }; | 367 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), |
368 | kind: MacroDefKind::BuiltIn(expander), | ||
369 | }; | ||
341 | 370 | ||
342 | let loc = MacroCallLoc { | 371 | let loc = MacroCallLoc { |
343 | def, | 372 | def, |
344 | kind: MacroCallKind::FnLike(AstId::new( | 373 | kind: MacroCallKind::FnLike(AstId::new( |
345 | file_id.into(), | 374 | file_id.into(), |
346 | ast_id_map.ast_id(¯o_calls[1]), | 375 | ast_id_map.ast_id(¯o_calls[1]), |
347 | )), | 376 | )), |
348 | }; | 377 | }; |
378 | |||
379 | let id: MacroCallId = db.intern_macro(loc).into(); | ||
380 | id.as_file() | ||
381 | } | ||
382 | Either::Right(expander) => { | ||
383 | // the first one should be a macro_rules | ||
384 | let def = MacroDefId { | ||
385 | krate: Some(CrateId(0)), | ||
386 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), | ||
387 | kind: MacroDefKind::BuiltInEager(expander), | ||
388 | }; | ||
349 | 389 | ||
350 | let id: MacroCallId = db.intern_macro(loc).into(); | 390 | let args = macro_calls[1].token_tree().unwrap(); |
351 | let parsed = db.parse_or_expand(id.as_file()).unwrap(); | 391 | let parsed_args = mbe::ast_to_token_tree(&args).unwrap().0; |
392 | |||
393 | let arg_id = db.intern_eager_expansion({ | ||
394 | EagerCallLoc { | ||
395 | def, | ||
396 | fragment: FragmentKind::Expr, | ||
397 | subtree: Arc::new(parsed_args.clone()), | ||
398 | file_id: file_id.into(), | ||
399 | } | ||
400 | }); | ||
401 | |||
402 | let (subtree, fragment) = expander.expand(&db, arg_id, &parsed_args).unwrap(); | ||
403 | let eager = EagerCallLoc { | ||
404 | def, | ||
405 | fragment, | ||
406 | subtree: Arc::new(subtree), | ||
407 | file_id: file_id.into(), | ||
408 | }; | ||
409 | |||
410 | let id: MacroCallId = db.intern_eager_expansion(eager.into()).into(); | ||
411 | id.as_file() | ||
412 | } | ||
413 | }; | ||
352 | 414 | ||
353 | parsed.text().to_string() | 415 | db.parse_or_expand(file_id).unwrap().to_string() |
354 | } | 416 | } |
355 | 417 | ||
356 | #[test] | 418 | #[test] |
diff --git a/crates/ra_hir_expand/src/test_db.rs b/crates/ra_hir_expand/src/test_db.rs index 918736e2a..c1fb762de 100644 --- a/crates/ra_hir_expand/src/test_db.rs +++ b/crates/ra_hir_expand/src/test_db.rs | |||
@@ -5,7 +5,7 @@ use std::{ | |||
5 | sync::{Arc, Mutex}, | 5 | sync::{Arc, Mutex}, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; | 8 | use ra_db::{salsa, CrateId, ExternSourceId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; |
9 | 9 | ||
10 | #[salsa::database( | 10 | #[salsa::database( |
11 | ra_db::SourceDatabaseExtStorage, | 11 | ra_db::SourceDatabaseExtStorage, |
@@ -51,4 +51,11 @@ impl FileLoader for TestDB { | |||
51 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 51 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { |
52 | FileLoaderDelegate(self).relevant_crates(file_id) | 52 | FileLoaderDelegate(self).relevant_crates(file_id) |
53 | } | 53 | } |
54 | fn resolve_extern_path( | ||
55 | &self, | ||
56 | anchor: ExternSourceId, | ||
57 | relative_path: &RelativePath, | ||
58 | ) -> Option<FileId> { | ||
59 | FileLoaderDelegate(self).resolve_extern_path(anchor, relative_path) | ||
60 | } | ||
54 | } | 61 | } |
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs index c794f7b84..0be2fea4b 100644 --- a/crates/ra_hir_ty/src/test_db.rs +++ b/crates/ra_hir_ty/src/test_db.rs | |||
@@ -67,6 +67,13 @@ impl FileLoader for TestDB { | |||
67 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 67 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { |
68 | FileLoaderDelegate(self).relevant_crates(file_id) | 68 | FileLoaderDelegate(self).relevant_crates(file_id) |
69 | } | 69 | } |
70 | fn resolve_extern_path( | ||
71 | &self, | ||
72 | extern_id: ra_db::ExternSourceId, | ||
73 | relative_path: &RelativePath, | ||
74 | ) -> Option<FileId> { | ||
75 | FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path) | ||
76 | } | ||
70 | } | 77 | } |
71 | 78 | ||
72 | impl TestDB { | 79 | impl TestDB { |
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index ffa78b046..32457bbf7 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs | |||
@@ -550,6 +550,26 @@ fn main() { | |||
550 | } | 550 | } |
551 | 551 | ||
552 | #[test] | 552 | #[test] |
553 | fn infer_builtin_macros_env() { | ||
554 | assert_snapshot!( | ||
555 | infer(r#" | ||
556 | //- /main.rs env:foo=bar | ||
557 | #[rustc_builtin_macro] | ||
558 | macro_rules! env {() => {}} | ||
559 | |||
560 | fn main() { | ||
561 | let x = env!("foo"); | ||
562 | } | ||
563 | "#), | ||
564 | @r###" | ||
565 | ![0; 5) '"bar"': &str | ||
566 | [88; 116) '{ ...o"); }': () | ||
567 | [98; 99) 'x': &str | ||
568 | "### | ||
569 | ); | ||
570 | } | ||
571 | |||
572 | #[test] | ||
553 | fn infer_derive_clone_simple() { | 573 | fn infer_derive_clone_simple() { |
554 | let (db, pos) = TestDB::with_position( | 574 | let (db, pos) = TestDB::with_position( |
555 | r#" | 575 | r#" |
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 9f45003d3..015fae195 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs | |||
@@ -212,6 +212,7 @@ impl Analysis { | |||
212 | None, | 212 | None, |
213 | cfg_options, | 213 | cfg_options, |
214 | Env::default(), | 214 | Env::default(), |
215 | Default::default(), | ||
215 | ); | 216 | ); |
216 | change.add_file(source_root, file_id, "main.rs".into(), Arc::new(text)); | 217 | change.add_file(source_root, file_id, "main.rs".into(), Arc::new(text)); |
217 | change.set_crate_graph(crate_graph); | 218 | change.set_crate_graph(crate_graph); |
diff --git a/crates/ra_ide/src/mock_analysis.rs b/crates/ra_ide/src/mock_analysis.rs index 90f84b052..25816cf6f 100644 --- a/crates/ra_ide/src/mock_analysis.rs +++ b/crates/ra_ide/src/mock_analysis.rs | |||
@@ -102,6 +102,7 @@ impl MockAnalysis { | |||
102 | None, | 102 | None, |
103 | cfg_options, | 103 | cfg_options, |
104 | Env::default(), | 104 | Env::default(), |
105 | Default::default(), | ||
105 | )); | 106 | )); |
106 | } else if path.ends_with("/lib.rs") { | 107 | } else if path.ends_with("/lib.rs") { |
107 | let crate_name = path.parent().unwrap().file_name().unwrap(); | 108 | let crate_name = path.parent().unwrap().file_name().unwrap(); |
@@ -111,6 +112,7 @@ impl MockAnalysis { | |||
111 | Some(crate_name.to_owned()), | 112 | Some(crate_name.to_owned()), |
112 | cfg_options, | 113 | cfg_options, |
113 | Env::default(), | 114 | Env::default(), |
115 | Default::default(), | ||
114 | ); | 116 | ); |
115 | if let Some(root_crate) = root_crate { | 117 | if let Some(root_crate) = root_crate { |
116 | crate_graph | 118 | crate_graph |
diff --git a/crates/ra_ide/src/parent_module.rs b/crates/ra_ide/src/parent_module.rs index b73cefd97..76d130b9b 100644 --- a/crates/ra_ide/src/parent_module.rs +++ b/crates/ra_ide/src/parent_module.rs | |||
@@ -136,6 +136,7 @@ mod tests { | |||
136 | None, | 136 | None, |
137 | CfgOptions::default(), | 137 | CfgOptions::default(), |
138 | Env::default(), | 138 | Env::default(), |
139 | Default::default(), | ||
139 | ); | 140 | ); |
140 | let mut change = AnalysisChange::new(); | 141 | let mut change = AnalysisChange::new(); |
141 | change.set_crate_graph(crate_graph); | 142 | change.set_crate_graph(crate_graph); |
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs index 6bcccc848..fc1b19def 100644 --- a/crates/ra_ide_db/src/lib.rs +++ b/crates/ra_ide_db/src/lib.rs | |||
@@ -55,6 +55,13 @@ impl FileLoader for RootDatabase { | |||
55 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 55 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { |
56 | FileLoaderDelegate(self).relevant_crates(file_id) | 56 | FileLoaderDelegate(self).relevant_crates(file_id) |
57 | } | 57 | } |
58 | fn resolve_extern_path( | ||
59 | &self, | ||
60 | extern_id: ra_db::ExternSourceId, | ||
61 | relative_path: &RelativePath, | ||
62 | ) -> Option<FileId> { | ||
63 | FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path) | ||
64 | } | ||
58 | } | 65 | } |
59 | 66 | ||
60 | impl salsa::Database for RootDatabase { | 67 | impl salsa::Database for RootDatabase { |
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 37845ca56..a6274709d 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs | |||
@@ -14,7 +14,7 @@ use std::{ | |||
14 | 14 | ||
15 | use anyhow::{bail, Context, Result}; | 15 | use anyhow::{bail, Context, Result}; |
16 | use ra_cfg::CfgOptions; | 16 | use ra_cfg::CfgOptions; |
17 | use ra_db::{CrateGraph, CrateName, Edition, Env, FileId}; | 17 | use ra_db::{CrateGraph, CrateName, Edition, Env, ExternSource, ExternSourceId, FileId}; |
18 | use rustc_hash::FxHashMap; | 18 | use rustc_hash::FxHashMap; |
19 | use serde_json::from_reader; | 19 | use serde_json::from_reader; |
20 | 20 | ||
@@ -162,6 +162,7 @@ impl ProjectWorkspace { | |||
162 | pub fn to_crate_graph( | 162 | pub fn to_crate_graph( |
163 | &self, | 163 | &self, |
164 | default_cfg_options: &CfgOptions, | 164 | default_cfg_options: &CfgOptions, |
165 | outdirs: &FxHashMap<String, (ExternSourceId, String)>, | ||
165 | load: &mut dyn FnMut(&Path) -> Option<FileId>, | 166 | load: &mut dyn FnMut(&Path) -> Option<FileId>, |
166 | ) -> CrateGraph { | 167 | ) -> CrateGraph { |
167 | let mut crate_graph = CrateGraph::default(); | 168 | let mut crate_graph = CrateGraph::default(); |
@@ -185,6 +186,8 @@ impl ProjectWorkspace { | |||
185 | } | 186 | } |
186 | opts | 187 | opts |
187 | }; | 188 | }; |
189 | |||
190 | // FIXME: No crate name in json definition such that we cannot add OUT_DIR to env | ||
188 | crates.insert( | 191 | crates.insert( |
189 | crate_id, | 192 | crate_id, |
190 | crate_graph.add_crate_root( | 193 | crate_graph.add_crate_root( |
@@ -194,6 +197,7 @@ impl ProjectWorkspace { | |||
194 | None, | 197 | None, |
195 | cfg_options, | 198 | cfg_options, |
196 | Env::default(), | 199 | Env::default(), |
200 | Default::default(), | ||
197 | ), | 201 | ), |
198 | ); | 202 | ); |
199 | } | 203 | } |
@@ -231,12 +235,20 @@ impl ProjectWorkspace { | |||
231 | opts | 235 | opts |
232 | }; | 236 | }; |
233 | 237 | ||
238 | let mut env = Env::default(); | ||
239 | let mut extern_source = ExternSource::default(); | ||
240 | if let Some((id, path)) = outdirs.get(krate.name(&sysroot)) { | ||
241 | env.set("OUT_DIR", path.clone()); | ||
242 | extern_source.set_extern_path(&path, *id); | ||
243 | } | ||
244 | |||
234 | let crate_id = crate_graph.add_crate_root( | 245 | let crate_id = crate_graph.add_crate_root( |
235 | file_id, | 246 | file_id, |
236 | Edition::Edition2018, | 247 | Edition::Edition2018, |
237 | Some(krate.name(&sysroot).to_string()), | 248 | Some(krate.name(&sysroot).to_string()), |
238 | cfg_options, | 249 | cfg_options, |
239 | Env::default(), | 250 | env, |
251 | extern_source, | ||
240 | ); | 252 | ); |
241 | sysroot_crates.insert(krate, crate_id); | 253 | sysroot_crates.insert(krate, crate_id); |
242 | } | 254 | } |
@@ -275,12 +287,19 @@ impl ProjectWorkspace { | |||
275 | opts.insert_features(pkg.features(&cargo).iter().map(Into::into)); | 287 | opts.insert_features(pkg.features(&cargo).iter().map(Into::into)); |
276 | opts | 288 | opts |
277 | }; | 289 | }; |
290 | let mut env = Env::default(); | ||
291 | let mut extern_source = ExternSource::default(); | ||
292 | if let Some((id, path)) = outdirs.get(pkg.name(&cargo)) { | ||
293 | env.set("OUT_DIR", path.clone()); | ||
294 | extern_source.set_extern_path(&path, *id); | ||
295 | } | ||
278 | let crate_id = crate_graph.add_crate_root( | 296 | let crate_id = crate_graph.add_crate_root( |
279 | file_id, | 297 | file_id, |
280 | edition, | 298 | edition, |
281 | Some(pkg.name(&cargo).to_string()), | 299 | Some(pkg.name(&cargo).to_string()), |
282 | cfg_options, | 300 | cfg_options, |
283 | Env::default(), | 301 | env, |
302 | extern_source, | ||
284 | ); | 303 | ); |
285 | if tgt.kind(&cargo) == TargetKind::Lib { | 304 | if tgt.kind(&cargo) == TargetKind::Lib { |
286 | lib_tgt = Some(crate_id); | 305 | lib_tgt = Some(crate_id); |
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 5df29a383..2ce69c9b3 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs | |||
@@ -52,7 +52,10 @@ pub(crate) fn load_cargo( | |||
52 | opts | 52 | opts |
53 | }; | 53 | }; |
54 | 54 | ||
55 | let crate_graph = ws.to_crate_graph(&default_cfg_options, &mut |path: &Path| { | 55 | // FIXME: outdirs? |
56 | let outdirs = FxHashMap::default(); | ||
57 | |||
58 | let crate_graph = ws.to_crate_graph(&default_cfg_options, &outdirs, &mut |path: &Path| { | ||
56 | let vfs_file = vfs.load(path); | 59 | let vfs_file = vfs.load(path); |
57 | log::debug!("vfs file {:?} -> {:?}", path, vfs_file); | 60 | log::debug!("vfs file {:?} -> {:?}", path, vfs_file); |
58 | vfs_file.map(vfs_file_to_id) | 61 | vfs_file.map(vfs_file_to_id) |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 3314269ec..a8bf29ddf 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -44,6 +44,9 @@ pub struct ServerConfig { | |||
44 | /// Fine grained feature flags to disable specific features. | 44 | /// Fine grained feature flags to disable specific features. |
45 | pub feature_flags: FxHashMap<String, bool>, | 45 | pub feature_flags: FxHashMap<String, bool>, |
46 | 46 | ||
47 | /// Fine grained controls for additional `OUT_DIR` env variables | ||
48 | pub additional_out_dirs: FxHashMap<String, String>, | ||
49 | |||
47 | pub rustfmt_args: Vec<String>, | 50 | pub rustfmt_args: Vec<String>, |
48 | 51 | ||
49 | /// Cargo feature configurations. | 52 | /// Cargo feature configurations. |
@@ -64,6 +67,7 @@ impl Default for ServerConfig { | |||
64 | cargo_watch_all_targets: true, | 67 | cargo_watch_all_targets: true, |
65 | with_sysroot: true, | 68 | with_sysroot: true, |
66 | feature_flags: FxHashMap::default(), | 69 | feature_flags: FxHashMap::default(), |
70 | additional_out_dirs: FxHashMap::default(), | ||
67 | cargo_features: Default::default(), | 71 | cargo_features: Default::default(), |
68 | rustfmt_args: Vec::new(), | 72 | rustfmt_args: Vec::new(), |
69 | } | 73 | } |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index f9de712a0..4f7aac754 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -196,6 +196,7 @@ pub fn main_loop( | |||
196 | Watch(!config.use_client_watching), | 196 | Watch(!config.use_client_watching), |
197 | options, | 197 | options, |
198 | feature_flags, | 198 | feature_flags, |
199 | config.additional_out_dirs, | ||
199 | ) | 200 | ) |
200 | }; | 201 | }; |
201 | 202 | ||
diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs index 1ddc3c1a5..9ef368529 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs | |||
@@ -26,6 +26,8 @@ use crate::{ | |||
26 | vfs_glob::{Glob, RustPackageFilterBuilder}, | 26 | vfs_glob::{Glob, RustPackageFilterBuilder}, |
27 | LspError, Result, | 27 | LspError, Result, |
28 | }; | 28 | }; |
29 | use ra_db::ExternSourceId; | ||
30 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
29 | 31 | ||
30 | #[derive(Debug, Clone)] | 32 | #[derive(Debug, Clone)] |
31 | pub struct Options { | 33 | pub struct Options { |
@@ -78,6 +80,7 @@ impl WorldState { | |||
78 | watch: Watch, | 80 | watch: Watch, |
79 | options: Options, | 81 | options: Options, |
80 | feature_flags: FeatureFlags, | 82 | feature_flags: FeatureFlags, |
83 | additional_out_dirs: FxHashMap<String, String>, | ||
81 | ) -> WorldState { | 84 | ) -> WorldState { |
82 | let mut change = AnalysisChange::new(); | 85 | let mut change = AnalysisChange::new(); |
83 | 86 | ||
@@ -99,6 +102,19 @@ impl WorldState { | |||
99 | RootEntry::new(pkg_root.path().clone(), filter.into_vfs_filter()) | 102 | RootEntry::new(pkg_root.path().clone(), filter.into_vfs_filter()) |
100 | })); | 103 | })); |
101 | } | 104 | } |
105 | |||
106 | let extern_dirs: FxHashSet<_> = | ||
107 | additional_out_dirs.iter().map(|(_, path)| (PathBuf::from(path))).collect(); | ||
108 | let mut extern_source_roots = FxHashMap::default(); | ||
109 | |||
110 | roots.extend(additional_out_dirs.iter().map(|(_, path)| { | ||
111 | let mut filter = RustPackageFilterBuilder::default().set_member(false); | ||
112 | for glob in exclude_globs.iter() { | ||
113 | filter = filter.exclude(glob.clone()); | ||
114 | } | ||
115 | RootEntry::new(PathBuf::from(&path), filter.into_vfs_filter()) | ||
116 | })); | ||
117 | |||
102 | let (task_sender, task_receiver) = unbounded(); | 118 | let (task_sender, task_receiver) = unbounded(); |
103 | let task_sender = Box::new(move |t| task_sender.send(t).unwrap()); | 119 | let task_sender = Box::new(move |t| task_sender.send(t).unwrap()); |
104 | let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender, watch); | 120 | let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender, watch); |
@@ -108,6 +124,11 @@ impl WorldState { | |||
108 | let is_local = folder_roots.iter().any(|it| vfs_root_path.starts_with(it)); | 124 | let is_local = folder_roots.iter().any(|it| vfs_root_path.starts_with(it)); |
109 | change.add_root(SourceRootId(r.0), is_local); | 125 | change.add_root(SourceRootId(r.0), is_local); |
110 | change.set_debug_root_path(SourceRootId(r.0), vfs_root_path.display().to_string()); | 126 | change.set_debug_root_path(SourceRootId(r.0), vfs_root_path.display().to_string()); |
127 | |||
128 | // FIXME: add path2root in vfs to simpily this logic | ||
129 | if extern_dirs.contains(&vfs_root_path) { | ||
130 | extern_source_roots.insert(vfs_root_path, ExternSourceId(r.0)); | ||
131 | } | ||
111 | } | 132 | } |
112 | 133 | ||
113 | // FIXME: Read default cfgs from config | 134 | // FIXME: Read default cfgs from config |
@@ -125,11 +146,20 @@ impl WorldState { | |||
125 | vfs_file.map(|f| FileId(f.0)) | 146 | vfs_file.map(|f| FileId(f.0)) |
126 | }; | 147 | }; |
127 | 148 | ||
128 | workspaces.iter().map(|ws| ws.to_crate_graph(&default_cfg_options, &mut load)).for_each( | 149 | let mut outdirs = FxHashMap::default(); |
129 | |graph| { | 150 | for (name, path) in additional_out_dirs { |
151 | let path = PathBuf::from(&path); | ||
152 | if let Some(id) = extern_source_roots.get(&path) { | ||
153 | outdirs.insert(name, (id.clone(), path.to_string_lossy().replace("\\", "/"))); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | workspaces | ||
158 | .iter() | ||
159 | .map(|ws| ws.to_crate_graph(&default_cfg_options, &outdirs, &mut load)) | ||
160 | .for_each(|graph| { | ||
130 | crate_graph.extend(graph); | 161 | crate_graph.extend(graph); |
131 | }, | 162 | }); |
132 | ); | ||
133 | change.set_crate_graph(crate_graph); | 163 | change.set_crate_graph(crate_graph); |
134 | 164 | ||
135 | // FIXME: Figure out the multi-workspace situation | 165 | // FIXME: Figure out the multi-workspace situation |
diff --git a/editors/code/package.json b/editors/code/package.json index 512885454..1fe8e9f8a 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -224,6 +224,11 @@ | |||
224 | "default": true, | 224 | "default": true, |
225 | "description": "Whether to ask for permission before downloading any files from the Internet" | 225 | "description": "Whether to ask for permission before downloading any files from the Internet" |
226 | }, | 226 | }, |
227 | "rust-analyzer.additionalOutDirs": { | ||
228 | "type": "object", | ||
229 | "default": {}, | ||
230 | "markdownDescription": "Fine grained controls for OUT_DIR `env!(\"OUT_DIR\")` variable. e.g. `{\"foo\":\"/path/to/foo\"}`, " | ||
231 | }, | ||
227 | "rust-analyzer.serverPath": { | 232 | "rust-analyzer.serverPath": { |
228 | "type": [ | 233 | "type": [ |
229 | "null", | 234 | "null", |
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 540f7c9ea..6ce3b9235 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts | |||
@@ -37,6 +37,7 @@ export async function createClient(config: Config, serverPath: string): Promise< | |||
37 | excludeGlobs: config.excludeGlobs, | 37 | excludeGlobs: config.excludeGlobs, |
38 | useClientWatching: config.useClientWatching, | 38 | useClientWatching: config.useClientWatching, |
39 | featureFlags: config.featureFlags, | 39 | featureFlags: config.featureFlags, |
40 | additionalOutDirs: config.additionalOutDirs, | ||
40 | withSysroot: config.withSysroot, | 41 | withSysroot: config.withSysroot, |
41 | cargoFeatures: config.cargoFeatures, | 42 | cargoFeatures: config.cargoFeatures, |
42 | rustfmtArgs: config.rustfmtArgs, | 43 | rustfmtArgs: config.rustfmtArgs, |
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index b72206d3c..3ade7e900 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts | |||
@@ -154,6 +154,7 @@ export class Config { | |||
154 | get excludeGlobs() { return this.cfg.get("excludeGlobs") as string[]; } | 154 | get excludeGlobs() { return this.cfg.get("excludeGlobs") as string[]; } |
155 | get useClientWatching() { return this.cfg.get("useClientWatching") as boolean; } | 155 | get useClientWatching() { return this.cfg.get("useClientWatching") as boolean; } |
156 | get featureFlags() { return this.cfg.get("featureFlags") as Record<string, boolean>; } | 156 | get featureFlags() { return this.cfg.get("featureFlags") as Record<string, boolean>; } |
157 | get additionalOutDirs() { return this.cfg.get("additionalOutDirs") as Record<string, string>; } | ||
157 | get rustfmtArgs() { return this.cfg.get("rustfmtArgs") as string[]; } | 158 | get rustfmtArgs() { return this.cfg.get("rustfmtArgs") as string[]; } |
158 | 159 | ||
159 | get cargoWatchOptions(): CargoWatchOptions { | 160 | get cargoWatchOptions(): CargoWatchOptions { |