}
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)]
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)]
_ => unreachable!(),
};
- expander.expand(db, lazy_id, ¯o_arg.0)
+ expander.expand(db, loc.krate, ¯o_arg.0)
}
fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> {
//! Proc Macro Expander stub
-use crate::{db::AstDatabase, LazyMacroId};
+use crate::db::AstDatabase;
use base_db::{CrateId, ProcMacroId};
use tt::buffer::{Cursor, TokenBuffer};
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 {
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),
}
sync::Arc,
};
-use base_db::ProcMacro;
+use base_db::{Env, ProcMacro};
use tt::{SmolStr, Subtree};
use crate::process::{ProcMacroProcessSrv, ProcMacroProcessThread};
&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))?;
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)]
macro_name: Default::default(),
attributes: None,
lib: Default::default(),
+ env: Default::default(),
};
let json = serde_json::to_string(&task).unwrap();
use proc_macro_api::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask};
use std::{
collections::{hash_map::Entry, HashMap},
- fs,
+ env, fs,
path::{Path, PathBuf},
time::SystemTime,
};
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>");