diff options
Diffstat (limited to 'crates/hir_def')
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 34 |
1 files changed, 26 insertions, 8 deletions
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 02ceb8d50..3896be25d 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -43,7 +43,7 @@ use crate::{ | |||
43 | UnresolvedMacro, | 43 | UnresolvedMacro, |
44 | }; | 44 | }; |
45 | 45 | ||
46 | use super::proc_macro::ProcMacroDef; | 46 | use super::proc_macro::{ProcMacroDef, ProcMacroKind}; |
47 | 47 | ||
48 | const GLOB_RECURSION_LIMIT: usize = 100; | 48 | const GLOB_RECURSION_LIMIT: usize = 100; |
49 | const EXPANSION_DEPTH_LIMIT: usize = 128; | 49 | const EXPANSION_DEPTH_LIMIT: usize = 128; |
@@ -101,6 +101,7 @@ pub(super) fn collect_defs( | |||
101 | exports_proc_macros: false, | 101 | exports_proc_macros: false, |
102 | from_glob_import: Default::default(), | 102 | from_glob_import: Default::default(), |
103 | ignore_attrs_on: FxHashSet::default(), | 103 | ignore_attrs_on: FxHashSet::default(), |
104 | derive_helpers_in_scope: FxHashMap::default(), | ||
104 | }; | 105 | }; |
105 | match block { | 106 | match block { |
106 | Some(block) => { | 107 | Some(block) => { |
@@ -247,6 +248,9 @@ struct DefCollector<'a> { | |||
247 | exports_proc_macros: bool, | 248 | exports_proc_macros: bool, |
248 | from_glob_import: PerNsGlobImports, | 249 | from_glob_import: PerNsGlobImports, |
249 | ignore_attrs_on: FxHashSet<InFile<ModItem>>, | 250 | ignore_attrs_on: FxHashSet<InFile<ModItem>>, |
251 | /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper | ||
252 | /// attributes. | ||
253 | derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<Name>>, | ||
250 | } | 254 | } |
251 | 255 | ||
252 | impl DefCollector<'_> { | 256 | impl DefCollector<'_> { |
@@ -950,21 +954,35 @@ impl DefCollector<'_> { | |||
950 | // First, fetch the raw expansion result for purposes of error reporting. This goes through | 954 | // First, fetch the raw expansion result for purposes of error reporting. This goes through |
951 | // `macro_expand_error` to avoid depending on the full expansion result (to improve | 955 | // `macro_expand_error` to avoid depending on the full expansion result (to improve |
952 | // incrementality). | 956 | // incrementality). |
957 | let loc: MacroCallLoc = self.db.lookup_intern_macro(macro_call_id); | ||
953 | let err = self.db.macro_expand_error(macro_call_id); | 958 | let err = self.db.macro_expand_error(macro_call_id); |
954 | if let Some(err) = err { | 959 | if let Some(err) = err { |
955 | let loc: MacroCallLoc = self.db.lookup_intern_macro(macro_call_id); | ||
956 | |||
957 | let diag = match err { | 960 | let diag = match err { |
958 | hir_expand::ExpandError::UnresolvedProcMacro => { | 961 | hir_expand::ExpandError::UnresolvedProcMacro => { |
959 | // Missing proc macros are non-fatal, so they are handled specially. | 962 | // Missing proc macros are non-fatal, so they are handled specially. |
960 | DefDiagnostic::unresolved_proc_macro(module_id, loc.kind) | 963 | DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone()) |
961 | } | 964 | } |
962 | _ => DefDiagnostic::macro_error(module_id, loc.kind, err.to_string()), | 965 | _ => DefDiagnostic::macro_error(module_id, loc.kind.clone(), err.to_string()), |
963 | }; | 966 | }; |
964 | 967 | ||
965 | self.def_map.diagnostics.push(diag); | 968 | self.def_map.diagnostics.push(diag); |
966 | } | 969 | } |
967 | 970 | ||
971 | // If we've just resolved a derive, record its helper attributes. | ||
972 | if let MacroCallKind::Derive { ast_id, .. } = &loc.kind { | ||
973 | if loc.def.krate != self.def_map.krate { | ||
974 | let def_map = self.db.crate_def_map(loc.def.krate); | ||
975 | if let Some(def) = def_map.exported_proc_macros.get(&loc.def) { | ||
976 | if let ProcMacroKind::CustomDerive { helpers } = &def.kind { | ||
977 | self.derive_helpers_in_scope | ||
978 | .entry(*ast_id) | ||
979 | .or_default() | ||
980 | .extend(helpers.iter().cloned()); | ||
981 | } | ||
982 | } | ||
983 | } | ||
984 | } | ||
985 | |||
968 | // Then, fetch and process the item tree. This will reuse the expansion result from above. | 986 | // Then, fetch and process the item tree. This will reuse the expansion result from above. |
969 | let item_tree = self.db.file_item_tree(file_id); | 987 | let item_tree = self.db.file_item_tree(file_id); |
970 | let mod_dir = self.mod_dirs[&module_id].clone(); | 988 | let mod_dir = self.mod_dirs[&module_id].clone(); |
@@ -1120,9 +1138,8 @@ impl ModCollector<'_, '_> { | |||
1120 | } | 1138 | } |
1121 | 1139 | ||
1122 | if let Err(()) = self.resolve_attributes(&attrs, item) { | 1140 | if let Err(()) = self.resolve_attributes(&attrs, item) { |
1123 | // Do not process the item. It has at least one non-builtin attribute, which *must* | 1141 | // Do not process the item. It has at least one non-builtin attribute, so the |
1124 | // resolve to a proc macro (or fail to resolve), so we'll never see this item during | 1142 | // fixed-point algorithm is required to resolve the rest of them. |
1125 | // normal name resolution. | ||
1126 | continue; | 1143 | continue; |
1127 | } | 1144 | } |
1128 | 1145 | ||
@@ -1721,6 +1738,7 @@ mod tests { | |||
1721 | exports_proc_macros: false, | 1738 | exports_proc_macros: false, |
1722 | from_glob_import: Default::default(), | 1739 | from_glob_import: Default::default(), |
1723 | ignore_attrs_on: FxHashSet::default(), | 1740 | ignore_attrs_on: FxHashSet::default(), |
1741 | derive_helpers_in_scope: FxHashMap::default(), | ||
1724 | }; | 1742 | }; |
1725 | collector.seed_with_top_level(); | 1743 | collector.seed_with_top_level(); |
1726 | collector.collect(); | 1744 | collector.collect(); |