@@ -6,9 +6,24 @@ use syn::{parse2, visit_mut::visit_item_struct_mut, Error, ItemStruct, LitStr, R
66mod visitor;
77use visitor:: * ;
88
9+ /// Freezes the layout of a struct to the current hash of its fields, ensuring that future
10+ /// changes require updating the hash.
11+ ///
12+ /// If you ever get in a loop where rust analyzer insists that the hash is wrong each time you
13+ /// update, but `cargo check` is passing, you should use [`freeze_struct_ignore_ra`] instead.
914#[ proc_macro_attribute]
1015pub fn freeze_struct ( attr : TokenStream , tokens : TokenStream ) -> TokenStream {
11- match freeze_struct_impl ( attr, tokens) {
16+ match freeze_struct_impl ( attr, tokens, false ) {
17+ Ok ( item_struct) => item_struct. to_token_stream ( ) . into ( ) ,
18+ Err ( err) => err. to_compile_error ( ) . into ( ) ,
19+ }
20+ }
21+
22+ /// More permissive version of [`freeze_struct`] that ignores the hash check when running in
23+ /// rust-analyzer since in some rare situations rust-analyzer will generate an incorrect hash code
24+ #[ proc_macro_attribute]
25+ pub fn freeze_struct_ignore_ra ( attr : TokenStream , tokens : TokenStream ) -> TokenStream {
26+ match freeze_struct_impl ( attr, tokens, true ) {
1227 Ok ( item_struct) => item_struct. to_token_stream ( ) . into ( ) ,
1328 Err ( err) => err. to_compile_error ( ) . into ( ) ,
1429 }
@@ -17,6 +32,7 @@ pub fn freeze_struct(attr: TokenStream, tokens: TokenStream) -> TokenStream {
1732fn freeze_struct_impl (
1833 attr : impl Into < TokenStream2 > ,
1934 tokens : impl Into < TokenStream2 > ,
35+ ignore_ra : bool ,
2036) -> Result < ItemStruct > {
2137 let attr = attr. into ( ) ;
2238 let tokens = tokens. into ( ) ;
@@ -39,6 +55,10 @@ fn freeze_struct_impl(
3955 let mut visitor = CleanDocComments :: new ( ) ;
4056 visit_item_struct_mut ( & mut visitor, & mut item_clone) ;
4157
58+ if ignore_ra && is_rust_analyzer ( ) {
59+ return Ok ( item) ;
60+ }
61+
4262 if provided_hash_hex != calculated_hash_hex {
4363 return Err ( Error :: new_spanned ( item,
4464 format ! (
@@ -52,3 +72,10 @@ fn freeze_struct_impl(
5272 }
5373 Ok ( item)
5474}
75+
76+ /// Returns true if the current build is being run by rust-analyzer.
77+ fn is_rust_analyzer ( ) -> bool {
78+ std:: env:: var ( "RUSTC_WRAPPER" )
79+ . map ( |v| v. contains ( "rust-analyzer" ) )
80+ . unwrap_or ( false )
81+ }
0 commit comments