@@ -14,6 +14,7 @@ use hir_expand::{
1414 builtin_attr_macro:: find_builtin_attr,
1515 builtin_derive_macro:: find_builtin_derive,
1616 builtin_fn_macro:: find_builtin_macro,
17+ hygiene:: Hygiene ,
1718 name:: { name, AsName , Name } ,
1819 proc_macro:: ProcMacroExpander ,
1920 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
122123 from_glob_import : Default :: default ( ) ,
123124 skip_attrs : Default :: default ( ) ,
124125 is_proc_macro,
126+ hygienes : FxHashMap :: default ( ) ,
125127 } ;
126128 if tree_id. is_block ( ) {
127129 collector. seed_with_inner ( tree_id) ;
@@ -269,6 +271,12 @@ struct DefCollector<'a> {
269271 /// This also stores the attributes to skip when we resolve derive helpers and non-macro
270272 /// non-builtin attributes in general.
271273 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 > ,
272280}
273281
274282impl DefCollector < ' _ > {
@@ -312,13 +320,15 @@ impl DefCollector<'_> {
312320 }
313321
314322 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+ } ) ;
322332 self . def_map . unstable_features . extend ( features) ;
323333 }
324334
@@ -1224,7 +1234,19 @@ impl DefCollector<'_> {
12241234 } ;
12251235 let ast_id = ast_id. with_value ( ast_adt_id) ;
12261236
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) {
12281250 Some ( derive_macros) => {
12291251 let mut len = 0 ;
12301252 for ( idx, path) in derive_macros. enumerate ( ) {
@@ -2212,6 +2234,7 @@ mod tests {
22122234 from_glob_import : Default :: default ( ) ,
22132235 skip_attrs : Default :: default ( ) ,
22142236 is_proc_macro : false ,
2237+ hygienes : FxHashMap :: default ( ) ,
22152238 } ;
22162239 collector. seed_with_top_level ( ) ;
22172240 collector. collect ( ) ;
0 commit comments