Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/proc-macro-srv/src/proc_macros.rs')
| -rw-r--r-- | crates/proc-macro-srv/src/proc_macros.rs | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/crates/proc-macro-srv/src/proc_macros.rs b/crates/proc-macro-srv/src/proc_macros.rs new file mode 100644 index 0000000000..3c6f320331 --- /dev/null +++ b/crates/proc-macro-srv/src/proc_macros.rs @@ -0,0 +1,127 @@ +//! Proc macro ABI + +use libloading::Library; +use proc_macro_api::{ProcMacroKind, RustCInfo}; + +use crate::{dylib::LoadProcMacroDylibError, server::SYMBOL_INTERNER, tt}; + +pub(crate) struct ProcMacros { + exported_macros: Vec<proc_macro::bridge::client::ProcMacro>, +} + +impl From<proc_macro::bridge::PanicMessage> for crate::PanicMessage { + fn from(p: proc_macro::bridge::PanicMessage) -> Self { + Self { message: p.as_str().map(|s| s.to_string()) } + } +} + +impl ProcMacros { + /// Load a new ABI. + /// + /// # Arguments + /// + /// *`lib` - The dynamic library containing the macro implementations + /// *`symbol_name` - The symbol name the macros can be found attributes + /// *`info` - RustCInfo about the compiler that was used to compile the + /// macro crate. This is the information we use to figure out + /// which ABI to return + pub(crate) fn from_lib( + lib: &Library, + symbol_name: String, + info: RustCInfo, + ) -> Result<ProcMacros, LoadProcMacroDylibError> { + if info.version_string == crate::RUSTC_VERSION_STRING { + let macros = unsafe { + lib.get::<&&[proc_macro::bridge::client::ProcMacro]>(symbol_name.as_bytes()) + }?; + + return Ok(Self { exported_macros: macros.to_vec() }); + } + Err(LoadProcMacroDylibError::AbiMismatch(info.version_string)) + } + + pub(crate) fn expand( + &self, + macro_name: &str, + macro_body: &tt::Subtree, + attributes: Option<&tt::Subtree>, + ) -> Result<tt::Subtree, crate::PanicMessage> { + let parsed_body = crate::server::TokenStream::with_subtree(macro_body.clone()); + + let parsed_attributes = attributes.map_or(crate::server::TokenStream::new(), |attr| { + crate::server::TokenStream::with_subtree(attr.clone()) + }); + + for proc_macro in &self.exported_macros { + match proc_macro { + proc_macro::bridge::client::ProcMacro::CustomDerive { + trait_name, client, .. + } if *trait_name == macro_name => { + let res = client.run( + &proc_macro::bridge::server::SameThread, + crate::server::RustAnalyzer { interner: &SYMBOL_INTERNER }, + parsed_body, + true, + ); + return res.map(|it| it.into_subtree()).map_err(crate::PanicMessage::from); + } + proc_macro::bridge::client::ProcMacro::Bang { name, client } + if *name == macro_name => + { + let res = client.run( + &proc_macro::bridge::server::SameThread, + crate::server::RustAnalyzer { interner: &SYMBOL_INTERNER }, + parsed_body, + true, + ); + return res.map(|it| it.into_subtree()).map_err(crate::PanicMessage::from); + } + proc_macro::bridge::client::ProcMacro::Attr { name, client } + if *name == macro_name => + { + let res = client.run( + &proc_macro::bridge::server::SameThread, + crate::server::RustAnalyzer { interner: &SYMBOL_INTERNER }, + parsed_attributes, + parsed_body, + true, + ); + return res.map(|it| it.into_subtree()).map_err(crate::PanicMessage::from); + } + _ => continue, + } + } + + Err(proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string()).into()) + } + + pub(crate) fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { + self.exported_macros + .iter() + .map(|proc_macro| match proc_macro { + proc_macro::bridge::client::ProcMacro::CustomDerive { trait_name, .. } => { + (trait_name.to_string(), ProcMacroKind::CustomDerive) + } + proc_macro::bridge::client::ProcMacro::Bang { name, .. } => { + (name.to_string(), ProcMacroKind::FuncLike) + } + proc_macro::bridge::client::ProcMacro::Attr { name, .. } => { + (name.to_string(), ProcMacroKind::Attr) + } + }) + .collect() + } +} + +#[test] +fn test_version_check() { + let path = paths::AbsPathBuf::assert(crate::proc_macro_test_dylib_path()); + let info = proc_macro_api::read_dylib_info(&path).unwrap(); + assert_eq!( + info.version_string, + crate::RUSTC_VERSION_STRING, + "sysroot ABI mismatch: dylib rustc version (read from .rustc section): {:?} != proc-macro-srv version (read from 'rustc --version'): {:?}", + info.version_string, + crate::RUSTC_VERSION_STRING, + ); +} |