@@ -14,6 +14,7 @@ use hir_expand::{
14
14
builtin_attr_macro:: find_builtin_attr,
15
15
builtin_derive_macro:: find_builtin_derive,
16
16
builtin_fn_macro:: find_builtin_macro,
17
+ hygiene:: Hygiene ,
17
18
name:: { name, AsName , Name } ,
18
19
proc_macro:: ProcMacroExpander ,
19
20
ExpandResult , ExpandTo , HirFileId , InFile , MacroCallId , MacroCallKind , MacroCallLoc ,
@@ -122,6 +123,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T
122
123
from_glob_import : Default :: default ( ) ,
123
124
skip_attrs : Default :: default ( ) ,
124
125
is_proc_macro,
126
+ hygienes : FxHashMap :: default ( ) ,
125
127
} ;
126
128
if tree_id. is_block ( ) {
127
129
collector. seed_with_inner ( tree_id) ;
@@ -269,6 +271,12 @@ struct DefCollector<'a> {
269
271
/// This also stores the attributes to skip when we resolve derive helpers and non-macro
270
272
/// non-builtin attributes in general.
271
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 > ,
272
280
}
273
281
274
282
impl DefCollector < ' _ > {
@@ -312,13 +320,15 @@ impl DefCollector<'_> {
312
320
}
313
321
314
322
if * attr_name == hir_expand:: name![ feature] {
315
- let features =
316
- attr. parse_path_comma_token_tree ( ) . into_iter ( ) . flatten ( ) . filter_map (
317
- |feat| match feat. segments ( ) {
318
- [ name] => Some ( name. to_smol_str ( ) ) ,
319
- _ => None ,
320
- } ,
321
- ) ;
323
+ let hygiene = & Hygiene :: new_unhygienic ( ) ;
324
+ let features = attr
325
+ . parse_path_comma_token_tree ( self . db . upcast ( ) , hygiene)
326
+ . into_iter ( )
327
+ . flatten ( )
328
+ . filter_map ( |feat| match feat. segments ( ) {
329
+ [ name] => Some ( name. to_smol_str ( ) ) ,
330
+ _ => None ,
331
+ } ) ;
322
332
self . def_map . unstable_features . extend ( features) ;
323
333
}
324
334
@@ -1224,7 +1234,19 @@ impl DefCollector<'_> {
1224
1234
} ;
1225
1235
let ast_id = ast_id. with_value ( ast_adt_id) ;
1226
1236
1227
- match attr. parse_path_comma_token_tree ( ) {
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
+ } ;
1248
+
1249
+ match attr. parse_path_comma_token_tree ( self . db . upcast ( ) , hygiene) {
1228
1250
Some ( derive_macros) => {
1229
1251
let mut len = 0 ;
1230
1252
for ( idx, path) in derive_macros. enumerate ( ) {
@@ -2212,6 +2234,7 @@ mod tests {
2212
2234
from_glob_import : Default :: default ( ) ,
2213
2235
skip_attrs : Default :: default ( ) ,
2214
2236
is_proc_macro : false ,
2237
+ hygienes : FxHashMap :: default ( ) ,
2215
2238
} ;
2216
2239
collector. seed_with_top_level ( ) ;
2217
2240
collector. collect ( ) ;
0 commit comments