@@ -123,6 +123,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T
123123 from_glob_import : Default :: default ( ) ,
124124 skip_attrs : Default :: default ( ) ,
125125 is_proc_macro,
126+ hygienes : FxHashMap :: default ( ) ,
126127 } ;
127128 if tree_id. is_block ( ) {
128129 collector. seed_with_inner ( tree_id) ;
@@ -270,6 +271,12 @@ struct DefCollector<'a> {
270271 /// This also stores the attributes to skip when we resolve derive helpers and non-macro
271272 /// non-builtin attributes in general.
272273 skip_attrs : FxHashMap < InFile < ModItem > , AttrId > ,
274+ /// `Hygiene` cache, because `Hygiene` construction is expensive.
275+ ///
276+ /// Almost all paths should have been lowered to `ModPath` during `ItemTree` construction.
277+ /// However, `DefCollector` still needs to lower paths in attributes, in particular those in
278+ /// derive meta item list.
279+ hygienes : FxHashMap < HirFileId , Hygiene > ,
273280}
274281
275282impl DefCollector < ' _ > {
@@ -313,8 +320,9 @@ impl DefCollector<'_> {
313320 }
314321
315322 if * attr_name == hir_expand:: name![ feature] {
323+ let hygiene = & Hygiene :: new_unhygienic ( ) ;
316324 let features = attr
317- . parse_path_comma_token_tree ( self . db . upcast ( ) , Hygiene :: new_unhygienic ( ) )
325+ . parse_path_comma_token_tree ( self . db . upcast ( ) , hygiene )
318326 . into_iter ( )
319327 . flatten ( )
320328 . filter_map ( |feat| match feat. segments ( ) {
@@ -1225,7 +1233,18 @@ impl DefCollector<'_> {
12251233 }
12261234 } ;
12271235 let ast_id = ast_id. with_value ( ast_adt_id) ;
1228- let hygiene = Hygiene :: new ( self . db . upcast ( ) , file_id) ;
1236+
1237+ let extend_unhygenic;
1238+ let hygiene = if file_id. is_macro ( ) {
1239+ self . hygienes
1240+ . entry ( file_id)
1241+ . or_insert_with ( || Hygiene :: new ( self . db . upcast ( ) , file_id) )
1242+ } else {
1243+ // Avoid heap allocation (`Hygiene` embraces `Arc`) and hash map entry
1244+ // when we're in an oridinary (non-macro) file.
1245+ extend_unhygenic = Hygiene :: new_unhygienic ( ) ;
1246+ & extend_unhygenic
1247+ } ;
12291248
12301249 match attr. parse_path_comma_token_tree ( self . db . upcast ( ) , hygiene) {
12311250 Some ( derive_macros) => {
@@ -2215,6 +2234,7 @@ mod tests {
22152234 from_glob_import : Default :: default ( ) ,
22162235 skip_attrs : Default :: default ( ) ,
22172236 is_proc_macro : false ,
2237+ hygienes : FxHashMap :: default ( ) ,
22182238 } ;
22192239 collector. seed_with_top_level ( ) ;
22202240 collector. collect ( ) ;
0 commit comments