@@ -123,6 +123,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T
123
123
from_glob_import : Default :: default ( ) ,
124
124
skip_attrs : Default :: default ( ) ,
125
125
is_proc_macro,
126
+ hygienes : FxHashMap :: default ( ) ,
126
127
} ;
127
128
if tree_id. is_block ( ) {
128
129
collector. seed_with_inner ( tree_id) ;
@@ -270,6 +271,12 @@ struct DefCollector<'a> {
270
271
/// This also stores the attributes to skip when we resolve derive helpers and non-macro
271
272
/// non-builtin attributes in general.
272
273
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 > ,
273
280
}
274
281
275
282
impl DefCollector < ' _ > {
@@ -313,8 +320,9 @@ impl DefCollector<'_> {
313
320
}
314
321
315
322
if * attr_name == hir_expand:: name![ feature] {
323
+ let hygiene = & Hygiene :: new_unhygienic ( ) ;
316
324
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 )
318
326
. into_iter ( )
319
327
. flatten ( )
320
328
. filter_map ( |feat| match feat. segments ( ) {
@@ -1225,7 +1233,18 @@ impl DefCollector<'_> {
1225
1233
}
1226
1234
} ;
1227
1235
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
+ } ;
1229
1248
1230
1249
match attr. parse_path_comma_token_tree ( self . db . upcast ( ) , hygiene) {
1231
1250
Some ( derive_macros) => {
@@ -2215,6 +2234,7 @@ mod tests {
2215
2234
from_glob_import : Default :: default ( ) ,
2216
2235
skip_attrs : Default :: default ( ) ,
2217
2236
is_proc_macro : false ,
2237
+ hygienes : FxHashMap :: default ( ) ,
2218
2238
} ;
2219
2239
collector. seed_with_top_level ( ) ;
2220
2240
collector. collect ( ) ;
0 commit comments