aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/base_db/src/input.rs19
-rw-r--r--crates/base_db/src/lib.rs2
-rw-r--r--crates/hir_expand/src/db.rs2
-rw-r--r--crates/hir_expand/src/proc_macro.rs9
-rw-r--r--crates/proc_macro_api/src/lib.rs8
-rw-r--r--crates/proc_macro_api/src/rpc.rs4
-rw-r--r--crates/proc_macro_srv/src/lib.rs20
-rw-r--r--crates/tt/src/lib.rs7
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
9use std::{fmt, iter::FromIterator, ops, str::FromStr, sync::Arc}; 9use std::{fmt, iter::FromIterator, ops, panic::RefUnwindSafe, str::FromStr, sync::Arc};
10 10
11use cfg::CfgOptions; 11use cfg::CfgOptions;
12use rustc_hash::{FxHashMap, FxHashSet}; 12use rustc_hash::{FxHashMap, FxHashSet};
13use syntax::SmolStr; 13use syntax::SmolStr;
14use tt::TokenExpander; 14use tt::{ExpansionError, Subtree};
15use vfs::{file_set::FileSet, FileId, VfsPath}; 15use 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
153pub 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)]
154pub struct ProcMacro { 163pub 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
160impl Eq for ProcMacro {} 169impl 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};
20pub use salsa; 20pub 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, &macro_arg.0) 274 expander.expand(db, loc.krate, &macro_arg.0)
275} 275}
276 276
277fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> { 277fn 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
3use crate::{db::AstDatabase, LazyMacroId}; 3use crate::db::AstDatabase;
4use base_db::{CrateId, ProcMacroId}; 4use base_db::{CrateId, ProcMacroId};
5use tt::buffer::{Cursor, TokenBuffer}; 5use 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
19use base_db::ProcMacro; 19use base_db::{Env, ProcMacro};
20use tt::{SmolStr, Subtree}; 20use tt::{SmolStr, Subtree};
21 21
22use crate::process::{ProcMacroProcessSrv, ProcMacroProcessThread}; 22use crate::process::{ProcMacroProcessSrv, ProcMacroProcessThread};
@@ -39,17 +39,19 @@ impl PartialEq for ProcMacroProcessExpander {
39 } 39 }
40} 40}
41 41
42impl tt::TokenExpander for ProcMacroProcessExpander { 42impl 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;
24use proc_macro_api::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask}; 24use proc_macro_api::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask};
25use std::{ 25use 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 {
37impl ProcMacroSrv { 37impl 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`.
4use std::{fmt, panic::RefUnwindSafe}; 4use std::fmt;
5 5
6use stdx::impl_from; 6use stdx::impl_from;
7 7
@@ -247,8 +247,3 @@ impl fmt::Display for ExpansionError {
247 } 247 }
248 } 248 }
249} 249}
250
251pub trait TokenExpander: fmt::Debug + Send + Sync + RefUnwindSafe {
252 fn expand(&self, subtree: &Subtree, attrs: Option<&Subtree>)
253 -> Result<Subtree, ExpansionError>;
254}