33mod version;
44
55use proc_macro:: bridge;
6- use std:: { fmt, fs:: File , io} ;
6+ use std:: { fmt, fs, io, time :: SystemTime } ;
77
88use libloading:: Library ;
99use memmap2:: Mmap ;
1010use object:: Object ;
11- use paths:: { AbsPath , Utf8Path , Utf8PathBuf } ;
11+ use paths:: { Utf8Path , Utf8PathBuf } ;
1212use proc_macro_api:: ProcMacroKind ;
1313
1414use crate :: ProcMacroSrvSpan ;
@@ -23,14 +23,9 @@ fn is_derive_registrar_symbol(symbol: &str) -> bool {
2323 symbol. contains ( NEW_REGISTRAR_SYMBOL )
2424}
2525
26- fn find_registrar_symbol ( file : & Utf8Path ) -> io:: Result < Option < String > > {
27- let file = File :: open ( file) ?;
28- let buffer = unsafe { Mmap :: map ( & file) ? } ;
29-
30- Ok ( object:: File :: parse ( & * buffer)
31- . map_err ( invalid_data_err) ?
32- . exports ( )
33- . map_err ( invalid_data_err) ?
26+ fn find_registrar_symbol ( buffer : & [ u8 ] ) -> object:: Result < Option < String > > {
27+ Ok ( object:: File :: parse ( buffer) ?
28+ . exports ( ) ?
3429 . into_iter ( )
3530 . map ( |export| export. name ( ) )
3631 . filter_map ( |sym| String :: from_utf8 ( sym. into ( ) ) . ok ( ) )
@@ -113,17 +108,17 @@ struct ProcMacroLibraryLibloading {
113108}
114109
115110impl ProcMacroLibraryLibloading {
116- fn open ( file : & Utf8Path ) -> Result < Self , LoadProcMacroDylibError > {
117- let symbol_name = find_registrar_symbol ( file) ?. ok_or_else ( || {
118- invalid_data_err ( format ! ( "Cannot find registrar symbol in file {file}" ) )
119- } ) ?;
111+ fn open ( path : & Utf8Path ) -> Result < Self , LoadProcMacroDylibError > {
112+ let buffer = unsafe { Mmap :: map ( & fs:: File :: open ( path) ?) ? } ;
113+ let symbol_name =
114+ find_registrar_symbol ( & buffer) . map_err ( invalid_data_err) ?. ok_or_else ( || {
115+ invalid_data_err ( format ! ( "Cannot find registrar symbol in file {path}" ) )
116+ } ) ?;
120117
121- let abs_file: & AbsPath = file
122- . try_into ( )
123- . map_err ( |_| invalid_data_err ( format ! ( "expected an absolute path, got {file}" ) ) ) ?;
124- let version_info = version:: read_dylib_info ( abs_file) ?;
118+ let version_info = version:: read_dylib_info ( & buffer) ?;
119+ drop ( buffer) ;
125120
126- let lib = load_library ( file ) . map_err ( invalid_data_err) ?;
121+ let lib = load_library ( path ) . map_err ( invalid_data_err) ?;
127122 let proc_macros = crate :: proc_macros:: ProcMacros :: from_lib (
128123 & lib,
129124 symbol_name,
@@ -133,30 +128,33 @@ impl ProcMacroLibraryLibloading {
133128 }
134129}
135130
136- pub ( crate ) struct Expander {
137- inner : ProcMacroLibraryLibloading ,
138- path : Utf8PathBuf ,
139- }
140-
141- impl Drop for Expander {
131+ struct RemoveFileOnDrop ( Utf8PathBuf ) ;
132+ impl Drop for RemoveFileOnDrop {
142133 fn drop ( & mut self ) {
143134 #[ cfg( windows) ]
144- std:: fs:: remove_file ( & self . path ) . ok ( ) ;
145- _ = self . path ;
135+ std:: fs:: remove_file ( & self . 0 ) . unwrap ( ) ;
136+ _ = self . 0 ;
146137 }
147138}
148139
140+ // Drop order matters as we can't remove the dylib before the library is unloaded
141+ pub ( crate ) struct Expander {
142+ inner : ProcMacroLibraryLibloading ,
143+ _remove_on_drop : RemoveFileOnDrop ,
144+ modified_time : SystemTime ,
145+ }
146+
149147impl Expander {
150148 pub ( crate ) fn new ( lib : & Utf8Path ) -> Result < Expander , LoadProcMacroDylibError > {
151149 // Some libraries for dynamic loading require canonicalized path even when it is
152150 // already absolute
153151 let lib = lib. canonicalize_utf8 ( ) ?;
152+ let modified_time = fs:: metadata ( & lib) . and_then ( |it| it. modified ( ) ) ?;
154153
155154 let path = ensure_file_with_lock_free_access ( & lib) ?;
156-
157155 let library = ProcMacroLibraryLibloading :: open ( path. as_ref ( ) ) ?;
158156
159- Ok ( Expander { inner : library, path } )
157+ Ok ( Expander { inner : library, _remove_on_drop : RemoveFileOnDrop ( path) , modified_time } )
160158 }
161159
162160 pub ( crate ) fn expand < S : ProcMacroSrvSpan > (
@@ -181,6 +179,10 @@ impl Expander {
181179 pub ( crate ) fn list_macros ( & self ) -> Vec < ( String , ProcMacroKind ) > {
182180 self . inner . proc_macros . list_macros ( )
183181 }
182+
183+ pub ( crate ) fn modified_time ( & self ) -> SystemTime {
184+ self . modified_time
185+ }
184186}
185187
186188/// Copy the dylib to temp directory to prevent locking in Windows
@@ -194,20 +196,23 @@ fn ensure_file_with_lock_free_access(path: &Utf8Path) -> io::Result<Utf8PathBuf>
194196 }
195197
196198 let mut to = Utf8PathBuf :: from_path_buf ( std:: env:: temp_dir ( ) ) . unwrap ( ) ;
199+ to. push ( "rust-analyzer-proc-macros" ) ;
200+ _ = fs:: create_dir ( & to) ;
197201
198202 let file_name = path. file_name ( ) . ok_or_else ( || {
199203 io:: Error :: new ( io:: ErrorKind :: InvalidInput , format ! ( "File path is invalid: {path}" ) )
200204 } ) ?;
201205
202- // Generate a unique number by abusing `HashMap`'s hasher.
203- // Maybe this will also "inspire" a libs team member to finally put `rand` in libstd.
204- let t = RandomState :: new ( ) . build_hasher ( ) . finish ( ) ;
205-
206- let mut unique_name = t. to_string ( ) ;
207- unique_name. push_str ( file_name) ;
208-
209- to. push ( unique_name) ;
210- std:: fs:: copy ( path, & to) ?;
206+ to. push ( {
207+ // Generate a unique number by abusing `HashMap`'s hasher.
208+ // Maybe this will also "inspire" a libs team member to finally put `rand` in libstd.
209+ let t = RandomState :: new ( ) . build_hasher ( ) . finish ( ) ;
210+ let mut unique_name = t. to_string ( ) ;
211+ unique_name. push_str ( file_name) ;
212+ unique_name. push ( '-' ) ;
213+ unique_name
214+ } ) ;
215+ fs:: copy ( path, & to) ?;
211216 Ok ( to)
212217}
213218
0 commit comments