]> git.lizzy.rs Git - rust.git/commitdiff
Pass crate environment to proc macros
authorJonas Schievink <jonasschievink@gmail.com>
Fri, 11 Dec 2020 13:57:50 +0000 (14:57 +0100)
committerJonas Schievink <jonasschievink@gmail.com>
Sun, 27 Dec 2020 14:29:47 +0000 (15:29 +0100)
crates/base_db/src/input.rs
crates/hir_expand/src/db.rs
crates/hir_expand/src/proc_macro.rs
crates/proc_macro_api/src/lib.rs
crates/proc_macro_api/src/rpc.rs
crates/proc_macro_srv/src/lib.rs

index a693e7f80d5fb85c69e8f52c352db14473cd962a..9567bcc424de40d08e1e62f85faa10be7644f73f 100644 (file)
@@ -151,8 +151,12 @@ pub enum ProcMacroKind {
 }
 
 pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe {
-    fn expand(&self, subtree: &Subtree, attrs: Option<&Subtree>)
-        -> Result<Subtree, ExpansionError>;
+    fn expand(
+        &self,
+        subtree: &Subtree,
+        attrs: Option<&Subtree>,
+        env: &Env,
+    ) -> Result<Subtree, ExpansionError>;
 }
 
 #[derive(Debug, Clone)]
@@ -418,6 +422,10 @@ pub fn set(&mut self, env: &str, value: String) {
     pub fn get(&self, env: &str) -> Option<String> {
         self.entries.get(env).cloned()
     }
+
+    pub fn iter(&self) -> impl Iterator<Item = (&str, &str)> {
+        self.entries.iter().map(|(k, v)| (k.as_str(), v.as_str()))
+    }
 }
 
 #[derive(Debug)]
index 077de37270cf21b82ad981f448c449855218250f..06f0a3ed9cc423f76b86298523bb0137f78c2489 100644 (file)
@@ -271,7 +271,7 @@ fn expand_proc_macro(
         _ => unreachable!(),
     };
 
-    expander.expand(db, lazy_id, &macro_arg.0)
+    expander.expand(db, loc.krate, &macro_arg.0)
 }
 
 fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> {
index 38882d2b68b1f602ead7e59e627e688d1597e066..7c77f6ce0a36cdefebaefc81dda2496ac4eb31d1 100644 (file)
@@ -1,6 +1,6 @@
 //! Proc Macro Expander stub
 
-use crate::{db::AstDatabase, LazyMacroId};
+use crate::db::AstDatabase;
 use base_db::{CrateId, ProcMacroId};
 use tt::buffer::{Cursor, TokenBuffer};
 
@@ -32,7 +32,7 @@ pub fn dummy(krate: CrateId) -> Self {
     pub fn expand(
         self,
         db: &dyn AstDatabase,
-        _id: LazyMacroId,
+        calling_crate: CrateId,
         tt: &tt::Subtree,
     ) -> Result<tt::Subtree, mbe::ExpandError> {
         match self.proc_macro_id {
@@ -47,7 +47,10 @@ pub fn expand(
                 let tt = remove_derive_attrs(tt)
                     .ok_or_else(|| err!("Fail to remove derive for custom derive"))?;
 
-                proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from)
+                // Proc macros have access to the environment variables of the invoking crate.
+                let env = &krate_graph[calling_crate].env;
+
+                proc_macro.expander.expand(&tt, None, &env).map_err(mbe::ExpandError::from)
             }
             None => Err(mbe::ExpandError::UnresolvedProcMacro),
         }
index a61afbbd669980ecc3ef47f6ee6dca3467f78cbc..2ea456fb0960b37aadee0d78162950ed73788e46 100644 (file)
@@ -16,7 +16,7 @@
     sync::Arc,
 };
 
-use base_db::ProcMacro;
+use base_db::{Env, ProcMacro};
 use tt::{SmolStr, Subtree};
 
 use crate::process::{ProcMacroProcessSrv, ProcMacroProcessThread};
@@ -44,12 +44,14 @@ fn expand(
         &self,
         subtree: &Subtree,
         attr: Option<&Subtree>,
+        env: &Env,
     ) -> Result<Subtree, tt::ExpansionError> {
         let task = ExpansionTask {
             macro_body: subtree.clone(),
             macro_name: self.name.to_string(),
             attributes: attr.cloned(),
             lib: self.dylib_path.to_path_buf(),
+            env: env.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect(),
         };
 
         let result: ExpansionResult = self.process.send_task(msg::Request::ExpansionMacro(task))?;
index b85f92eeada9dc4bbd705df08c484d06b8a2dedd..cf830b59f17834abfaff59d1c179822a79e23071 100644 (file)
@@ -51,6 +51,9 @@ pub struct ExpansionTask {
     pub attributes: Option<Subtree>,
 
     pub lib: PathBuf,
+
+    /// Environment variables to set during macro expansion.
+    pub env: Vec<(String, String)>,
 }
 
 #[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)]
@@ -251,6 +254,7 @@ fn test_proc_macro_rpc_works() {
             macro_name: Default::default(),
             attributes: None,
             lib: Default::default(),
+            env: Default::default(),
         };
 
         let json = serde_json::to_string(&task).unwrap();
index 9cca969944059248293722b4b3ab28969e06a07c..d4f04ee0696780432fc755680fc47fd54f408c50 100644 (file)
@@ -24,7 +24,7 @@
 use proc_macro_api::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask};
 use std::{
     collections::{hash_map::Entry, HashMap},
-    fs,
+    env, fs,
     path::{Path, PathBuf},
     time::SystemTime,
 };
@@ -37,7 +37,23 @@ pub(crate) struct ProcMacroSrv {
 impl ProcMacroSrv {
     pub fn expand(&mut self, task: &ExpansionTask) -> Result<ExpansionResult, String> {
         let expander = self.expander(&task.lib)?;
-        match expander.expand(&task.macro_name, &task.macro_body, task.attributes.as_ref()) {
+
+        let mut prev_env = HashMap::new();
+        for (k, v) in &task.env {
+            prev_env.insert(k.as_str(), env::var_os(k));
+            env::set_var(k, v);
+        }
+
+        let result = expander.expand(&task.macro_name, &task.macro_body, task.attributes.as_ref());
+
+        for (k, _) in &task.env {
+            match &prev_env[k.as_str()] {
+                Some(v) => env::set_var(k, v),
+                None => env::remove_var(k),
+            }
+        }
+
+        match result {
             Ok(expansion) => Ok(ExpansionResult { expansion }),
             Err(msg) => {
                 let msg = msg.as_str().unwrap_or("<unknown error>");