diff options
Diffstat (limited to 'crates/hir_def')
-rw-r--r-- | crates/hir_def/src/attr.rs | 6 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 50 |
2 files changed, 54 insertions, 2 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index dea552a60..a841b97bf 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -171,6 +171,9 @@ pub struct AttrQuery<'a> { | |||
171 | } | 171 | } |
172 | 172 | ||
173 | impl<'a> AttrQuery<'a> { | 173 | impl<'a> AttrQuery<'a> { |
174 | /// For an attribute like `#[attr(value)]`, returns the `(value)` subtree. | ||
175 | /// | ||
176 | /// If the attribute does not have a token tree argument, returns `None`. | ||
174 | pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> { | 177 | pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> { |
175 | self.attrs().filter_map(|attr| match attr.input.as_ref()? { | 178 | self.attrs().filter_map(|attr| match attr.input.as_ref()? { |
176 | AttrInput::TokenTree(it) => Some(it), | 179 | AttrInput::TokenTree(it) => Some(it), |
@@ -178,6 +181,9 @@ impl<'a> AttrQuery<'a> { | |||
178 | }) | 181 | }) |
179 | } | 182 | } |
180 | 183 | ||
184 | /// For an attribute like `#[key = "value"]`, returns `"value"`. | ||
185 | /// | ||
186 | /// Returns `None` if the attribute does not have `key = "value"` form. | ||
181 | pub fn string_value(self) -> Option<&'a SmolStr> { | 187 | pub fn string_value(self) -> Option<&'a SmolStr> { |
182 | self.attrs().find_map(|attr| match attr.input.as_ref()? { | 188 | self.attrs().find_map(|attr| match attr.input.as_ref()? { |
183 | AttrInput::Literal(it) => Some(it), | 189 | AttrInput::Literal(it) => Some(it), |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 4c3993ff0..42c0f0536 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -16,10 +16,10 @@ use hir_expand::{ | |||
16 | proc_macro::ProcMacroExpander, | 16 | proc_macro::ProcMacroExpander, |
17 | HirFileId, MacroCallId, MacroDefId, MacroDefKind, | 17 | HirFileId, MacroCallId, MacroDefId, MacroDefKind, |
18 | }; | 18 | }; |
19 | use rustc_hash::FxHashMap; | 19 | use rustc_hash::{FxHashMap, FxHashSet}; |
20 | use rustc_hash::FxHashSet; | ||
21 | use syntax::ast; | 20 | use syntax::ast; |
22 | use test_utils::mark; | 21 | use test_utils::mark; |
22 | use tt::{Leaf, TokenTree}; | ||
23 | 23 | ||
24 | use crate::{ | 24 | use crate::{ |
25 | attr::Attrs, | 25 | attr::Attrs, |
@@ -281,6 +281,25 @@ impl DefCollector<'_> { | |||
281 | } | 281 | } |
282 | } | 282 | } |
283 | 283 | ||
284 | fn resolve_proc_macro(&mut self, name: &Name) { | ||
285 | let macro_def = match self.proc_macros.iter().find(|(n, _)| n == name) { | ||
286 | Some((_, expander)) => MacroDefId { | ||
287 | ast_id: None, | ||
288 | krate: Some(self.def_map.krate), | ||
289 | kind: MacroDefKind::ProcMacro(*expander), | ||
290 | local_inner: false, | ||
291 | }, | ||
292 | None => MacroDefId { | ||
293 | ast_id: None, | ||
294 | krate: Some(self.def_map.krate), | ||
295 | kind: MacroDefKind::ProcMacro(ProcMacroExpander::dummy(self.def_map.krate)), | ||
296 | local_inner: false, | ||
297 | }, | ||
298 | }; | ||
299 | |||
300 | self.define_proc_macro(name.clone(), macro_def); | ||
301 | } | ||
302 | |||
284 | /// Define a macro with `macro_rules`. | 303 | /// Define a macro with `macro_rules`. |
285 | /// | 304 | /// |
286 | /// It will define the macro in legacy textual scope, and if it has `#[macro_export]`, | 305 | /// It will define the macro in legacy textual scope, and if it has `#[macro_export]`, |
@@ -917,6 +936,9 @@ impl ModCollector<'_, '_> { | |||
917 | } | 936 | } |
918 | ModItem::Function(id) => { | 937 | ModItem::Function(id) => { |
919 | let func = &self.item_tree[id]; | 938 | let func = &self.item_tree[id]; |
939 | |||
940 | self.collect_proc_macro_def(&func.name, attrs); | ||
941 | |||
920 | def = Some(DefData { | 942 | def = Some(DefData { |
921 | id: FunctionLoc { | 943 | id: FunctionLoc { |
922 | container: container.into(), | 944 | container: container.into(), |
@@ -1177,6 +1199,30 @@ impl ModCollector<'_, '_> { | |||
1177 | } | 1199 | } |
1178 | } | 1200 | } |
1179 | 1201 | ||
1202 | /// If `attrs` registers a procedural macro, collects its definition. | ||
1203 | fn collect_proc_macro_def(&mut self, func_name: &Name, attrs: &Attrs) { | ||
1204 | // FIXME: this should only be done in the root module of `proc-macro` crates, not everywhere | ||
1205 | // FIXME: distinguish the type of macro | ||
1206 | let macro_name = if attrs.by_key("proc_macro").exists() | ||
1207 | || attrs.by_key("proc_macro_attribute").exists() | ||
1208 | { | ||
1209 | func_name.clone() | ||
1210 | } else { | ||
1211 | let derive = attrs.by_key("proc_macro_derive"); | ||
1212 | if let Some(arg) = derive.tt_values().next() { | ||
1213 | if let [TokenTree::Leaf(Leaf::Ident(trait_name))] = &*arg.token_trees { | ||
1214 | trait_name.as_name() | ||
1215 | } else { | ||
1216 | return; | ||
1217 | } | ||
1218 | } else { | ||
1219 | return; | ||
1220 | } | ||
1221 | }; | ||
1222 | |||
1223 | self.def_collector.resolve_proc_macro(¯o_name); | ||
1224 | } | ||
1225 | |||
1180 | fn collect_macro(&mut self, mac: &MacroCall) { | 1226 | fn collect_macro(&mut self, mac: &MacroCall) { |
1181 | let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); | 1227 | let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); |
1182 | 1228 | ||