44//! resolves imports and expands macros.
55
66use hir_expand:: {
7+ builtin_derive:: find_builtin_derive,
78 builtin_macro:: find_builtin_macro,
89 name:: { self , AsName , Name } ,
9- HirFileId , MacroCallId , MacroDefId , MacroDefKind , MacroFileKind ,
10+ HirFileId , MacroCallId , MacroCallKind , MacroDefId , MacroDefKind , MacroFileKind ,
1011} ;
1112use ra_cfg:: CfgOptions ;
1213use ra_db:: { CrateId , FileId } ;
@@ -58,6 +59,7 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
5859 glob_imports : FxHashMap :: default ( ) ,
5960 unresolved_imports : Vec :: new ( ) ,
6061 unexpanded_macros : Vec :: new ( ) ,
62+ unexpanded_attribute_macros : Vec :: new ( ) ,
6163 mod_dirs : FxHashMap :: default ( ) ,
6264 macro_stack_monitor : MacroStackMonitor :: default ( ) ,
6365 poison_macros : FxHashSet :: default ( ) ,
@@ -102,6 +104,7 @@ struct DefCollector<'a, DB> {
102104 glob_imports : FxHashMap < LocalModuleId , Vec < ( LocalModuleId , LocalImportId ) > > ,
103105 unresolved_imports : Vec < ( LocalModuleId , LocalImportId , raw:: ImportData ) > ,
104106 unexpanded_macros : Vec < ( LocalModuleId , AstId < ast:: MacroCall > , Path ) > ,
107+ unexpanded_attribute_macros : Vec < ( LocalModuleId , AstId < ast:: ModuleItem > , Path ) > ,
105108 mod_dirs : FxHashMap < LocalModuleId , ModDir > ,
106109
107110 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly
@@ -470,6 +473,8 @@ where
470473
471474 fn resolve_macros ( & mut self ) -> ReachedFixedPoint {
472475 let mut macros = std:: mem:: replace ( & mut self . unexpanded_macros , Vec :: new ( ) ) ;
476+ let mut attribute_macros =
477+ std:: mem:: replace ( & mut self . unexpanded_attribute_macros , Vec :: new ( ) ) ;
473478 let mut resolved = Vec :: new ( ) ;
474479 let mut res = ReachedFixedPoint :: Yes ;
475480 macros. retain ( |( module_id, ast_id, path) | {
@@ -482,7 +487,19 @@ where
482487 ) ;
483488
484489 if let Some ( def) = resolved_res. resolved_def . take_macros ( ) {
485- let call_id = def. as_call_id ( self . db , * ast_id) ;
490+ let call_id = def. as_call_id ( self . db , MacroCallKind :: FnLike ( * ast_id) ) ;
491+ resolved. push ( ( * module_id, call_id, def) ) ;
492+ res = ReachedFixedPoint :: No ;
493+ return false ;
494+ }
495+
496+ true
497+ } ) ;
498+ attribute_macros. retain ( |( module_id, ast_id, path) | {
499+ let resolved_res = self . resolve_attribute_macro ( path) ;
500+
501+ if let Some ( def) = resolved_res {
502+ let call_id = def. as_call_id ( self . db , MacroCallKind :: Attr ( * ast_id) ) ;
486503 resolved. push ( ( * module_id, call_id, def) ) ;
487504 res = ReachedFixedPoint :: No ;
488505 return false ;
@@ -492,6 +509,7 @@ where
492509 } ) ;
493510
494511 self . unexpanded_macros = macros;
512+ self . unexpanded_attribute_macros = attribute_macros;
495513
496514 for ( module_id, macro_call_id, macro_def_id) in resolved {
497515 self . collect_macro_expansion ( module_id, macro_call_id, macro_def_id) ;
@@ -500,6 +518,20 @@ where
500518 res
501519 }
502520
521+ fn resolve_attribute_macro ( & self , path : & Path ) -> Option < MacroDefId > {
522+ // FIXME this is currently super hacky, just enough to support the
523+ // built-in derives
524+ if let Some ( name) = path. as_ident ( ) {
525+ // FIXME this should actually be handled with the normal name
526+ // resolution; the std lib defines built-in stubs for the derives,
527+ // but these are new-style `macro`s, which we don't support yet
528+ if let Some ( def_id) = find_builtin_derive ( name) {
529+ return Some ( def_id) ;
530+ }
531+ }
532+ None
533+ }
534+
503535 fn collect_macro_expansion (
504536 & mut self ,
505537 module_id : LocalModuleId ,
@@ -587,7 +619,9 @@ where
587619 . def_collector
588620 . unresolved_imports
589621 . push ( ( self . module_id , import_id, self . raw_items [ import_id] . clone ( ) ) ) ,
590- raw:: RawItemKind :: Def ( def) => self . define_def ( & self . raw_items [ def] ) ,
622+ raw:: RawItemKind :: Def ( def) => {
623+ self . define_def ( & self . raw_items [ def] , & item. attrs )
624+ }
591625 raw:: RawItemKind :: Macro ( mac) => self . collect_macro ( & self . raw_items [ mac] ) ,
592626 raw:: RawItemKind :: Impl ( imp) => {
593627 let module = ModuleId {
@@ -682,10 +716,16 @@ where
682716 res
683717 }
684718
685- fn define_def ( & mut self , def : & raw:: DefData ) {
719+ fn define_def ( & mut self , def : & raw:: DefData , attrs : & Attrs ) {
686720 let module = ModuleId { krate : self . def_collector . def_map . krate , local_id : self . module_id } ;
687721 let ctx = LocationCtx :: new ( self . def_collector . db , module, self . file_id ) ;
688722
723+ // FIXME: check attrs to see if this is an attribute macro invocation;
724+ // in which case we don't add the invocation, just a single attribute
725+ // macro invocation
726+
727+ self . collect_derives ( attrs, def) ;
728+
689729 let name = def. name . clone ( ) ;
690730 let def: PerNs = match def. kind {
691731 raw:: DefKind :: Function ( ast_id) => {
@@ -736,6 +776,23 @@ where
736776 self . def_collector . update ( self . module_id , None , & [ ( name, resolution) ] )
737777 }
738778
779+ fn collect_derives ( & mut self , attrs : & Attrs , def : & raw:: DefData ) {
780+ for derive_subtree in attrs. by_key ( "derive" ) . tt_values ( ) {
781+ // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree
782+ for tt in & derive_subtree. token_trees {
783+ let ident = match & tt {
784+ tt:: TokenTree :: Leaf ( tt:: Leaf :: Ident ( ident) ) => ident,
785+ tt:: TokenTree :: Leaf ( tt:: Leaf :: Punct ( _) ) => continue , // , is ok
786+ _ => continue , // anything else would be an error (which we currently ignore)
787+ } ;
788+ let path = Path :: from_tt_ident ( ident) ;
789+
790+ let ast_id = AstId :: new ( self . file_id , def. kind . ast_id ( ) ) ;
791+ self . def_collector . unexpanded_attribute_macros . push ( ( self . module_id , ast_id, path) ) ;
792+ }
793+ }
794+ }
795+
739796 fn collect_macro ( & mut self , mac : & raw:: MacroData ) {
740797 let ast_id = AstId :: new ( self . file_id , mac. ast_id ) ;
741798
@@ -759,8 +816,8 @@ where
759816 if is_macro_rules ( & mac. path ) {
760817 if let Some ( name) = & mac. name {
761818 let macro_id = MacroDefId {
762- ast_id,
763- krate : self . def_collector . def_map . krate ,
819+ ast_id : Some ( ast_id ) ,
820+ krate : Some ( self . def_collector . def_map . krate ) ,
764821 kind : MacroDefKind :: Declarative ,
765822 } ;
766823 self . def_collector . define_macro ( self . module_id , name. clone ( ) , macro_id, mac. export ) ;
@@ -773,7 +830,8 @@ where
773830 if let Some ( macro_def) = mac. path . as_ident ( ) . and_then ( |name| {
774831 self . def_collector . def_map [ self . module_id ] . scope . get_legacy_macro ( & name)
775832 } ) {
776- let macro_call_id = macro_def. as_call_id ( self . def_collector . db , ast_id) ;
833+ let macro_call_id =
834+ macro_def. as_call_id ( self . def_collector . db , MacroCallKind :: FnLike ( ast_id) ) ;
777835
778836 self . def_collector . collect_macro_expansion ( self . module_id , macro_call_id, macro_def) ;
779837 return ;
@@ -829,6 +887,7 @@ mod tests {
829887 glob_imports : FxHashMap :: default ( ) ,
830888 unresolved_imports : Vec :: new ( ) ,
831889 unexpanded_macros : Vec :: new ( ) ,
890+ unexpanded_attribute_macros : Vec :: new ( ) ,
832891 mod_dirs : FxHashMap :: default ( ) ,
833892 macro_stack_monitor : monitor,
834893 poison_macros : FxHashSet :: default ( ) ,
0 commit comments