diff options
Diffstat (limited to 'crates/hir_def/src/nameres/collector.rs')
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 118 |
1 files changed, 55 insertions, 63 deletions
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index d0fefb5af..28b73c3a1 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -18,12 +18,11 @@ use hir_expand::{ | |||
18 | use hir_expand::{InFile, MacroCallLoc}; | 18 | use hir_expand::{InFile, MacroCallLoc}; |
19 | use rustc_hash::{FxHashMap, FxHashSet}; | 19 | use rustc_hash::{FxHashMap, FxHashSet}; |
20 | use syntax::ast; | 20 | use syntax::ast; |
21 | use tt::{Leaf, TokenTree}; | ||
22 | 21 | ||
23 | use crate::{ | 22 | use crate::{ |
24 | attr::Attrs, | 23 | attr::Attrs, |
25 | db::DefDatabase, | 24 | db::DefDatabase, |
26 | item_attr_as_call_id, | 25 | derive_macro_as_call_id, |
27 | item_scope::{ImportType, PerNsGlobImports}, | 26 | item_scope::{ImportType, PerNsGlobImports}, |
28 | item_tree::{ | 27 | item_tree::{ |
29 | self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroRules, Mod, ModItem, ModKind, | 28 | self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroRules, Mod, ModItem, ModKind, |
@@ -42,6 +41,8 @@ use crate::{ | |||
42 | UnresolvedMacro, | 41 | UnresolvedMacro, |
43 | }; | 42 | }; |
44 | 43 | ||
44 | use super::proc_macro::ProcMacroDef; | ||
45 | |||
45 | const GLOB_RECURSION_LIMIT: usize = 100; | 46 | const GLOB_RECURSION_LIMIT: usize = 100; |
46 | const EXPANSION_DEPTH_LIMIT: usize = 128; | 47 | const EXPANSION_DEPTH_LIMIT: usize = 128; |
47 | const FIXED_POINT_LIMIT: usize = 8192; | 48 | const FIXED_POINT_LIMIT: usize = 8192; |
@@ -353,24 +354,23 @@ impl DefCollector<'_> { | |||
353 | /// use a dummy expander that always errors. This comes with the drawback of macros potentially | 354 | /// use a dummy expander that always errors. This comes with the drawback of macros potentially |
354 | /// going out of sync with what the build system sees (since we resolve using VFS state, but | 355 | /// going out of sync with what the build system sees (since we resolve using VFS state, but |
355 | /// Cargo builds only on-disk files). We could and probably should add diagnostics for that. | 356 | /// Cargo builds only on-disk files). We could and probably should add diagnostics for that. |
356 | fn resolve_proc_macro(&mut self, name: &Name) { | 357 | fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId<ast::Fn>) { |
357 | self.exports_proc_macros = true; | 358 | self.exports_proc_macros = true; |
358 | let macro_def = match self.proc_macros.iter().find(|(n, _)| n == name) { | 359 | let macro_def = match self.proc_macros.iter().find(|(n, _)| n == &def.name) { |
359 | Some((_, expander)) => MacroDefId { | 360 | Some((_, expander)) => MacroDefId { |
360 | ast_id: None, | ||
361 | krate: self.def_map.krate, | 361 | krate: self.def_map.krate, |
362 | kind: MacroDefKind::ProcMacro(*expander), | 362 | kind: MacroDefKind::ProcMacro(*expander, ast_id), |
363 | local_inner: false, | 363 | local_inner: false, |
364 | }, | 364 | }, |
365 | None => MacroDefId { | 365 | None => MacroDefId { |
366 | ast_id: None, | ||
367 | krate: self.def_map.krate, | 366 | krate: self.def_map.krate, |
368 | kind: MacroDefKind::ProcMacro(ProcMacroExpander::dummy(self.def_map.krate)), | 367 | kind: MacroDefKind::ProcMacro(ProcMacroExpander::dummy(self.def_map.krate), ast_id), |
369 | local_inner: false, | 368 | local_inner: false, |
370 | }, | 369 | }, |
371 | }; | 370 | }; |
372 | 371 | ||
373 | self.define_proc_macro(name.clone(), macro_def); | 372 | self.define_proc_macro(def.name.clone(), macro_def); |
373 | self.def_map.exported_proc_macros.insert(macro_def, def); | ||
374 | } | 374 | } |
375 | 375 | ||
376 | /// Define a macro with `macro_rules`. | 376 | /// Define a macro with `macro_rules`. |
@@ -820,8 +820,8 @@ impl DefCollector<'_> { | |||
820 | true | 820 | true |
821 | }); | 821 | }); |
822 | attribute_macros.retain(|directive| { | 822 | attribute_macros.retain(|directive| { |
823 | match item_attr_as_call_id(&directive.ast_id, self.db, self.def_map.krate, |path| { | 823 | match derive_macro_as_call_id(&directive.ast_id, self.db, self.def_map.krate, |path| { |
824 | self.resolve_attribute_macro(&directive, &path) | 824 | self.resolve_derive_macro(&directive, &path) |
825 | }) { | 825 | }) { |
826 | Ok(call_id) => { | 826 | Ok(call_id) => { |
827 | resolved.push((directive.module_id, call_id, 0)); | 827 | resolved.push((directive.module_id, call_id, 0)); |
@@ -844,7 +844,7 @@ impl DefCollector<'_> { | |||
844 | res | 844 | res |
845 | } | 845 | } |
846 | 846 | ||
847 | fn resolve_attribute_macro( | 847 | fn resolve_derive_macro( |
848 | &self, | 848 | &self, |
849 | directive: &DeriveDirective, | 849 | directive: &DeriveDirective, |
850 | path: &ModPath, | 850 | path: &ModPath, |
@@ -1118,7 +1118,8 @@ impl ModCollector<'_, '_> { | |||
1118 | ModItem::Function(id) => { | 1118 | ModItem::Function(id) => { |
1119 | let func = &self.item_tree[id]; | 1119 | let func = &self.item_tree[id]; |
1120 | 1120 | ||
1121 | self.collect_proc_macro_def(&func.name, &attrs); | 1121 | let ast_id = InFile::new(self.file_id, func.ast_id); |
1122 | self.collect_proc_macro_def(&func.name, ast_id, &attrs); | ||
1122 | 1123 | ||
1123 | def = Some(DefData { | 1124 | def = Some(DefData { |
1124 | id: FunctionLoc { | 1125 | id: FunctionLoc { |
@@ -1293,29 +1294,37 @@ impl ModCollector<'_, '_> { | |||
1293 | let db = self.def_collector.db; | 1294 | let db = self.def_collector.db; |
1294 | match self.mod_dir.resolve_declaration(db, self.file_id, &module.name, path_attr) { | 1295 | match self.mod_dir.resolve_declaration(db, self.file_id, &module.name, path_attr) { |
1295 | Ok((file_id, is_mod_rs, mod_dir)) => { | 1296 | Ok((file_id, is_mod_rs, mod_dir)) => { |
1296 | let module_id = self.push_child_module( | ||
1297 | module.name.clone(), | ||
1298 | ast_id, | ||
1299 | Some((file_id, is_mod_rs)), | ||
1300 | &self.item_tree[module.visibility], | ||
1301 | ); | ||
1302 | let item_tree = db.file_item_tree(file_id.into()); | 1297 | let item_tree = db.file_item_tree(file_id.into()); |
1303 | ModCollector { | 1298 | if item_tree |
1304 | def_collector: &mut *self.def_collector, | 1299 | .top_level_attrs(db, self.def_collector.def_map.krate) |
1305 | macro_depth: self.macro_depth, | 1300 | .cfg() |
1306 | module_id, | 1301 | .map_or(true, |cfg| { |
1307 | file_id: file_id.into(), | 1302 | self.def_collector.cfg_options.check(&cfg) != Some(false) |
1308 | item_tree: &item_tree, | 1303 | }) |
1309 | mod_dir, | ||
1310 | } | ||
1311 | .collect(item_tree.top_level_items()); | ||
1312 | if is_macro_use | ||
1313 | || item_tree | ||
1314 | .top_level_attrs(db, self.def_collector.def_map.krate) | ||
1315 | .by_key("macro_use") | ||
1316 | .exists() | ||
1317 | { | 1304 | { |
1318 | self.import_all_legacy_macros(module_id); | 1305 | let module_id = self.push_child_module( |
1306 | module.name.clone(), | ||
1307 | ast_id, | ||
1308 | Some((file_id, is_mod_rs)), | ||
1309 | &self.item_tree[module.visibility], | ||
1310 | ); | ||
1311 | ModCollector { | ||
1312 | def_collector: &mut *self.def_collector, | ||
1313 | macro_depth: self.macro_depth, | ||
1314 | module_id, | ||
1315 | file_id: file_id.into(), | ||
1316 | item_tree: &item_tree, | ||
1317 | mod_dir, | ||
1318 | } | ||
1319 | .collect(item_tree.top_level_items()); | ||
1320 | if is_macro_use | ||
1321 | || item_tree | ||
1322 | .top_level_attrs(db, self.def_collector.def_map.krate) | ||
1323 | .by_key("macro_use") | ||
1324 | .exists() | ||
1325 | { | ||
1326 | self.import_all_legacy_macros(module_id); | ||
1327 | } | ||
1319 | } | 1328 | } |
1320 | } | 1329 | } |
1321 | Err(candidate) => { | 1330 | Err(candidate) => { |
@@ -1385,28 +1394,11 @@ impl ModCollector<'_, '_> { | |||
1385 | } | 1394 | } |
1386 | 1395 | ||
1387 | /// If `attrs` registers a procedural macro, collects its definition. | 1396 | /// If `attrs` registers a procedural macro, collects its definition. |
1388 | fn collect_proc_macro_def(&mut self, func_name: &Name, attrs: &Attrs) { | 1397 | fn collect_proc_macro_def(&mut self, func_name: &Name, ast_id: AstId<ast::Fn>, attrs: &Attrs) { |
1389 | // FIXME: this should only be done in the root module of `proc-macro` crates, not everywhere | 1398 | // FIXME: this should only be done in the root module of `proc-macro` crates, not everywhere |
1390 | // FIXME: distinguish the type of macro | 1399 | if let Some(proc_macro) = attrs.parse_proc_macro_decl(func_name) { |
1391 | let macro_name = if attrs.by_key("proc_macro").exists() | 1400 | self.def_collector.export_proc_macro(proc_macro, ast_id); |
1392 | || attrs.by_key("proc_macro_attribute").exists() | 1401 | } |
1393 | { | ||
1394 | func_name.clone() | ||
1395 | } else { | ||
1396 | let derive = attrs.by_key("proc_macro_derive"); | ||
1397 | if let Some(arg) = derive.tt_values().next() { | ||
1398 | if let [TokenTree::Leaf(Leaf::Ident(trait_name)), ..] = &*arg.token_trees { | ||
1399 | trait_name.as_name() | ||
1400 | } else { | ||
1401 | log::trace!("malformed `#[proc_macro_derive]`: {}", arg); | ||
1402 | return; | ||
1403 | } | ||
1404 | } else { | ||
1405 | return; | ||
1406 | } | ||
1407 | }; | ||
1408 | |||
1409 | self.def_collector.resolve_proc_macro(¯o_name); | ||
1410 | } | 1402 | } |
1411 | 1403 | ||
1412 | fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>) { | 1404 | fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>) { |
@@ -1445,9 +1437,8 @@ impl ModCollector<'_, '_> { | |||
1445 | 1437 | ||
1446 | // Case 2: normal `macro_rules!` macro | 1438 | // Case 2: normal `macro_rules!` macro |
1447 | let macro_id = MacroDefId { | 1439 | let macro_id = MacroDefId { |
1448 | ast_id: Some(ast_id), | ||
1449 | krate: self.def_collector.def_map.krate, | 1440 | krate: self.def_collector.def_map.krate, |
1450 | kind: MacroDefKind::Declarative, | 1441 | kind: MacroDefKind::Declarative(ast_id), |
1451 | local_inner: is_local_inner, | 1442 | local_inner: is_local_inner, |
1452 | }; | 1443 | }; |
1453 | self.def_collector.define_macro(self.module_id, mac.name.clone(), macro_id, is_export); | 1444 | self.def_collector.define_macro(self.module_id, mac.name.clone(), macro_id, is_export); |
@@ -1476,12 +1467,13 @@ impl ModCollector<'_, '_> { | |||
1476 | }, | 1467 | }, |
1477 | ) { | 1468 | ) { |
1478 | Ok(Ok(macro_call_id)) => { | 1469 | Ok(Ok(macro_call_id)) => { |
1479 | self.def_collector.unexpanded_macros.push(MacroDirective { | 1470 | // Legacy macros need to be expanded immediately, so that any macros they produce |
1480 | module_id: self.module_id, | 1471 | // are in scope. |
1481 | ast_id, | 1472 | self.def_collector.collect_macro_expansion( |
1482 | legacy: Some(macro_call_id), | 1473 | self.module_id, |
1483 | depth: self.macro_depth + 1, | 1474 | macro_call_id, |
1484 | }); | 1475 | self.macro_depth + 1, |
1476 | ); | ||
1485 | 1477 | ||
1486 | return; | 1478 | return; |
1487 | } | 1479 | } |