diff options
-rw-r--r-- | crates/base_db/src/input.rs | 19 | ||||
-rw-r--r-- | crates/base_db/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/hir_expand/src/db.rs | 2 | ||||
-rw-r--r-- | crates/hir_expand/src/proc_macro.rs | 9 | ||||
-rw-r--r-- | crates/proc_macro_api/src/lib.rs | 8 | ||||
-rw-r--r-- | crates/proc_macro_api/src/rpc.rs | 4 | ||||
-rw-r--r-- | crates/proc_macro_srv/src/lib.rs | 20 | ||||
-rw-r--r-- | crates/tt/src/lib.rs | 7 |
8 files changed, 52 insertions, 19 deletions
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs index cda5e57dc..9567bcc42 100644 --- a/crates/base_db/src/input.rs +++ b/crates/base_db/src/input.rs | |||
@@ -6,12 +6,12 @@ | |||
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::{fmt, iter::FromIterator, ops, str::FromStr, sync::Arc}; | 9 | use std::{fmt, iter::FromIterator, ops, panic::RefUnwindSafe, str::FromStr, sync::Arc}; |
10 | 10 | ||
11 | use cfg::CfgOptions; | 11 | use cfg::CfgOptions; |
12 | use rustc_hash::{FxHashMap, FxHashSet}; | 12 | use rustc_hash::{FxHashMap, FxHashSet}; |
13 | use syntax::SmolStr; | 13 | use syntax::SmolStr; |
14 | use tt::TokenExpander; | 14 | use tt::{ExpansionError, Subtree}; |
15 | use vfs::{file_set::FileSet, FileId, VfsPath}; | 15 | use vfs::{file_set::FileSet, FileId, VfsPath}; |
16 | 16 | ||
17 | /// Files are grouped into source roots. A source root is a directory on the | 17 | /// Files are grouped into source roots. A source root is a directory on the |
@@ -150,11 +150,20 @@ pub enum ProcMacroKind { | |||
150 | Attr, | 150 | Attr, |
151 | } | 151 | } |
152 | 152 | ||
153 | pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe { | ||
154 | fn expand( | ||
155 | &self, | ||
156 | subtree: &Subtree, | ||
157 | attrs: Option<&Subtree>, | ||
158 | env: &Env, | ||
159 | ) -> Result<Subtree, ExpansionError>; | ||
160 | } | ||
161 | |||
153 | #[derive(Debug, Clone)] | 162 | #[derive(Debug, Clone)] |
154 | pub struct ProcMacro { | 163 | pub struct ProcMacro { |
155 | pub name: SmolStr, | 164 | pub name: SmolStr, |
156 | pub kind: ProcMacroKind, | 165 | pub kind: ProcMacroKind, |
157 | pub expander: Arc<dyn TokenExpander>, | 166 | pub expander: Arc<dyn ProcMacroExpander>, |
158 | } | 167 | } |
159 | 168 | ||
160 | impl Eq for ProcMacro {} | 169 | impl Eq for ProcMacro {} |
@@ -413,6 +422,10 @@ impl Env { | |||
413 | pub fn get(&self, env: &str) -> Option<String> { | 422 | pub fn get(&self, env: &str) -> Option<String> { |
414 | self.entries.get(env).cloned() | 423 | self.entries.get(env).cloned() |
415 | } | 424 | } |
425 | |||
426 | pub fn iter(&self) -> impl Iterator<Item = (&str, &str)> { | ||
427 | self.entries.iter().map(|(k, v)| (k.as_str(), v.as_str())) | ||
428 | } | ||
416 | } | 429 | } |
417 | 430 | ||
418 | #[derive(Debug)] | 431 | #[derive(Debug)] |
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs index 595f28ada..5f77a0b1f 100644 --- a/crates/base_db/src/lib.rs +++ b/crates/base_db/src/lib.rs | |||
@@ -14,7 +14,7 @@ pub use crate::{ | |||
14 | change::Change, | 14 | change::Change, |
15 | input::{ | 15 | input::{ |
16 | CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, | 16 | CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, |
17 | ProcMacro, ProcMacroId, ProcMacroKind, SourceRoot, SourceRootId, | 17 | ProcMacro, ProcMacroExpander, ProcMacroId, ProcMacroKind, SourceRoot, SourceRootId, |
18 | }, | 18 | }, |
19 | }; | 19 | }; |
20 | pub use salsa; | 20 | pub use salsa; |
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 077de3727..06f0a3ed9 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -271,7 +271,7 @@ fn expand_proc_macro( | |||
271 | _ => unreachable!(), | 271 | _ => unreachable!(), |
272 | }; | 272 | }; |
273 | 273 | ||
274 | expander.expand(db, lazy_id, ¯o_arg.0) | 274 | expander.expand(db, loc.krate, ¯o_arg.0) |
275 | } | 275 | } |
276 | 276 | ||
277 | fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> { | 277 | fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> { |
diff --git a/crates/hir_expand/src/proc_macro.rs b/crates/hir_expand/src/proc_macro.rs index 38882d2b6..7c77f6ce0 100644 --- a/crates/hir_expand/src/proc_macro.rs +++ b/crates/hir_expand/src/proc_macro.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! Proc Macro Expander stub | 1 | //! Proc Macro Expander stub |
2 | 2 | ||
3 | use crate::{db::AstDatabase, LazyMacroId}; | 3 | use crate::db::AstDatabase; |
4 | use base_db::{CrateId, ProcMacroId}; | 4 | use base_db::{CrateId, ProcMacroId}; |
5 | use tt::buffer::{Cursor, TokenBuffer}; | 5 | use tt::buffer::{Cursor, TokenBuffer}; |
6 | 6 | ||
@@ -32,7 +32,7 @@ impl ProcMacroExpander { | |||
32 | pub fn expand( | 32 | pub fn expand( |
33 | self, | 33 | self, |
34 | db: &dyn AstDatabase, | 34 | db: &dyn AstDatabase, |
35 | _id: LazyMacroId, | 35 | calling_crate: CrateId, |
36 | tt: &tt::Subtree, | 36 | tt: &tt::Subtree, |
37 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 37 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
38 | match self.proc_macro_id { | 38 | match self.proc_macro_id { |
@@ -47,7 +47,10 @@ impl ProcMacroExpander { | |||
47 | let tt = remove_derive_attrs(tt) | 47 | let tt = remove_derive_attrs(tt) |
48 | .ok_or_else(|| err!("Fail to remove derive for custom derive"))?; | 48 | .ok_or_else(|| err!("Fail to remove derive for custom derive"))?; |
49 | 49 | ||
50 | proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from) | 50 | // Proc macros have access to the environment variables of the invoking crate. |
51 | let env = &krate_graph[calling_crate].env; | ||
52 | |||
53 | proc_macro.expander.expand(&tt, None, &env).map_err(mbe::ExpandError::from) | ||
51 | } | 54 | } |
52 | None => Err(mbe::ExpandError::UnresolvedProcMacro), | 55 | None => Err(mbe::ExpandError::UnresolvedProcMacro), |
53 | } | 56 | } |
diff --git a/crates/proc_macro_api/src/lib.rs b/crates/proc_macro_api/src/lib.rs index 0d061fd53..2ea456fb0 100644 --- a/crates/proc_macro_api/src/lib.rs +++ b/crates/proc_macro_api/src/lib.rs | |||
@@ -16,7 +16,7 @@ use std::{ | |||
16 | sync::Arc, | 16 | sync::Arc, |
17 | }; | 17 | }; |
18 | 18 | ||
19 | use base_db::ProcMacro; | 19 | use base_db::{Env, ProcMacro}; |
20 | use tt::{SmolStr, Subtree}; | 20 | use tt::{SmolStr, Subtree}; |
21 | 21 | ||
22 | use crate::process::{ProcMacroProcessSrv, ProcMacroProcessThread}; | 22 | use crate::process::{ProcMacroProcessSrv, ProcMacroProcessThread}; |
@@ -39,17 +39,19 @@ impl PartialEq for ProcMacroProcessExpander { | |||
39 | } | 39 | } |
40 | } | 40 | } |
41 | 41 | ||
42 | impl tt::TokenExpander for ProcMacroProcessExpander { | 42 | impl base_db::ProcMacroExpander for ProcMacroProcessExpander { |
43 | fn expand( | 43 | fn expand( |
44 | &self, | 44 | &self, |
45 | subtree: &Subtree, | 45 | subtree: &Subtree, |
46 | attr: Option<&Subtree>, | 46 | attr: Option<&Subtree>, |
47 | env: &Env, | ||
47 | ) -> Result<Subtree, tt::ExpansionError> { | 48 | ) -> Result<Subtree, tt::ExpansionError> { |
48 | let task = ExpansionTask { | 49 | let task = ExpansionTask { |
49 | macro_body: subtree.clone(), | 50 | macro_body: subtree.clone(), |
50 | macro_name: self.name.to_string(), | 51 | macro_name: self.name.to_string(), |
51 | attributes: attr.cloned(), | 52 | attributes: attr.cloned(), |
52 | lib: self.dylib_path.to_path_buf(), | 53 | lib: self.dylib_path.to_path_buf(), |
54 | env: env.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect(), | ||
53 | }; | 55 | }; |
54 | 56 | ||
55 | let result: ExpansionResult = self.process.send_task(msg::Request::ExpansionMacro(task))?; | 57 | let result: ExpansionResult = self.process.send_task(msg::Request::ExpansionMacro(task))?; |
@@ -90,7 +92,7 @@ impl ProcMacroClient { | |||
90 | ProcMacroKind::FuncLike => base_db::ProcMacroKind::FuncLike, | 92 | ProcMacroKind::FuncLike => base_db::ProcMacroKind::FuncLike, |
91 | ProcMacroKind::Attr => base_db::ProcMacroKind::Attr, | 93 | ProcMacroKind::Attr => base_db::ProcMacroKind::Attr, |
92 | }; | 94 | }; |
93 | let expander: Arc<dyn tt::TokenExpander> = Arc::new(ProcMacroProcessExpander { | 95 | let expander = Arc::new(ProcMacroProcessExpander { |
94 | process: self.process.clone(), | 96 | process: self.process.clone(), |
95 | name: name.clone(), | 97 | name: name.clone(), |
96 | dylib_path: dylib_path.into(), | 98 | dylib_path: dylib_path.into(), |
diff --git a/crates/proc_macro_api/src/rpc.rs b/crates/proc_macro_api/src/rpc.rs index b85f92eea..cf830b59f 100644 --- a/crates/proc_macro_api/src/rpc.rs +++ b/crates/proc_macro_api/src/rpc.rs | |||
@@ -51,6 +51,9 @@ pub struct ExpansionTask { | |||
51 | pub attributes: Option<Subtree>, | 51 | pub attributes: Option<Subtree>, |
52 | 52 | ||
53 | pub lib: PathBuf, | 53 | pub lib: PathBuf, |
54 | |||
55 | /// Environment variables to set during macro expansion. | ||
56 | pub env: Vec<(String, String)>, | ||
54 | } | 57 | } |
55 | 58 | ||
56 | #[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)] | 59 | #[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)] |
@@ -251,6 +254,7 @@ mod tests { | |||
251 | macro_name: Default::default(), | 254 | macro_name: Default::default(), |
252 | attributes: None, | 255 | attributes: None, |
253 | lib: Default::default(), | 256 | lib: Default::default(), |
257 | env: Default::default(), | ||
254 | }; | 258 | }; |
255 | 259 | ||
256 | let json = serde_json::to_string(&task).unwrap(); | 260 | let json = serde_json::to_string(&task).unwrap(); |
diff --git a/crates/proc_macro_srv/src/lib.rs b/crates/proc_macro_srv/src/lib.rs index 9cca96994..d4f04ee06 100644 --- a/crates/proc_macro_srv/src/lib.rs +++ b/crates/proc_macro_srv/src/lib.rs | |||
@@ -24,7 +24,7 @@ use proc_macro::bridge::client::TokenStream; | |||
24 | use proc_macro_api::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask}; | 24 | use proc_macro_api::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask}; |
25 | use std::{ | 25 | use std::{ |
26 | collections::{hash_map::Entry, HashMap}, | 26 | collections::{hash_map::Entry, HashMap}, |
27 | fs, | 27 | env, fs, |
28 | path::{Path, PathBuf}, | 28 | path::{Path, PathBuf}, |
29 | time::SystemTime, | 29 | time::SystemTime, |
30 | }; | 30 | }; |
@@ -37,7 +37,23 @@ pub(crate) struct ProcMacroSrv { | |||
37 | impl ProcMacroSrv { | 37 | impl ProcMacroSrv { |
38 | pub fn expand(&mut self, task: &ExpansionTask) -> Result<ExpansionResult, String> { | 38 | pub fn expand(&mut self, task: &ExpansionTask) -> Result<ExpansionResult, String> { |
39 | let expander = self.expander(&task.lib)?; | 39 | let expander = self.expander(&task.lib)?; |
40 | match expander.expand(&task.macro_name, &task.macro_body, task.attributes.as_ref()) { | 40 | |
41 | let mut prev_env = HashMap::new(); | ||
42 | for (k, v) in &task.env { | ||
43 | prev_env.insert(k.as_str(), env::var_os(k)); | ||
44 | env::set_var(k, v); | ||
45 | } | ||
46 | |||
47 | let result = expander.expand(&task.macro_name, &task.macro_body, task.attributes.as_ref()); | ||
48 | |||
49 | for (k, _) in &task.env { | ||
50 | match &prev_env[k.as_str()] { | ||
51 | Some(v) => env::set_var(k, v), | ||
52 | None => env::remove_var(k), | ||
53 | } | ||
54 | } | ||
55 | |||
56 | match result { | ||
41 | Ok(expansion) => Ok(ExpansionResult { expansion }), | 57 | Ok(expansion) => Ok(ExpansionResult { expansion }), |
42 | Err(msg) => { | 58 | Err(msg) => { |
43 | let msg = msg.as_str().unwrap_or("<unknown error>"); | 59 | let msg = msg.as_str().unwrap_or("<unknown error>"); |
diff --git a/crates/tt/src/lib.rs b/crates/tt/src/lib.rs index 6c1bf8d09..8301dc28a 100644 --- a/crates/tt/src/lib.rs +++ b/crates/tt/src/lib.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! `tt` crate defines a `TokenTree` data structure: this is the interface (both | 1 | //! `tt` crate defines a `TokenTree` data structure: this is the interface (both |
2 | //! input and output) of macros. It closely mirrors `proc_macro` crate's | 2 | //! input and output) of macros. It closely mirrors `proc_macro` crate's |
3 | //! `TokenTree`. | 3 | //! `TokenTree`. |
4 | use std::{fmt, panic::RefUnwindSafe}; | 4 | use std::fmt; |
5 | 5 | ||
6 | use stdx::impl_from; | 6 | use stdx::impl_from; |
7 | 7 | ||
@@ -247,8 +247,3 @@ impl fmt::Display for ExpansionError { | |||
247 | } | 247 | } |
248 | } | 248 | } |
249 | } | 249 | } |
250 | |||
251 | pub trait TokenExpander: fmt::Debug + Send + Sync + RefUnwindSafe { | ||
252 | fn expand(&self, subtree: &Subtree, attrs: Option<&Subtree>) | ||
253 | -> Result<Subtree, ExpansionError>; | ||
254 | } | ||