diff options
Diffstat (limited to 'crates/ra_hir_def/src/nameres')
-rw-r--r-- | crates/ra_hir_def/src/nameres/collector.rs | 38 |
1 files changed, 27 insertions, 11 deletions
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index b02364e86..1d004b6a6 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -8,7 +8,7 @@ use hir_expand::{ | |||
8 | use ra_cfg::CfgOptions; | 8 | use ra_cfg::CfgOptions; |
9 | use ra_db::{CrateId, FileId}; | 9 | use ra_db::{CrateId, FileId}; |
10 | use ra_syntax::{ast, SmolStr}; | 10 | use ra_syntax::{ast, SmolStr}; |
11 | use rustc_hash::FxHashMap; | 11 | use rustc_hash::{FxHashMap, FxHashSet}; |
12 | use test_utils::tested_by; | 12 | use test_utils::tested_by; |
13 | 13 | ||
14 | use crate::{ | 14 | use crate::{ |
@@ -57,6 +57,7 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C | |||
57 | unexpanded_macros: Vec::new(), | 57 | unexpanded_macros: Vec::new(), |
58 | mod_dirs: FxHashMap::default(), | 58 | mod_dirs: FxHashMap::default(), |
59 | macro_stack_monitor: MacroStackMonitor::default(), | 59 | macro_stack_monitor: MacroStackMonitor::default(), |
60 | poison_macros: FxHashSet::default(), | ||
60 | cfg_options, | 61 | cfg_options, |
61 | }; | 62 | }; |
62 | collector.collect(); | 63 | collector.collect(); |
@@ -103,6 +104,17 @@ struct DefCollector<'a, DB> { | |||
103 | /// Some macro use `$tt:tt which mean we have to handle the macro perfectly | 104 | /// Some macro use `$tt:tt which mean we have to handle the macro perfectly |
104 | /// To prevent stack overflow, we add a deep counter here for prevent that. | 105 | /// To prevent stack overflow, we add a deep counter here for prevent that. |
105 | macro_stack_monitor: MacroStackMonitor, | 106 | macro_stack_monitor: MacroStackMonitor, |
107 | /// Some macros are not well-behavior, which leads to infinite loop | ||
108 | /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } } | ||
109 | /// We mark it down and skip it in collector | ||
110 | /// | ||
111 | /// FIXME: | ||
112 | /// Right now it only handle a poison macro in a single crate, | ||
113 | /// such that if other crate try to call that macro, | ||
114 | /// the whole process will do again until it became poisoned in that crate. | ||
115 | /// We should handle this macro set globally | ||
116 | /// However, do we want to put it as a global variable? | ||
117 | poison_macros: FxHashSet<MacroDefId>, | ||
106 | 118 | ||
107 | cfg_options: &'a CfgOptions, | 119 | cfg_options: &'a CfgOptions, |
108 | } | 120 | } |
@@ -489,7 +501,7 @@ where | |||
489 | macro_call_id: MacroCallId, | 501 | macro_call_id: MacroCallId, |
490 | macro_def_id: MacroDefId, | 502 | macro_def_id: MacroDefId, |
491 | ) { | 503 | ) { |
492 | if self.def_map.poison_macros.contains(¯o_def_id) { | 504 | if self.poison_macros.contains(¯o_def_id) { |
493 | return; | 505 | return; |
494 | } | 506 | } |
495 | 507 | ||
@@ -509,7 +521,7 @@ where | |||
509 | .collect(raw_items.items()); | 521 | .collect(raw_items.items()); |
510 | } else { | 522 | } else { |
511 | log::error!("Too deep macro expansion: {:?}", macro_call_id); | 523 | log::error!("Too deep macro expansion: {:?}", macro_call_id); |
512 | self.def_map.poison_macros.insert(macro_def_id); | 524 | self.poison_macros.insert(macro_def_id); |
513 | } | 525 | } |
514 | 526 | ||
515 | self.macro_stack_monitor.decrease(macro_def_id); | 527 | self.macro_stack_monitor.decrease(macro_def_id); |
@@ -807,7 +819,7 @@ mod tests { | |||
807 | db: &impl DefDatabase, | 819 | db: &impl DefDatabase, |
808 | def_map: CrateDefMap, | 820 | def_map: CrateDefMap, |
809 | monitor: MacroStackMonitor, | 821 | monitor: MacroStackMonitor, |
810 | ) -> CrateDefMap { | 822 | ) -> (CrateDefMap, FxHashSet<MacroDefId>) { |
811 | let mut collector = DefCollector { | 823 | let mut collector = DefCollector { |
812 | db, | 824 | db, |
813 | def_map, | 825 | def_map, |
@@ -816,13 +828,18 @@ mod tests { | |||
816 | unexpanded_macros: Vec::new(), | 828 | unexpanded_macros: Vec::new(), |
817 | mod_dirs: FxHashMap::default(), | 829 | mod_dirs: FxHashMap::default(), |
818 | macro_stack_monitor: monitor, | 830 | macro_stack_monitor: monitor, |
831 | poison_macros: FxHashSet::default(), | ||
819 | cfg_options: &CfgOptions::default(), | 832 | cfg_options: &CfgOptions::default(), |
820 | }; | 833 | }; |
821 | collector.collect(); | 834 | collector.collect(); |
822 | collector.finish() | 835 | (collector.def_map, collector.poison_macros) |
823 | } | 836 | } |
824 | 837 | ||
825 | fn do_limited_resolve(code: &str, limit: u32, poison_limit: u32) -> CrateDefMap { | 838 | fn do_limited_resolve( |
839 | code: &str, | ||
840 | limit: u32, | ||
841 | poison_limit: u32, | ||
842 | ) -> (CrateDefMap, FxHashSet<MacroDefId>) { | ||
826 | let (db, _file_id) = TestDB::with_single_file(&code); | 843 | let (db, _file_id) = TestDB::with_single_file(&code); |
827 | let krate = db.test_crate(); | 844 | let krate = db.test_crate(); |
828 | 845 | ||
@@ -837,7 +854,6 @@ mod tests { | |||
837 | prelude: None, | 854 | prelude: None, |
838 | root, | 855 | root, |
839 | modules, | 856 | modules, |
840 | poison_macros: FxHashSet::default(), | ||
841 | diagnostics: Vec::new(), | 857 | diagnostics: Vec::new(), |
842 | } | 858 | } |
843 | }; | 859 | }; |
@@ -867,7 +883,7 @@ foo!(KABOOM); | |||
867 | 883 | ||
868 | #[test] | 884 | #[test] |
869 | fn test_macro_expand_poisoned() { | 885 | fn test_macro_expand_poisoned() { |
870 | let def = do_limited_resolve( | 886 | let (_, poison_macros) = do_limited_resolve( |
871 | r#" | 887 | r#" |
872 | macro_rules! foo { | 888 | macro_rules! foo { |
873 | ($ty:ty) => { foo!($ty); } | 889 | ($ty:ty) => { foo!($ty); } |
@@ -878,12 +894,12 @@ foo!(KABOOM); | |||
878 | 16, | 894 | 16, |
879 | ); | 895 | ); |
880 | 896 | ||
881 | assert_eq!(def.poison_macros.len(), 1); | 897 | assert_eq!(poison_macros.len(), 1); |
882 | } | 898 | } |
883 | 899 | ||
884 | #[test] | 900 | #[test] |
885 | fn test_macro_expand_normal() { | 901 | fn test_macro_expand_normal() { |
886 | let def = do_limited_resolve( | 902 | let (_, poison_macros) = do_limited_resolve( |
887 | r#" | 903 | r#" |
888 | macro_rules! foo { | 904 | macro_rules! foo { |
889 | ($ident:ident) => { struct $ident {} } | 905 | ($ident:ident) => { struct $ident {} } |
@@ -894,6 +910,6 @@ foo!(Bar); | |||
894 | 16, | 910 | 16, |
895 | ); | 911 | ); |
896 | 912 | ||
897 | assert_eq!(def.poison_macros.len(), 0); | 913 | assert_eq!(poison_macros.len(), 0); |
898 | } | 914 | } |
899 | } | 915 | } |