aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/src/attr.rs6
-rw-r--r--crates/hir_def/src/nameres/collector.rs50
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
173impl<'a> AttrQuery<'a> { 173impl<'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};
19use rustc_hash::FxHashMap; 19use rustc_hash::{FxHashMap, FxHashSet};
20use rustc_hash::FxHashSet;
21use syntax::ast; 20use syntax::ast;
22use test_utils::mark; 21use test_utils::mark;
22use tt::{Leaf, TokenTree};
23 23
24use crate::{ 24use 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(&macro_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