aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_proc_macro_srv/src/dylib.rs
diff options
context:
space:
mode:
authorBenjamin Coenen <[email protected]>2020-04-21 13:32:02 +0100
committerBenjamin Coenen <[email protected]>2020-04-21 13:32:02 +0100
commit7f143b154e7c47b1f5bdc558bb0b5d1f2bf74f8d (patch)
tree571b7d5bdfc84bdaeaa8235221fd96a87453fe05 /crates/ra_proc_macro_srv/src/dylib.rs
parent1c3a1385a587f0713908c0ae888ffad31f13de11 (diff)
parenta88887df0726cc3d390db4bfbbc1274195d87f91 (diff)
Merge branch 'master' of github.com:rust-analyzer/rust-analyzer
Diffstat (limited to 'crates/ra_proc_macro_srv/src/dylib.rs')
-rw-r--r--crates/ra_proc_macro_srv/src/dylib.rs103
1 files changed, 45 insertions, 58 deletions
diff --git a/crates/ra_proc_macro_srv/src/dylib.rs b/crates/ra_proc_macro_srv/src/dylib.rs
index 16bd7466e..d202eb0fd 100644
--- a/crates/ra_proc_macro_srv/src/dylib.rs
+++ b/crates/ra_proc_macro_srv/src/dylib.rs
@@ -9,43 +9,37 @@ use libloading::Library;
9use memmap::Mmap; 9use memmap::Mmap;
10use ra_proc_macro::ProcMacroKind; 10use ra_proc_macro::ProcMacroKind;
11 11
12use std::io::Error as IoError; 12use std::io;
13use std::io::ErrorKind as IoErrorKind;
14 13
15const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_"; 14const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_";
16 15
17fn invalid_data_err(e: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> IoError { 16fn invalid_data_err(e: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> io::Error {
18 IoError::new(IoErrorKind::InvalidData, e) 17 io::Error::new(io::ErrorKind::InvalidData, e)
19} 18}
20 19
21fn is_derive_registrar_symbol(symbol: &str) -> bool { 20fn is_derive_registrar_symbol(symbol: &str) -> bool {
22 symbol.contains(NEW_REGISTRAR_SYMBOL) 21 symbol.contains(NEW_REGISTRAR_SYMBOL)
23} 22}
24 23
25fn find_registrar_symbol(file: &Path) -> Result<Option<String>, IoError> { 24fn find_registrar_symbol(file: &Path) -> io::Result<Option<String>> {
26 let file = File::open(file)?; 25 let file = File::open(file)?;
27 let buffer = unsafe { Mmap::map(&file)? }; 26 let buffer = unsafe { Mmap::map(&file)? };
28 let object = Object::parse(&buffer).map_err(invalid_data_err)?; 27 let object = Object::parse(&buffer).map_err(invalid_data_err)?;
29 28
30 match object { 29 let name = match object {
31 Object::Elf(elf) => { 30 Object::Elf(elf) => {
32 let symbols = elf.dynstrtab.to_vec().map_err(invalid_data_err)?; 31 let symbols = elf.dynstrtab.to_vec().map_err(invalid_data_err)?;
33 let name = 32 symbols.into_iter().find(|s| is_derive_registrar_symbol(s)).map(&str::to_owned)
34 symbols.iter().find(|s| is_derive_registrar_symbol(s)).map(|s| s.to_string());
35 Ok(name)
36 }
37 Object::PE(pe) => {
38 let name = pe
39 .exports
40 .iter()
41 .flat_map(|s| s.name)
42 .find(|s| is_derive_registrar_symbol(s))
43 .map(|s| s.to_string());
44 Ok(name)
45 } 33 }
34 Object::PE(pe) => pe
35 .exports
36 .iter()
37 .flat_map(|s| s.name)
38 .find(|s| is_derive_registrar_symbol(s))
39 .map(&str::to_owned),
46 Object::Mach(Mach::Binary(binary)) => { 40 Object::Mach(Mach::Binary(binary)) => {
47 let exports = binary.exports().map_err(invalid_data_err)?; 41 let exports = binary.exports().map_err(invalid_data_err)?;
48 let name = exports 42 exports
49 .iter() 43 .iter()
50 .map(|s| { 44 .map(|s| {
51 // In macos doc: 45 // In macos doc:
@@ -59,11 +53,11 @@ fn find_registrar_symbol(file: &Path) -> Result<Option<String>, IoError> {
59 } 53 }
60 }) 54 })
61 .find(|s| is_derive_registrar_symbol(s)) 55 .find(|s| is_derive_registrar_symbol(s))
62 .map(|s| s.to_string()); 56 .map(&str::to_owned)
63 Ok(name)
64 } 57 }
65 _ => Ok(None), 58 _ => return Ok(None),
66 } 59 };
60 return Ok(name);
67} 61}
68 62
69/// Loads dynamic library in platform dependent manner. 63/// Loads dynamic library in platform dependent manner.
@@ -93,15 +87,16 @@ fn load_library(file: &Path) -> Result<Library, libloading::Error> {
93} 87}
94 88
95struct ProcMacroLibraryLibloading { 89struct ProcMacroLibraryLibloading {
96 // Hold the dylib to prevent it for unloadeding 90 // Hold the dylib to prevent it from unloading
97 _lib: Library, 91 _lib: Library,
98 exported_macros: Vec<bridge::client::ProcMacro>, 92 exported_macros: Vec<bridge::client::ProcMacro>,
99} 93}
100 94
101impl ProcMacroLibraryLibloading { 95impl ProcMacroLibraryLibloading {
102 fn open(file: &Path) -> Result<Self, IoError> { 96 fn open(file: &Path) -> io::Result<Self> {
103 let symbol_name = find_registrar_symbol(file)? 97 let symbol_name = find_registrar_symbol(file)?.ok_or_else(|| {
104 .ok_or(invalid_data_err(format!("Cannot find registrar symbol in file {:?}", file)))?; 98 invalid_data_err(format!("Cannot find registrar symbol in file {}", file.display()))
99 })?;
105 100
106 let lib = load_library(file).map_err(invalid_data_err)?; 101 let lib = load_library(file).map_err(invalid_data_err)?;
107 let exported_macros = { 102 let exported_macros = {
@@ -121,18 +116,16 @@ pub struct Expander {
121} 116}
122 117
123impl Expander { 118impl Expander {
124 pub fn new<P: AsRef<Path>>(lib: &P) -> Result<Expander, String> { 119 pub fn new(lib: &Path) -> Result<Expander, String> {
125 let mut libs = vec![]; 120 // Some libraries for dynamic loading require canonicalized path even when it is
126 /* Some libraries for dynamic loading require canonicalized path (even when it is 121 // already absolute
127 already absolute 122 let lib = lib
128 */ 123 .canonicalize()
129 let lib = 124 .unwrap_or_else(|err| panic!("Cannot canonicalize {}: {:?}", lib.display(), err));
130 lib.as_ref().canonicalize().expect(&format!("Cannot canonicalize {:?}", lib.as_ref()));
131 125
132 let library = ProcMacroLibraryImpl::open(&lib).map_err(|e| e.to_string())?; 126 let library = ProcMacroLibraryImpl::open(&lib).map_err(|e| e.to_string())?;
133 libs.push(library);
134 127
135 Ok(Expander { libs }) 128 Ok(Expander { libs: vec![library] })
136 } 129 }
137 130
138 pub fn expand( 131 pub fn expand(
@@ -176,7 +169,6 @@ impl Expander {
176 parsed_attributes, 169 parsed_attributes,
177 parsed_body, 170 parsed_body,
178 ); 171 );
179
180 return res.map(|it| it.subtree); 172 return res.map(|it| it.subtree);
181 } 173 }
182 _ => continue, 174 _ => continue,
@@ -187,26 +179,21 @@ impl Expander {
187 Err(bridge::PanicMessage::String("Nothing to expand".to_string())) 179 Err(bridge::PanicMessage::String("Nothing to expand".to_string()))
188 } 180 }
189 181
190 pub fn list_macros(&self) -> Result<Vec<(String, ProcMacroKind)>, bridge::PanicMessage> { 182 pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> {
191 let mut result = vec![]; 183 self.libs
192 184 .iter()
193 for lib in &self.libs { 185 .flat_map(|it| &it.exported_macros)
194 for proc_macro in &lib.exported_macros { 186 .map(|proc_macro| match proc_macro {
195 let res = match proc_macro { 187 bridge::client::ProcMacro::CustomDerive { trait_name, .. } => {
196 bridge::client::ProcMacro::CustomDerive { trait_name, .. } => { 188 (trait_name.to_string(), ProcMacroKind::CustomDerive)
197 (trait_name.to_string(), ProcMacroKind::CustomDerive) 189 }
198 } 190 bridge::client::ProcMacro::Bang { name, .. } => {
199 bridge::client::ProcMacro::Bang { name, .. } => { 191 (name.to_string(), ProcMacroKind::FuncLike)
200 (name.to_string(), ProcMacroKind::FuncLike) 192 }
201 } 193 bridge::client::ProcMacro::Attr { name, .. } => {
202 bridge::client::ProcMacro::Attr { name, .. } => { 194 (name.to_string(), ProcMacroKind::Attr)
203 (name.to_string(), ProcMacroKind::Attr) 195 }
204 } 196 })
205 }; 197 .collect()
206 result.push(res);
207 }
208 }
209
210 Ok(result)
211 } 198 }
212} 199}